在现代 opengl 中旋转立方体......看起来很奇怪
Rotating a cube in modern opengl... looks strange
有点迷茫,真的很迷茫
我正在尝试旋转立方体(目前仅围绕 y 轴旋转),这是(丑陋且错误的)结果:
这是旋转矩阵的代码:
def rotate(axis: Vector3, angle: Float): Unit =
{
val cosAngle: Float = Math.cos(angle).toFloat
val sinAngle: Float = Math.sin(angle).toFloat
val oneMinusCosAngle: Float = 1.0f - cosAngle
val xy: Float = axis.x * axis.y
val xz: Float = axis.x * axis.z
val yz: Float = axis.y * axis.z
val xs: Float = axis.x * sinAngle
val ys: Float = axis.y * sinAngle
val zs: Float = axis.z * sinAngle
val f00: Float = axis.x * axis.x * oneMinusCosAngle + cosAngle
val f01: Float = xy * oneMinusCosAngle + zs
val f02: Float = xz * oneMinusCosAngle - ys
val f10: Float = xy * oneMinusCosAngle - zs
val f11: Float = axis.y * axis.y * oneMinusCosAngle + cosAngle
val f12: Float = yz * oneMinusCosAngle + xs
val f20: Float = xz * oneMinusCosAngle + ys
val f21: Float = yz * oneMinusCosAngle - xs
val f22: Float = axis.z * axis.z * oneMinusCosAngle + cosAngle
val t00: Float = this.m00 * f00 + this.m10 * f01 + this.m20 * f02
val t01: Float = this.m01 * f00 + this.m11 * f01 + this.m21 * f02
val t02: Float = this.m02 * f00 + this.m12 * f01 + this.m22 * f02
val t03: Float = this.m03 * f00 + this.m13 * f01 + this.m23 * f02
val t10: Float = this.m00 * f10 + this.m10 * f11 + this.m20 * f12
val t11: Float = this.m01 * f10 + this.m11 * f11 + this.m21 * f12
val t12: Float = this.m02 * f10 + this.m12 * f11 + this.m22 * f12
val t13: Float = this.m03 * f10 + this.m13 * f11 + this.m23 * f12
this.m00 = t00
this.m01 = t01
this.m02 = t02
this.m03 = t03
this.m10 = t10
this.m11 = t11
this.m12 = t12
this.m13 = t13
this.m20 = this.m00 * f20 + this.m10 * f21 + this.m20 * f22
this.m21 = this.m01 * f20 + this.m11 * f21 + this.m21 * f22
this.m22 = this.m02 * f20 + this.m12 * f21 + this.m22 * f22
this.m23 = this.m03 * f20 + this.m13 * f21 + this.m23 * f22
}
它的灵感来自于:https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/util/vector/Matrix4f.java 它不再是 lwjgl 3 的一部分
立方体本身由这些顶点、索引和纹理坐标组成
val vertices: Array[Float] = Array(
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,0.5f,-0.5f,
-0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
0.5f,0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
0.5f,0.5f,-0.5f,
0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f
)
val indices: Array[Int] = Array(
0,1,3,
3,1,2,
4,5,7,
7,5,6,
8,9,11,
11,9,10,
12,13,15,
15,13,14,
16,17,19,
19,17,18,
20,21,23,
23,21,22
)
val textureCoords: Array[Float] = Array(
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0
)
它的模型矩阵是这样计算的:
def calculateModelMatrix(position: Vector3, rotation: Vector3, scale: Float): Matrix4 =
{
val matrix: Matrix4 = Matrix4.Identity
matrix.translate(position)
matrix.rotate(new Vector3(1,0,0), Math.toRadians(rotation.x).toFloat)
matrix.rotate(new Vector3(0,1,0), Math.toRadians(rotation.y).toFloat)
matrix.rotate(new Vector3(0,0,1), Math.toRadians(rotation.z).toFloat)
matrix.scale(new Vector3(scale, scale, scale))
matrix
}
从正面渲染立方体非常有效。我还没有实施移动 "camera",所以也许 viewMatrix 是错误的?
ViewMatrix 是在每一帧(在相机中)计算的,像这样:
def calculateViewMatrix(): Matrix4 =
{
val matrix: Matrix4 = Matrix4.Identity
matrix.rotate(new Vector3(1,0,0), Math.toRadians(this.pitch).toFloat)
matrix.rotate(new Vector3(0,1,0), Math.toRadians(this.yaw).toFloat)
matrix.translate(new Vector3(-this.position.x, -this.position.y, -this.position.z))
matrix
}
如果你需要额外的代码,我可以提供一切,我只是不想post所有的代码而让很多人望而却步。
编辑:
根据评论添加着色器代码和投影矩阵生成:
def calculateProjectionMatrix(): Matrix4 =
{
val aspectRatio: Float = 1024 / 768 // TODO get this from somewhere
val yScale: Float = ((1.0f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio).toFloat
val xScale: Float = yScale / aspectRatio
val frustumLength = FAR_PLANE - NEAR_PLANE
val matrix: Matrix4 = Matrix4.Zero
matrix.m00 = xScale
matrix.m11 = yScale
matrix.m22 = -((FAR_PLANE + NEAR_PLANE) / frustumLength)
matrix.m23 = -1.0f
matrix.m32 = -((2.0f * NEAR_PLANE * FAR_PLANE) / frustumLength)
matrix
}
(是的,window 测量值匹配 1024*768)
projectionMatrix 设置一次,因为它永远不会改变。
着色器代码:
#version 330 core
in vec3 position;
in vec2 textureCoords;
out vec2 passTextureCoords;
uniform mat4 modelViewProjectionMatrix;
void main(void)
{
gl_Position = modelViewProjectionMatrix * vec4(position, 1.0f);
passTextureCoords = textureCoords;
}
并且,modelViewProjectionMatrix 计算(并设置)每一帧,如下所示:
modelViewProjectionMatrix = Matrix4.multiply(viewProjectionMatrix, modelMatrix)
其中 viewProjectionMatrix 是:
def calculateViewProjectionMatrix(): Matrix4 =
{
Matrix4.multiply(this.projectionMatrix, this.viewMatrix)
}
并且,可以 100% 确定,乘法...我们这里有一个对象(就像所有 java-dev 的静态方法)
def multiply(left: Matrix4, right: Matrix4): Matrix4 =
{
val matrix: Matrix4 = new Matrix4(left)
matrix.multiply(right)
matrix
}
那里有一个复制构造函数,class-实例的乘法是:
def multiply(right: Matrix4): Unit =
{
set(
this.m00 * right.m00 + this.m10 * right.m01 + this.m20 * right.m02 + this.m30 * right.m03,
this.m01 * right.m00 + this.m11 * right.m01 + this.m21 * right.m02 + this.m31 * right.m03,
this.m02 * right.m00 + this.m12 * right.m01 + this.m22 * right.m02 + this.m32 * right.m03,
this.m03 * right.m00 + this.m13 * right.m01 + this.m23 * right.m02 + this.m33 * right.m03,
this.m00 * right.m10 + this.m10 * right.m11 + this.m20 * right.m12 + this.m30 * right.m13,
this.m01 * right.m10 + this.m11 * right.m11 + this.m21 * right.m12 + this.m31 * right.m13,
this.m02 * right.m10 + this.m12 * right.m11 + this.m22 * right.m12 + this.m32 * right.m13,
this.m03 * right.m10 + this.m13 * right.m11 + this.m23 * right.m12 + this.m33 * right.m13,
this.m00 * right.m20 + this.m10 * right.m21 + this.m20 * right.m22 + this.m30 * right.m23,
this.m01 * right.m20 + this.m11 * right.m21 + this.m21 * right.m22 + this.m31 * right.m23,
this.m02 * right.m20 + this.m12 * right.m21 + this.m22 * right.m22 + this.m32 * right.m23,
this.m03 * right.m20 + this.m13 * right.m21 + this.m23 * right.m22 + this.m33 * right.m23,
this.m00 * right.m30 + this.m10 * right.m31 + this.m20 * right.m32 + this.m30 * right.m33,
this.m01 * right.m30 + this.m11 * right.m31 + this.m21 * right.m32 + this.m31 * right.m33,
this.m02 * right.m30 + this.m12 * right.m31 + this.m22 * right.m32 + this.m32 * right.m33,
this.m03 * right.m30 + this.m13 * right.m31 + this.m23 * right.m32 + this.m33 * right.m33
)
}
其中 set(...) 只是设置 Matrix4 的 var(iable)s...所以第一行是 m00,最后一行是 m33。
def set( m00: Float, m01: Float, m02: Float, m03: Float,
m10: Float, m11: Float, m12: Float, m13: Float,
m20: Float, m21: Float, m22: Float, m23: Float,
m30: Float, m31: Float, m32: Float, m33: Float): Unit =
{
this.m00 = m00
this.m01 = m01
this.m02 = m02
this.m03 = m03
this.m10 = m10
this.m11 = m11
this.m12 = m12
this.m13 = m13
this.m20 = m20
this.m21 = m21
this.m22 = m22
this.m23 = m23
this.m30 = m30
this.m31 = m31
this.m32 = m32
this.m33 = m33
}
也许乘法是错误的(可能是,但对我来说真的很奇怪,因为我之前已经验证过了)
将您的 Matrix.rotate
代码与链接代码进行比较,您首先要做
this.m00 = t00
然后你再做
this.m20 = this.m00 * f20 + this.m10 * f21 + this.m20 * f22
使用您刚刚修改的 this.m00。您以类似的方式执行此操作几次。示例代码以相反的方式执行此操作,这意味着最终结果是不同的。交换代码块,一切都应该没问题。希望LWJGL尽快决定把线性代数类加回来!
有点迷茫,真的很迷茫
我正在尝试旋转立方体(目前仅围绕 y 轴旋转),这是(丑陋且错误的)结果:
这是旋转矩阵的代码:
def rotate(axis: Vector3, angle: Float): Unit =
{
val cosAngle: Float = Math.cos(angle).toFloat
val sinAngle: Float = Math.sin(angle).toFloat
val oneMinusCosAngle: Float = 1.0f - cosAngle
val xy: Float = axis.x * axis.y
val xz: Float = axis.x * axis.z
val yz: Float = axis.y * axis.z
val xs: Float = axis.x * sinAngle
val ys: Float = axis.y * sinAngle
val zs: Float = axis.z * sinAngle
val f00: Float = axis.x * axis.x * oneMinusCosAngle + cosAngle
val f01: Float = xy * oneMinusCosAngle + zs
val f02: Float = xz * oneMinusCosAngle - ys
val f10: Float = xy * oneMinusCosAngle - zs
val f11: Float = axis.y * axis.y * oneMinusCosAngle + cosAngle
val f12: Float = yz * oneMinusCosAngle + xs
val f20: Float = xz * oneMinusCosAngle + ys
val f21: Float = yz * oneMinusCosAngle - xs
val f22: Float = axis.z * axis.z * oneMinusCosAngle + cosAngle
val t00: Float = this.m00 * f00 + this.m10 * f01 + this.m20 * f02
val t01: Float = this.m01 * f00 + this.m11 * f01 + this.m21 * f02
val t02: Float = this.m02 * f00 + this.m12 * f01 + this.m22 * f02
val t03: Float = this.m03 * f00 + this.m13 * f01 + this.m23 * f02
val t10: Float = this.m00 * f10 + this.m10 * f11 + this.m20 * f12
val t11: Float = this.m01 * f10 + this.m11 * f11 + this.m21 * f12
val t12: Float = this.m02 * f10 + this.m12 * f11 + this.m22 * f12
val t13: Float = this.m03 * f10 + this.m13 * f11 + this.m23 * f12
this.m00 = t00
this.m01 = t01
this.m02 = t02
this.m03 = t03
this.m10 = t10
this.m11 = t11
this.m12 = t12
this.m13 = t13
this.m20 = this.m00 * f20 + this.m10 * f21 + this.m20 * f22
this.m21 = this.m01 * f20 + this.m11 * f21 + this.m21 * f22
this.m22 = this.m02 * f20 + this.m12 * f21 + this.m22 * f22
this.m23 = this.m03 * f20 + this.m13 * f21 + this.m23 * f22
}
它的灵感来自于:https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/util/vector/Matrix4f.java 它不再是 lwjgl 3 的一部分
立方体本身由这些顶点、索引和纹理坐标组成
val vertices: Array[Float] = Array(
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,0.5f,-0.5f,
-0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
0.5f,0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
0.5f,0.5f,-0.5f,
0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f
)
val indices: Array[Int] = Array(
0,1,3,
3,1,2,
4,5,7,
7,5,6,
8,9,11,
11,9,10,
12,13,15,
15,13,14,
16,17,19,
19,17,18,
20,21,23,
23,21,22
)
val textureCoords: Array[Float] = Array(
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0,
0,0,
0,1,
1,1,
1,0
)
它的模型矩阵是这样计算的:
def calculateModelMatrix(position: Vector3, rotation: Vector3, scale: Float): Matrix4 =
{
val matrix: Matrix4 = Matrix4.Identity
matrix.translate(position)
matrix.rotate(new Vector3(1,0,0), Math.toRadians(rotation.x).toFloat)
matrix.rotate(new Vector3(0,1,0), Math.toRadians(rotation.y).toFloat)
matrix.rotate(new Vector3(0,0,1), Math.toRadians(rotation.z).toFloat)
matrix.scale(new Vector3(scale, scale, scale))
matrix
}
从正面渲染立方体非常有效。我还没有实施移动 "camera",所以也许 viewMatrix 是错误的?
ViewMatrix 是在每一帧(在相机中)计算的,像这样:
def calculateViewMatrix(): Matrix4 =
{
val matrix: Matrix4 = Matrix4.Identity
matrix.rotate(new Vector3(1,0,0), Math.toRadians(this.pitch).toFloat)
matrix.rotate(new Vector3(0,1,0), Math.toRadians(this.yaw).toFloat)
matrix.translate(new Vector3(-this.position.x, -this.position.y, -this.position.z))
matrix
}
如果你需要额外的代码,我可以提供一切,我只是不想post所有的代码而让很多人望而却步。
编辑:
根据评论添加着色器代码和投影矩阵生成:
def calculateProjectionMatrix(): Matrix4 =
{
val aspectRatio: Float = 1024 / 768 // TODO get this from somewhere
val yScale: Float = ((1.0f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio).toFloat
val xScale: Float = yScale / aspectRatio
val frustumLength = FAR_PLANE - NEAR_PLANE
val matrix: Matrix4 = Matrix4.Zero
matrix.m00 = xScale
matrix.m11 = yScale
matrix.m22 = -((FAR_PLANE + NEAR_PLANE) / frustumLength)
matrix.m23 = -1.0f
matrix.m32 = -((2.0f * NEAR_PLANE * FAR_PLANE) / frustumLength)
matrix
}
(是的,window 测量值匹配 1024*768)
projectionMatrix 设置一次,因为它永远不会改变。
着色器代码:
#version 330 core
in vec3 position;
in vec2 textureCoords;
out vec2 passTextureCoords;
uniform mat4 modelViewProjectionMatrix;
void main(void)
{
gl_Position = modelViewProjectionMatrix * vec4(position, 1.0f);
passTextureCoords = textureCoords;
}
并且,modelViewProjectionMatrix 计算(并设置)每一帧,如下所示:
modelViewProjectionMatrix = Matrix4.multiply(viewProjectionMatrix, modelMatrix)
其中 viewProjectionMatrix 是:
def calculateViewProjectionMatrix(): Matrix4 =
{
Matrix4.multiply(this.projectionMatrix, this.viewMatrix)
}
并且,可以 100% 确定,乘法...我们这里有一个对象(就像所有 java-dev 的静态方法)
def multiply(left: Matrix4, right: Matrix4): Matrix4 =
{
val matrix: Matrix4 = new Matrix4(left)
matrix.multiply(right)
matrix
}
那里有一个复制构造函数,class-实例的乘法是:
def multiply(right: Matrix4): Unit =
{
set(
this.m00 * right.m00 + this.m10 * right.m01 + this.m20 * right.m02 + this.m30 * right.m03,
this.m01 * right.m00 + this.m11 * right.m01 + this.m21 * right.m02 + this.m31 * right.m03,
this.m02 * right.m00 + this.m12 * right.m01 + this.m22 * right.m02 + this.m32 * right.m03,
this.m03 * right.m00 + this.m13 * right.m01 + this.m23 * right.m02 + this.m33 * right.m03,
this.m00 * right.m10 + this.m10 * right.m11 + this.m20 * right.m12 + this.m30 * right.m13,
this.m01 * right.m10 + this.m11 * right.m11 + this.m21 * right.m12 + this.m31 * right.m13,
this.m02 * right.m10 + this.m12 * right.m11 + this.m22 * right.m12 + this.m32 * right.m13,
this.m03 * right.m10 + this.m13 * right.m11 + this.m23 * right.m12 + this.m33 * right.m13,
this.m00 * right.m20 + this.m10 * right.m21 + this.m20 * right.m22 + this.m30 * right.m23,
this.m01 * right.m20 + this.m11 * right.m21 + this.m21 * right.m22 + this.m31 * right.m23,
this.m02 * right.m20 + this.m12 * right.m21 + this.m22 * right.m22 + this.m32 * right.m23,
this.m03 * right.m20 + this.m13 * right.m21 + this.m23 * right.m22 + this.m33 * right.m23,
this.m00 * right.m30 + this.m10 * right.m31 + this.m20 * right.m32 + this.m30 * right.m33,
this.m01 * right.m30 + this.m11 * right.m31 + this.m21 * right.m32 + this.m31 * right.m33,
this.m02 * right.m30 + this.m12 * right.m31 + this.m22 * right.m32 + this.m32 * right.m33,
this.m03 * right.m30 + this.m13 * right.m31 + this.m23 * right.m32 + this.m33 * right.m33
)
}
其中 set(...) 只是设置 Matrix4 的 var(iable)s...所以第一行是 m00,最后一行是 m33。
def set( m00: Float, m01: Float, m02: Float, m03: Float,
m10: Float, m11: Float, m12: Float, m13: Float,
m20: Float, m21: Float, m22: Float, m23: Float,
m30: Float, m31: Float, m32: Float, m33: Float): Unit =
{
this.m00 = m00
this.m01 = m01
this.m02 = m02
this.m03 = m03
this.m10 = m10
this.m11 = m11
this.m12 = m12
this.m13 = m13
this.m20 = m20
this.m21 = m21
this.m22 = m22
this.m23 = m23
this.m30 = m30
this.m31 = m31
this.m32 = m32
this.m33 = m33
}
也许乘法是错误的(可能是,但对我来说真的很奇怪,因为我之前已经验证过了)
将您的 Matrix.rotate
代码与链接代码进行比较,您首先要做
this.m00 = t00
然后你再做
this.m20 = this.m00 * f20 + this.m10 * f21 + this.m20 * f22
使用您刚刚修改的 this.m00。您以类似的方式执行此操作几次。示例代码以相反的方式执行此操作,这意味着最终结果是不同的。交换代码块,一切都应该没问题。希望LWJGL尽快决定把线性代数类加回来!