Raycasting dando valores erráticos

Usando LWJGL3 y JOML.

Estoy tratando de averiguar cómo obtener el punto en el terreno utilizando un sistema de rayos. Utilizo el punto para establecer una posición de caracteres para ver qué punto se emite.

No creo que sea mi terreno lo que causa el problema, ya que mover el personaje (con el teclado o simplemente agregando un valor a cada cuadro) y adjuntarlo al terreno funciona bien.

Los problemas que recibo:

  • Invertir la matriz de proyección hace que el punto parpadee entre la posición correcta y algún otro punto, pero no estoy seguro de la relación con este otro valor.
  • No invertir la matriz de proyección detiene el parpadeo, pero ahora el punto se aleja exponencialmente de la posición del mouse.
  • Cerca del centro de la pantalla, las 2 posiciones se fusionarán.

Si imprimo el vector de punto de terreno, aparece en notación científica por alguna razón:

( 5.335E+1  3.849E-2 -9.564E+1)
( 8.804E+1 -6.256E-3 -2.815E+2)
( 5.335E+1  3.849E-2 -9.564E+1)
( 8.804E+1 -6.256E-3 -2.815E+2)
( 5.335E+1  3.849E-2 -9.564E+1)

Si imprimo cada uno de los valores de x, y y z individualmente, en realidad muestra la posición correcta pero también cambia a otra (la diferencia aumenta entre más lejos del centro de la pantalla que se mueve el mouse):

5.8912144, 0.016174316, -7.771721
6.1992702, 0.01574707, -11.79966
5.8912144, 0.016174316, -7.771721
6.1992702, 0.01574707, -11.79966
6.609352, 0.01815033, -8.793705

Clase Raycasting:

public class Raycast
{
    private static final int RECURSION_COUNT = 200;
    private static final float RAY_RANGE = 600;

    private Input input;
    private Vector3f currentRay = new Vector3f();

    private Matrix4f projectionMatrix;
    private Matrix4f viewMatrix;

    private Camera camera;
    private Terrain terrain;
    private Vector3f currentTerrainPoint;

    public Raycast(Camera camera, Matrix4f projectionMatrix, Terrain terrain, Input input) {
        this.camera = camera;
        this.projectionMatrix = projectionMatrix;
        this.input = input;
        this.viewMatrix = MathUtils.createViewMatrix(camera);
        this.terrain = terrain;
    }

    public void update()
    {
        viewMatrix = MathUtils.createViewMatrix(camera);
        currentRay = calculateRay();
        if (intersectionInRange(0, RAY_RANGE, currentRay)) {
            currentTerrainPoint = binarySearch(0, 0, RAY_RANGE, currentRay);
        } else {
            currentTerrainPoint = null;
        }
    }

    private Vector3f calculateRay()
    {
        float mouseX = (float) input.getMouseDx();
        float mouseY = (float) input.getMouseDy();
        Vector2f deviceCoords = getNormalizedDeviceCoordinates(mouseX, mouseY);
        //System.out.println(deviceCoords.x+", "+deviceCoords.y);
        Vector4f clipCoords = new Vector4f(deviceCoords.x, deviceCoords.y, -1f, 1f);
        Vector4f eyeCoords = toEyeCoords(clipCoords);
        Vector3f worldRay = toWorldCoords(eyeCoords);
        return worldRay;
    }

    private Vector3f toWorldCoords(Vector4f eyeCoords)
    {
        Matrix4f invertedView = viewMatrix.invert();
        Vector4f rayWorld = invertedView.transform(eyeCoords);
        Vector3f mouseRay = new Vector3f(rayWorld.x, rayWorld.y, rayWorld.z);
        mouseRay.normalize();
        return mouseRay;
    }

    private Vector4f toEyeCoords(Vector4f clipCoords)
    {
        Matrix4f invertedProjection = projectionMatrix.invert();
        Vector4f eyeCoords = invertedProjection.transform(clipCoords);

        return new Vector4f(eyeCoords.x, eyeCoords.y, -1f, 0f);
    }

    private Vector2f getNormalizedDeviceCoordinates(float mouseX, float mouseY)
    {
        float x = (2f * mouseX) / Constants.DISPLAY_WIDTH - 1f;
        float y = (2f * mouseY) / Constants.DISPLAY_HEIGHT - 1f;

        return new Vector2f(x, -y);
    }

    private Vector3f getPointOnRay(Vector3f ray, float distance) {
        //Vector3f camPos = new Vector3f(camera.getPosX(), camera.getPosY(), camera.getPosZ());
        Vector3f start = new Vector3f(camera.getPosX(), camera.getPosY(), camera.getPosZ());
        Vector3f scaledRay = new Vector3f(ray.x * distance, ray.y * distance, ray.z * distance);
        return start.add(scaledRay);
    }

    private Vector3f binarySearch(int count, float start, float finish, Vector3f ray) {
        float half = start + ((finish - start) / 2f);
        if (count >= RECURSION_COUNT) {
            Vector3f endPoint = getPointOnRay(ray, half);
            Terrain terrain = getTerrain(endPoint.x, endPoint.z);
            if (terrain != null) {
                return endPoint;
            } else {
                return null;
            }
        }
        if (intersectionInRange(start, half, ray)) {
            return binarySearch(count + 1, start, half, ray);
        } else {
            return binarySearch(count + 1, half, finish, ray);
        }
    }

    private boolean intersectionInRange(float start, float finish, Vector3f ray) {
        Vector3f startPoint = getPointOnRay(ray, start);
        Vector3f endPoint = getPointOnRay(ray, finish);
        if (!isUnderGround(startPoint) && isUnderGround(endPoint)) {
            return true;
        } else {
            return false;
        }
    }

    private boolean isUnderGround(Vector3f testPoint) {
        Terrain terrain = getTerrain(testPoint.x, testPoint.z);
        float height = 0;
        if (terrain != null) {
            height = terrain.getTerrainHeight(testPoint.x, testPoint.z);
        }
        if (testPoint.y < height) {
            return true;
        } else {
            return false;
        }
    }

    private Terrain getTerrain(float worldX, float worldZ) {
        return terrain;
    }

    public Vector3f getCurrentTerrainPoint() {
        return currentTerrainPoint;
    }

    public Vector3f getCurrentRay() {
        return currentRay;
    }
}

Clase MathUtils con matrices de vista y proyección:

public class MathUtils {

    public static float baryCentric(Vector3f p1, Vector3f p2, Vector3f p3, Vector2f pos) {
        float det = (p2.z - p3.z) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.z - p3.z);
        float l1 = ((p2.z - p3.z) * (pos.x - p3.x) + (p3.x - p2.x) * (pos.y - p3.z)) / det;
        float l2 = ((p3.z - p1.z) * (pos.x - p3.x) + (p1.x - p3.x) * (pos.y - p3.z)) / det;
        float l3 = 1.0f - l1 - l2;
        return l1 * p1.y + l2 * p2.y + l3 * p3.y;
    }

    public static Matrix4f createTransformationMatrix(Vector2f translation, Vector2f scale) {
        Matrix4f matrix = new Matrix4f();
        matrix.identity();
        matrix.translate(translation.x,translation.y,0f);
        matrix.scale(scale.x,scale.y,1f);
        return matrix;
    }

    public static Matrix4f createTransformationMatrix(Vector3f translation, float rx, float ry, float rz, float scale) {
        Matrix4f transformationMatrix = new Matrix4f();
        transformationMatrix.identity();
        transformationMatrix.translate(translation);
        transformationMatrix.rotate((float) Math.toRadians(rx), 1,0,0);
        transformationMatrix.rotate((float) Math.toRadians(ry), 0,1,0);
        transformationMatrix.rotate((float) Math.toRadians(rz), 0,0,1);
        transformationMatrix.scale(scale);
        return transformationMatrix;
    }

    public static Matrix4f createViewMatrix(Camera camera) {
        Matrix4f viewMatrix = new Matrix4f();
        viewMatrix.identity();
        viewMatrix = viewMatrix.rotate((float) Math.toRadians(camera.getPitch()), 1,0,0);//((float) Math.toRadians(camera.getPitch()), new Vector3f(1, 0, 0), viewMatrix);
        viewMatrix = viewMatrix.rotate((float) Math.toRadians(camera.getYaw()),0, 1, 0);
        Vector3f cameraPos = new Vector3f(camera.getPosX(), camera.getPosY(), camera.getPosZ());
        Vector3f negativeCameraPos = new Vector3f(-cameraPos.x, -cameraPos.y, -cameraPos.z);
        viewMatrix  = viewMatrix.translate(negativeCameraPos);
        return viewMatrix;
    }

    public static Matrix4f createProjectionMatrix() {
        Matrix4f projectionMatrix = new Matrix4f();
        float aspectRatio = (float) Constants.DISPLAY_WIDTH / (float) Constants.DISPLAY_HEIGHT;
        float fov = Constants.FOV;
        float near = Constants.NEAR_PLANE;
        float far = Constants.FAR_PLANE;
        projectionMatrix = projectionMatrix.perspective((float) java.lang.Math.toRadians(fov), aspectRatio, near, far);
        return projectionMatrix;
    }
Respuesta 1

Tengo esta idea bastante "loca" de tener una instalación de "procedimiento almacenado" en mi aplicación. Básicamente, mi aplicación está centrada en los datos y puede acceder al almacén de datos a través de alguna forma de interfaz Restful. ...

Acabo de comenzar a trabajar en la API de rally. Quiero crear un nuevo resultado de caso de prueba, pero sigo recibiendo una excepción y no sé por qué. Creo que esto va a ser algo realmente tonto ...

¿Cómo puedo escribir un código Java que escanee un documento desde el escáner y me muestre en el árbol Java? Cuando hago clic en escanear, escanea domucemts en mi escáner y me muestra en la ventana. ¿Cómo puedo escribir esto? Esta ahí ...

Estoy tratando de configurar un sistema de profundidad en el procesamiento. El objetivo es que funcione de manera similar a una ventana (Windows). Tengo una clase llamada 'Ventana' y que puede tomar algunos argumentos y ...