将ProjectionMatrix添加到实体会导致渲染时出现异常行为

时间:2018-10-17 15:35:45

标签: java glsl rendering lwjgl projection-matrix

问题简介:

我正在使用this tutorial之后的LWJGL库来开发游戏引擎。但是,我正在努力做到这一点,以便在主机和游戏本身之间实现真正的划分。因此,我使该项目变得非常复杂,并且我认为这会引起一些问题,因为ProjectionMatrix无法按照视频中的说明进行操作。

我在做什么:

创建ProjectionMatrix:

为了创建ProjectionMatrix,我创建了一个为我创建它的方法:

public static Matrix4f createProjectionMatrix(float aspectRatio, float fov, float nearPlane, float farPlane) {
    float y_scale = (float) ((1f / Math.tan(Math.toRadians(fov / 2f))) * aspectRatio);
    float x_scale = y_scale / aspectRatio;
    float frustum_length = nearPlane - farPlane;

    Matrix4f projectionMatrix = new Matrix4f();
    projectionMatrix.m00 = x_scale;
    projectionMatrix.m11 = y_scale;
    projectionMatrix.m22 = -((farPlane + nearPlane) / frustum_length);
    projectionMatrix.m23 = -1;
    projectionMatrix.m32 = -((2 * nearPlane * farPlane) / frustum_length);
    projectionMatrix.m33 = 0;

    return projectionMatrix;
}

我使用以下值创建ProjectionMatrix:

aspectRatio = width/height = 640/480 = 1.33333
fov = 100
nearPlane = -0.5
farPlane = 100

这将为我的ProjectionMatrix产生以下值:

0.83909965  0.0         0.0        0.0
0.0         0.83909965  0.0        0.0
0.0         0.0         0.9990005  -0.9995003
0.0         0.0        -1.0        0.0

使用ProjectionMatrix:

为了使用ProjectionMatrix,我创建了以下着色器:

vertex.vs:

#version 150

in vec3 position;
in vec2 textureCoordinates;

out vec2 passTextureCoordinates;

uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform int useProjectionMatrix;

void main(void){
    if (useProjectionMatrix == 1) {
        gl_Position = projectionMatrix * transformationMatrix * vec4(position,1.0);
    } else {
        gl_Position = transformationMatrix * vec4(position,1.0);
    }
    passTextureCoordinates = textureCoordinates;

}

fragment.fs:

#version 150

in vec2 passTextureCoordinates;

out vec4 out_Color;

uniform sampler2D textureSampler;

void main(void){

    out_Color = texture(textureSampler,passTextureCoordinates);

}

最后,为了渲染实体,我创建了以下渲染器类:

public class TexturedEntityRenderer extends AbstractEntityRenderer{

    private float aspectRatio;
    private float fov;
    private float nearPlane;
    private float farPlane;

    public void prepare() {
        GL11.glClearColor(0,0,0,1);
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
    }

    public void render (AbstractEntity entity, AbstractShader shader) {
        if(shader instanceof TexturedEntityShader) {
            if(entity.getModel() instanceof TexturedModel) {
                TexturedModel model = (TexturedModel)entity.getModel();
                GL30.glBindVertexArray(model.getVaoID());
                GL20.glEnableVertexAttribArray(0);
                GL20.glEnableVertexAttribArray(1);
                Matrix4f transformationMatrix = MatrixMaths.createTransformationMatrix(entity.getPosition(), entity.getRx(), entity.getRy(), entity.getRz(), entity.getScale());
                ((TexturedEntityShader)shader).loadTransformationMatrix(transformationMatrix);
                GL13.glActiveTexture(GL13.GL_TEXTURE0);
                GL11.glBindTexture(GL11.GL_TEXTURE_2D, ((TexturedModel)entity.getModel()).getTexture().getTextureID());
                GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, model.getVaoID());
                GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
                GL20.glDisableVertexAttribArray(0);
                GL20.glDisableVertexAttribArray(1);
                GL30.glBindVertexArray(0);
            } else {
                ExceptionThrower.throwException(new ModelInvalidException());
            }
        } else {
            ExceptionThrower.throwException(new ShaderIncompatableException(shader.toString()));
        }
    }

    public void setup(AbstractShader shader) {
        nearPlane = Float.parseFloat(OptionHandler.getProperty(GraphicOptions.WINDOWNEARPLANE_KEY, OptionHandler.GRAPHIC_OPTION_ID));
        farPlane = Float.parseFloat(OptionHandler.getProperty(GraphicOptions.WINDOWFARPLANE_KEY, OptionHandler.GRAPHIC_OPTION_ID));
        aspectRatio = DisplayManager.getWidth() / DisplayManager.getHeight();
        fov = Float.parseFloat(OptionHandler.getProperty(GraphicOptions.WINDOWFOV_KEY, OptionHandler.GRAPHIC_OPTION_ID));
        ((TexturedEntityShader)shader).loadProjectionMatrix(MatrixMaths.createProjectionMatrix(aspectRatio, fov, nearPlane, farPlane));
        ((TexturedEntityShader)shader).loadUseProjectionMatrix();
    }
}

Optionhandler.getProperty()中的setup()函数从文本文件返回给定键的属性(例如fov或nearPlane值)。 (我已经检查出可以通过打印所有已加载的选项来确保其正常工作。)此外,DisplayManager.getWidth()DisplayManager.getHeight()函数显然可以获得用于计算AspectRatio变量的宽度和高度。

更新实体:

最后但并非最不重要的一点,我正在使用一个名为EntityModifier的类来更新实体,该类如下:

public class EntityModifier {

    private Vector3f dposition;
    private float drx;
    private float dry;
    private float drz;
    private float dscale;

    public BasicEntityModifier(Vector3f dposition, float drx, float dry, float drz, float dscale) {
        this.dposition = dposition;
        this.drx = drx;
        this.dry = dry;
        this.drz = drx;
        this.dscale = dscale;
    }

    public Vector3f getDposition() {
        return dposition;
    }

    public float getDrx() {
        return drx;
    }

    public float getDry() {
        return dry;
    }

    public float getDrz() {
        return drz;
    }

    public float getDscale() {
        return dscale;
    }

    @Override
    public String toString() {
        return "BasicEntityModifier [dposition=" + dposition + ", drx=" + drx + ", dry=" + dry + ", drz=" + drz + ", dscale=" + dscale + "]";
    }

}

我创建的每个实体都具有以下类之一,并且可以调用update方法,该方法将值添加到实体的转换中:

public void update() {
        increasePosition(modifier.getDposition().getX(),modifier.getDposition().getY(),modifier.getDposition().getZ());
        increaseRotation(modifier.getDrx(), modifier.getDry(), modifier.getDrz());
        increaseScale(modifier.getDscale());
    }

    private void increasePosition(float dx, float dy, float dz) {
        position.x += dx;
        position.y += dy;
        position.z += dz;

    }

    private void increaseRotation(float drx, float dry, float drz) {
        rx += drx;
        ry += dry;
        rz += drz;
    }

    private void increaseScale(float dscale) {
        scale += dscale;
    }

问题:

我能够正常更改实体的xy值的位置,但是每当我使用EntityModifier更改z位置时,都会加载实体,但随后从屏幕上消失。在消失和更改dz的值之前,它已加载约60帧,但似乎丝毫没有影响它消失的速度(它确实如此,请参见编辑2)。同样,该实体不具有tutorial here中所示的缩放效果(相同的链接,但带有时间戳)。

dz的值更改为0可以停止实体的消失。

这是怎么回事?我该如何解决?

编辑:

我在评论中指出,nearPlane值应为正,因此将其更改为0.5,但仍然得到相同的结果。我也将float frustum_length = nearPlane - farPlane;更改为float frustum_length = farPlane - nearPlane;,在那里也有人建议这样做(这也不能解决问题)。

编辑2:

更多调查后,我发现了一些有趣的东西:

1。。更改z值更改的速度确实会影响实体消失所需的时间。找到这个之后,我尝试对几个不同的dz(其中dz是每帧z的变化)值进行计时,然后得到了:

`for dz = -0.002 -> frames before dissapear: 515 frames.`
`for dz = -0.001 -> frames before dissapear: 1024 frames.`
`for dz = 0.02   -> frames before dissapear: 63 frames.`

如果考虑到反应时间(我使程序在关闭时输出渲染帧的总数,并在实体消失时尽快关闭它),我们可以计算实体消失时的z值。

-0.002 * 515  ≈ -1
-0.001 * 1024 ≈ -1
 0.02  * 63   ≈  1

这可能与坐标系统在OpenGL中的工作方式有关,但仍无法解释为什么实体没有像上述教程中那样变小。

2。。删除将ProjectionMatrix添加到渲染器类的代码不会更改行为。这意味着错误是其他的。

新问题:

我认为ProjectionMatrix没有问题(或者至少没有引起此问题的问题),但是问题是实体的位置在z轴上超过1或-1。但是,这仍然不能解释为什么没有“缩放效果”。因此,我不认为将z的移动限制在-1和1之间可以解决此问题,实际上,我认为这将不利于我们,因为如果实体完全“缩小”或“缩小”,则无论如何都不应该渲染。

如果不是ProjectionManager,会导致什么问题?

编辑3:

有人在reddit上指出,以下类可能对于解决问题也很有意义:

AbstractShader:包含所有着色器类共有的基本着色器功能。

TexturedEntityShader:用于渲染TexturedEntity(如上所示)

DisplayManager:处理渲染的类。

编辑4:

在关于reddit的更多讨论之后,我们遇到了一个问题并得以解决:useProjectionMatrix的值未加载,因为在我尝试加载着色器时,着色器已停止。将loadUseProjectionMatrix()方法更改为:

public void loadUseProjectionMatrix() {
    super.start();
    super.loadBoolean(useProjectionMatrixLocation, useProjectionMatrix);
    System.out.println("loaded useProjectionMatrix: " + useProjectionMatrix + "\n\n");
    super.stop();
}

似乎可以部分解决该问题,因为projectionMatrix现在可以在着色器内部使用(在此之前,由于useProjectionMatrix值始终为0,因此我们不使用它,因为我们没有使用为其加载值。)

但是,这不能解决整个问题,因为我认为projectionMatrix仍然存在问题。该实体完全不希望在使用projectionMatrix时渲染,但是在不使用它时可以很好地渲染。我已经尝试通过使用以下着色器对投影矩阵的值进行硬编码:

#version 150

in vec3 position;
in vec2 textureCoordinates;

out vec2 passTextureCoordinates;

uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform int useProjectionMatrix;

mat4 testMat;

void main(void){

    testMat[0] = vec4(0.83909965, 0, 0, 0);
    testMat[1] = vec4(0, 0.83909965, 0, 0);
    testMat[2] = vec4(0, 0, 0.9990005,  -0.9995003);
    testMat[3] = vec4(0, 0, -1,  0);

    if (true) {
        gl_Position = testMat * transformationMatrix * vec4(position,1.0);
    } else {
        gl_Position = transformationMatrix * vec4(position,1.0);
    }
    passTextureCoordinates = textureCoordinates;

}

但是,这似乎不起作用。这些值可以吗?

想在这里看到的人是我在reddit上创建的有关此问题的2篇帖子:post 1post 2

0 个答案:

没有答案