Рейтрейсинг блока под курсором мыши [DIFFICULTY: IMPOSIBLAH]

18
0
Да не простой рейтрейсинг, а такой как в МКЭдите. Суть - в открытом гуе указываешь мышью на блок - получаешь его координаты. Есть догадки что такая штука будет зависеть от ФОВа и разрешения экрана

Вопрос: Как? Куда? Что? Возможно ли? И почему нет?
 
Agravaine написал(а):
Всмысле в открытом гуи?
Вот есть гуи, в гуе мышь не привязана к центру. Координаты мыши в двух измерениях, в пределах разрешения экрана. Вот, хочу узнать координаты блока под этим самым курсором мыши
 
Agravaine написал(а):
А, типо вид сверху?
Смотри. Ты когда-нибудь строил что-то в мкэдите? В нём есть замечательное выделение блоков. Ты тыкаешь в любое место в мире - редактор узнаёт координаты блока - начинает выделять сетку. Вот такую штуку хочу замутить в майнкрафте
 
desu написал(а):
Agravaine написал(а):
Всмысле в открытом гуи?
Вот есть гуи, в гуе мышь не привязана к центру. Координаты мыши в двух измерениях, в пределах разрешения экрана. Вот, хочу узнать координаты блока под этим самым курсором мыши
Не выйдет. Придется рендерить свой маленький мир внутри гуи с включенной глубиной.
 
Dragon2488 написал(а):
desu написал(а):
Agravaine написал(а):
Всмысле в открытом гуи?
Вот есть гуи, в гуе мышь не привязана к центру. Координаты мыши в двух измерениях, в пределах разрешения экрана. Вот, хочу узнать координаты блока под этим самым курсором мыши
Не выйдет. Придется рендерить свой маленький мир внутри гуи с включенной глубиной.
Не знаю, или я объяснил не так, или вы не так поняли. Мне не надо ничего рендерить, мне просто нужно получить блок на который указывает мой курсор
 
Неужели, в кой-то веки интересный вопрос.
Более-менее подробная статья, да еще и на русском! Справишься сам с портированием на java/lwjgl? Могу помочь. Ну и сразу небольшая подсказка: функция gluUnProject в lwjgl находится в классе Project.
 
GloomyFolken написал(а):
Неужели, в кой-то веки интересный вопрос.
Более-менее подробная статья, да еще и на русском! Справишься сам с портированием на java/lwjgl? Могу помочь. Ну и сразу небольшая подсказка: функция gluUnProject в lwjgl находится в классе Project.
Ох чёрт, у меня с ГЛ всё очень плохо. Да и с векторами, синусами и косинусами. Зря я не учил матан, позор мне. Спасибо
 
Ну и естественно вариант решения с чтением из буфера глубины будет работать только если там действительно то, что нужно в буфере глубины: что-то может перекрывать блок, и тогда он выберется неправильно. Если это проблема, то стоит всё-таки отказаться от чтения из буфера глубины и вызвать World#clip() (или как там называется метод на рейтрейсинг блоков между двумя точками в нужной тебе версии), указав начало и конец "селектирующего отрезка", как его обзывают в той статье.
 
GloomyFolken написал(а):
Ну и естественно вариант решения с чтением из буфера глубины будет работать только если там действительно то, что нужно в буфере глубины: что-то может перекрывать блок, и тогда он выберется неправильно. Если это проблема, то стоит всё-таки отказаться от чтения из буфера глубины и вызвать World#clip() (или как там называется метод на рейтрейсинг блоков между двумя точками в нужной тебе версии), указав начало и конец "селектирующего отрезка", как его обзывают в той статье.
Да что-то ничерта у меня не выйдет, я перестал понимать начиная с "буффер глубины", печаль
 
Конкретно здесь матан не особо нужен, потому что задачу уже десять раз решили до нас :D
Попробовал портировать на lwjgl, но не тестил. Надеюсь, сможешь отдебажить.
Код:
//не стоит каждый раз создавать новый буфер, это чревато проблемами с производительностью
    private static IntBuffer viewportBuf = BufferUtils.createIntBuffer(16);
    private static FloatBuffer projectionBuf = BufferUtils.createFloatBuffer(16);
    private static FloatBuffer modelviewBuf = BufferUtils.createFloatBuffer(16);

    /**
     * Метод использует текущие матрицу проекции и modelview матрицу, так что вызывать
     * его во время отрисовки ГУИ - не дело. Вызывай в RenderWorldLastEvent, например
     */
    public MovingObjectPosition calcBlockMouseOver(World world){
        GL11.glGetInteger(GL11.GL_VIEWPORT, viewportBuf);
        GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projectionBuf);
        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelviewBuf);

        float vx = Mouse.getX();
        // я не очень помню, где находится 0 по оси Y: сверху или снизу.
        // если сверху, то vy = mc.displayHeight - Mouse.getY().
        float vy = Mouse.getY();

        // этот буфер не нативный, так что всё ОК
        FloatBuffer resultBuf = FloatBuffer.allocate(3);

        // В той статье предполагается ставить z на -1,
        // но я не уверен, что оно будет правильно работать.
        // Всё-таки миниальная глубина - это 0, а не -1. Решай сам, кому верить 
        Project.gluUnProject(vx, vy, -1, modelviewBuf, projectionBuf, viewportBuf, resultBuf);
        Vec3 p1 = Vec3.createVectorHelper(resultBuf.get(0), resultBuf.get(1), resultBuf.get(2));

        Project.gluUnProject(vx, vy, 1, modelviewBuf, projectionBuf, viewportBuf, resultBuf);
        Vec3 p2 = Vec3.createVectorHelper(resultBuf.get(0), resultBuf.get(1), resultBuf.get(2));
        
        //И всё бы ничего, но p1 и p2 центрированы то ли к камере, то ли к голове персонажа.
        //Склоняюсь ко второму варианту. Поправим это.
        
        p1 = p1.addVector(RenderManager.renderPosX, RenderManager.renderPosY, RenderManager.renderPosZ);
        p2 = p2.addVector(RenderManager.renderPosX, RenderManager.renderPosY, RenderManager.renderPosZ);
        
        return world.clip(p1, p2);
    }
 
GloomyFolken написал(а):
Конкретно здесь матан не особо нужен, потому что задачу уже десять раз решили до нас :D
Попробовал портировать на lwjgl, но не тестил. Надеюсь, сможешь отдебажить.
Код:
//не стоит каждый раз создавать новый буфер, это чревато проблемами с производительностью
    private static IntBuffer viewportBuf = BufferUtils.createIntBuffer(4);
    private static FloatBuffer projectionBuf = BufferUtils.createFloatBuffer(16);
    private static FloatBuffer modelviewBuf = BufferUtils.createFloatBuffer(16);

    /**
     * Метод использует текущие матрицу проекции и modelview матрицу, так что вызывать
     * его во время отрисовки ГУИ - не дело. Вызывай в RenderWorldLastEvent, например
     */
    public MovingObjectPosition calcBlockMouseOver(World world){
        GL11.glGetInteger(GL11.GL_VIEWPORT, viewportBuf);
        GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projectionBuf);
        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelviewBuf);

        float vx = Mouse.getX();
        // я не очень помню, где находится 0 по оси Y: сверху или снизу.
        // если сверху, то vy = mc.displayHeight - Mouse.getY().
        float vy = Mouse.getY();

        // этот буфер не нативный, так что всё ОК
        FloatBuffer resultBuf = FloatBuffer.allocate(3);

        // В той статье предполагается ставить z на -1,
        // но я не уверен, что оно будет правильно работать.
        // Всё-таки миниальная глубина - это 0, а не -1. Решай сам, кому верить 
        Project.gluUnProject(vx, vy, -1, modelviewBuf, projectionBuf, viewportBuf, resultBuf);
        Vec3 p1 = Vec3.createVectorHelper(resultBuf.get(0), resultBuf.get(1), resultBuf.get(2));

        Project.gluUnProject(vx, vy, 1, modelviewBuf, projectionBuf, viewportBuf, resultBuf);
        Vec3 p2 = Vec3.createVectorHelper(resultBuf.get(0), resultBuf.get(1), resultBuf.get(2));
        
        //И всё бы ничего, но p1 и p2 центрированы то ли к камере, то ли к голове персонажа.
        //Склоняюсь ко второму варианту. Поправим это.
        
        p1.addVector(RenderManager.renderPosX, RenderManager.renderPosY, RenderManager.renderPosZ);
        p2.addVector(RenderManager.renderPosX, RenderManager.renderPosY, RenderManager.renderPosZ);
        
        return world.clip(p1, p2);
    }
Ох чёрт! Я когда писал сюда, я не расчитывал на помощь. Пошёл качать сурсы форжа, в который раз. Спасибос от души просто
 
o_O WTF?
h_1432321546_1555296_f3271e5f21.png
 
Чревато спать днём ._.
Такую интересную задачку пропустил, блин.
Тем не менее, огромное спасибо глуми за ссылку и портированный отрезок кода, ухожу курить статью и разбирать решение, как раз раньше интересовал подробный вопрос, но решить руки так и не доходили.
 
Хм. Я может бред скажу, но возник вопрос:
В той же статье описывается момент, когда можно узнать лишь мировые координаты объекта (вернее ближайшей точки на нём) по буферу глубины и координатам курсора. Так почему бы сначала не узнать мировые координаты наиближайшего по пикселю объекта, и кастить СО уже оттуда, вместо того, чтобы создавать огромный СО аж от камеры? Ведь такой СО будет гораздо короче, а это выигрыш в скорости выборки.
Буфер глубины как бы в любом случае выберет наиближайший объект к камере, значит мы ничего не пропустим.
 
GloomyFolken написал(а):
Ну и естественно вариант решения с чтением из буфера глубины будет работать только если там действительно то, что нужно в буфере глубины: что-то может перекрывать блок, и тогда он выберется неправильно. Если это проблема, то стоит всё-таки отказаться от чтения из буфера глубины и вызвать World#clip() (или как там называется метод на рейтрейсинг блоков между двумя точками в нужной тебе версии), указав начало и конец "селектирующего отрезка", как его обзывают в той статье.
Например, блок может заслонять какая-нибудь сущность. Тогда в буфере глубины значение окажется меньше нужного. А ещё нужно вспоминать, как из числа в буфере глубины получить расстояние до объекта:
Код:
    private static float depthToDistance(float zNear, float zFar, float zValue){
        float a = zFar / (zFar - zNear);
        float b = zFar * zNear / (zNear - zFar);
        return b/(zValue-a);
    }
А ещё нужно знать, с какими параметрами farPlane и nearPlane последний раз вызывался метод gluPerspective (это майн делает в начале отрисовки кадра). А ещё на эти параметры наверняка влияет оптифайн. Короче говоря, можно-то можно, но это явно не будет проще, когда есть готовый метод для рейтрейсинга блоков.
 
Не, не. Я в общем случае рассматриваю. Не именно для кубача.
Даже если для кубача, допустим, у нас есть отдельный буфер глубины ОНЛИ для блоков. В таком случае, имеет ли смысл такая оптимизация? Или всё засрет скорость доступа к видеопамяти и текстуре буфера глубины?
 
Oldestkon написал(а):
Не, не. Я в общем случае рассматриваю. Не именно для кубача.
Даже если для кубача, допустим, у нас есть отдельный буфер глубины ОНЛИ для блоков. В таком случае, имеет ли смысл такая оптимизация? Или всё засрет скорость доступа к видеопамяти и текстуре буфера глубины?
Ну, вместо "отдельного буфера глубины" можно просто трейсить, когда блоки уже отрисовались, а остальное ещё нет :)
ИМХО такой вариант правда будет работать быстрее как минимум в несколько раз, а в некоторых случаях (если блок далеко) - то и в несколько десятков раз. Впрочем, это гадание на кофейной гуще, такие вещи нужно тестировать.
К тому же, при чтении из буфера глубины лучше учитывается форма блоков. Так что основная проблема в нюансах реализации.
 
Назад
Сверху