我正在使用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;
}
我能够正常更改实体的x
和y
值的位置,但是每当我使用EntityModifier更改z
位置时,都会加载实体,但随后从屏幕上消失。在消失和更改dz
的值之前,它已加载约60帧,但似乎丝毫没有影响它消失的速度(它确实如此,请参见编辑2)。同样,该实体不具有tutorial here中所示的缩放效果(相同的链接,但带有时间戳)。
将dz
的值更改为0可以停止实体的消失。
这是怎么回事?我该如何解决?
我在评论中指出,nearPlane值应为正,因此将其更改为0.5,但仍然得到相同的结果。我也将float frustum_length = nearPlane - farPlane;
更改为float frustum_length = farPlane - nearPlane;
,在那里也有人建议这样做(这也不能解决问题)。
更多调查后,我发现了一些有趣的东西:
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,会导致什么问题?
有人在reddit上指出,以下类可能对于解决问题也很有意义:
AbstractShader:包含所有着色器类共有的基本着色器功能。
TexturedEntityShader:用于渲染TexturedEntity(如上所示)
DisplayManager:处理渲染的类。
在关于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;
}
但是,这似乎不起作用。这些值可以吗?