尝试使用LWJGL中的着色器移动对象时我做错了什么?

时间:2018-05-04 23:27:54

标签: java opengl glsl lwjgl

我正在尝试使用着色器正确地将网格点转换并投影到窗口的表面(感兴趣的点是负责输出最终顶点位置的顶点着色器)。

我将在大约6个小时内详细说明这个问题,因为我现在必须上床睡觉。如果有人有意愿通读这个(它还没有正确地高度重写和写作)我会更加欣赏它。

模型(四边形)由以下顶点表示:[ - 0.5f,0.5f,0f](V0),[ - 0.5f,-0.5f,0f](V1),[0.5f,-0.5 f,0f](V2),[0.5f,0.5f,0]。

我有以下一对方法创建透视投影矩阵

public static Matrix4f getProjectionMatrix(float fovy, int width, int height, float zNear, float zFar) {
    float aspectRatio = (float) width / height;
    projectionMatrix.perspective(fovy, aspectRatio, zNear, zFar);
    return projectionMatrix;
}

此方法可在 转换 类中找到,并创建并返回透视投影矩阵。

  • fovy =垂直视野
  • 宽度 =窗口的宽度
  • 高度 =窗口的高度
  • zNear =近剪裁平面
  • zFar =远剪裁平面

    public Matrix4f perspective(float fovy, float aspectRatio, float zNear, float zFar) {
        float scale = (float) (Math.tan(fovy * 0.5) * zNear);
        float top = scale;
        float right = top * aspectRatio;
        float bottom = -top;
        float left = bottom * aspectRatio;
    
        this.m00 = 2*zNear / (right - left);
        this.m03 = (right + left) / (right - left);
        this.m11 = 2*zNear / (top - bottom);
        this.m12 = (top + bottom) / (top - bottom);
        this.m22 = -(zFar + zNear) / (zFar - zNear);
        this.m23 = -2*zFar*zNear / (zFar - zNear);
        this.m32 = -1;
    
        return this;
    

    } 此方法位于 Matrix4f 类中。

这是Matrix4f类的开头,包含Matrix4f实例变量和构造函数:

public class Matrix4f {
    float m00, m01, m02, m03;
    float m10, m11, m12, m13;
    float m20, m21, m22, m23;
    float m30, m31, m32, m33;

public Matrix4f() {
    m00 = 1.0f; m01 = 0.0f; m02 = 0.0f; m03 = 0.0f;
    m10 = 0.0f; m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
    m20 = 0.0f; m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
    m30 = 0.0f; m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
}

调用构造函数后,已经创建了单位矩阵。剩下的唯一事情是知道如何初始化透视投影矩阵。这是在调用类 转换 的构造函数时完成的:

public class Transformations {
    private Matrix4f translationMatrix;
    private static Matrix4f projectionMatrix;

    public Transformations() {
        translationMatrix = new Matrix4f();
        projectionMatrix = new Matrix4f();
    }

现在是翻译矩阵。通过方法getTranslationMatrix(float x, float y, float z) 转换 类中提供了它的创建功能,该方法使用以下参数创建并返回转换矩阵: p>

public Matrix4f getTranslationMatrix(float x, float y, float z) {
    translationMatrix.m03 = x;
    translationMatrix.m13 = y;
    translationMatrix.m23 = z;
    return translationMatrix;
}

为了实际拥有代表游戏模型的东西,我创建了一个名为 GameEntity 的类。它代表模型的网格和位置:

public class GameEntity {

    private final Mesh mesh;
    private Vector3f position;

    public GameEntity(Mesh mesh) {
        this.mesh = mesh;
        position = new Vector3f(0, 0, 0);
    }

    public Vector3f getPosition() {
        return position;
    }    

    public void updatePosition(float x, float y, float z) {
        position.x += x;
        position.y += y;
        position.z += z;
    }

    public Mesh getMesh() {
        return mesh;
    }
}

updatePosition方法应该在整个窗口周围移动实体。我不会在这里包含 Mesh 类的代码说明。您需要知道的是它包含关于 GameEntity 的网格(顶点)数据,例如顶点位置,顶点颜色,索引等,它们都存储在一个顶点数组对象,然后用于将 网格 实例渲染到窗口上。在我的例子中,形成四边形的两个三角形表示为 GameEntity 实例。

移动模型:每次按下任意键W,A,S,D,空格或左移时,都会调用 updatePosition 方法。它会将 GameEntity 实例的位置(它存储在索引0处的GameEntity[] entities数组中)更新一定量:

    private void processInput() {
        glfwPollEvents();

        if (window.keys[GLFW_KEY_W]) {
            entities[0].updatePosition(0, 0, -1.0f);
        } else if (window.keys[GLFW_KEY_S]){
            entities[0].updatePosition(0, 0, 1.0f);
        } else if (window.keys[GLFW_KEY_A]) {
            entities[0].updatePosition(1.0f, 0, 0);
        } else if (window.keys[GLFW_KEY_D]) {
            entities[0].updatePosition(-1.0f, 0, 0);
        } else if (window.keys[GLFW_KEY_SPACE]) {
            entities[0].updatePosition(0, 1.0f, 0);
        } else if (window.keys[GLFW_KEY_LEFT_SHIFT]) {
            entities[0].updatePosition(0, -1.0f, 0);
        } 
     }

在主游戏循环中调用此方法。

然后,在 渲染器 类中,根据模型的位置构建模型的平移矩阵,并根据属性构造投影矩阵窗口对象:

private ShaderProgram shaderProgram;
private Window window = new Window();

private final Transformations transformation;

private Matrix4f translationMatrix = new Matrix4f();
private Matrix4f projectionMatrix = new Matrix4f();


private static double angleOfView = 60.0;
private static final float FOVY = (float) Math.toRadians(angleOfView);
private static final float zNear = 0.01f;
private static final float zFar = 1000.0f;

shaderProgram.createUniform("translationMatrix");
shaderProgram.createUniform("projectionMatrix");

public void render(Window window, GameEntity[] entities) {
    i++;

    clear();

    if (window.isResized()) {
        glViewport(0, 0, window.getWidth(), window.getHeight());
        window.setResized(false);
    }

    //make the shaders active
    shaderProgram.bind();

    //update the projection matrix
    Matrix4f projectionMatrix = transformation.getProjectionMatrix(FOVY, window.getWidth(), window.getHeight(), zNear, zFar);

    shaderProgram.setUniformMatrix("projectionMatrix", projectionMatrix);

    //render each game item
    for(GameEntity entity : entities) {
        Matrix4f translationMat = transformation.getTranslationMatrix(entity.getPosition());
        shaderProgram.setUniformMatrix("translationMatrix", translationMat);
        entity.getMesh().render();
    }

    shaderProgram.unbind();
}

首先,定义所有统一位置(在render()方法之上)。

clear()方法清除渲染缓冲区 - 它准备渲染新图像。在以下if子句中,处理窗口大小调整操作。如果调整窗口大小,则具有相应方法的if子句将更新窗口的widthheight以匹配调整大小的窗口。

projectionMatrix由变量构成,这些变量被定义为Renderer类的实例变量(FOVYzNearzFar)和两个获取当前变量的变量窗口对象的宽度和高度(window.getWidth()window.getHeight())。

然后,投影矩阵被发送"调用shaderProgram.setUniformMatrix("projectionMatrix", projectionMatrix);

到顶点着色器
private final Map<String, Integer> uniforms;

public void createUniform(String uniformName) throws Exception {
    int uniformLocation = glGetUniformLocation(programID, uniformName);

    if (uniformLocation < 0) {
        throw new Exception("[ShaderProgram.createUniform]: Couldn't find uniform: " + uniformName);
    }
    uniforms.put(uniformName, uniformLocation);
}

此方法位于 ShaderProgram 类中,该类保存对活动着色器porgram的引用以及与其关联的统一变量,这些变量存储在{{1}中Hashmap ..

然后,在for循环中,渲染两个四边形。首先,基于 GameInstance 的位置值的值构建平移矩阵,其被表示为3元组向量(x,y,z)。然后,创建的矩阵被发送&#34;到顶点着色器。

现在,已经将透视投影(uniforms)和翻译矩阵(projectionMatrix x)发送到顶点着色器,现在可以在上调用渲染方法 Mesh 实例来渲染它。 translationMatri方法的代码(在render()的上下文中)是:

entity.getMesh().render()

然而,结果并不令人满意。当按下W或S时,四边形(两个三角形)会越来越靠近&#34; us&#34;,这是正确的。但是,当按下A或D时(应该在x轴上平移模型),四边形(两个三角形)不会被翻译。 它围绕它的中心旋转。如何解决这个问题?感谢您提供帮助以及阅读这个长期问题所花费的时间。

1 个答案:

答案 0 :(得分:0)

行/列命名法似乎有问题。

据我所知,矩阵中的代码单元格mij为col = i,row = j

OpenGL需要一个16值数组,即13,14,15个位置的平移。通常这称为&#34;列主要顺序&#34;,翻译在第4列中表示。

所以试试这个:

public Matrix4f getTranslationMatrix(float x, float y, float z) {
    translationMatrix.m30 = x;
    translationMatrix.m31 = y;
    translationMatrix.m32 = z;
    return translationMatrix;
}

另外,请查看您的perspective。我认为你在ij指数中有一些错误。 ii个细胞看起来很好。