【问题标题】:OpenGL rotation wrong around x and z-axis. Around y it looks okay?OpenGL 围绕 x 和 z 轴的旋转错误。周围 y 看起来还好吗?
【发布时间】:2015-09-24 10:35:08
【问题描述】:

我完全被 OpenGL 中的旋转困住了(再次)。我不确定它到底是什么,但我有一些理论。

首先让我分享一些代码:

我在这里渲染三个实体,它们只是 Ico-Spheres 的 .obj 模型,在搅拌机中创建。

val testEntity: Test = new Test(new Vector3(-3.0f,0,0), new Vector3(0,0,0), 0.75f)
val testEntity2: Test = new Test(new Vector3(0,0,0), new Vector3(0,0,0), 0.75f)
val testEntity3: Test = new Test(new Vector3(3.0f,0,0), new Vector3(0,0,0), 0.75f)

override def render(): Unit =
{
  camera.update()
  testEntity.addRotation(new Vector3(1,0,0))
  testEntity.render(camera.getViewProjectionMatrix, camera.getViewMatrix)

  testEntity2.addRotation(new Vector3(0,1,0))
  testEntity2.render(camera.getViewProjectionMatrix, camera.getViewMatrix)

  testEntity3.addRotation(new Vector3(0,0,1))
  testEntity3.render(camera.getViewProjectionMatrix, camera.getViewMatrix)
}

如您所见,我所做的只是将三个球体彼此相邻设置并尝试围绕一个轴旋转每个球体。

addRotation(new Vector3(1,0,0)) 只是在实体的方向上添加一个旋转(在开头是 (0,0,0) ),所以在这种情况下它在 x 上添加 1 - 每帧轴。

理论#1 - 模型矩阵的计算错误

这就是我为每帧的每个实体计算模型矩阵的方式

protected def calculateModelMatrix(position: Vector3, orientation: Vector3, scale: Float): Matrix4 =
{
    val matrix: Matrix4 = Matrix4.Identity

    matrix.scale(new Vector3(scale, scale, scale))
    matrix.rotate(new Vector3(1,0,0), Math.toRadians(orientation.x).toFloat)
    matrix.rotate(new Vector3(0,1,0), Math.toRadians(orientation.y).toFloat)
    matrix.rotate(new Vector3(0,0,1), Math.toRadians(orientation.z).toFloat)
    matrix.translate(position)

    matrix
}

旋转应该始终发生在原点,但身份矩阵会处理这一点。 首先我们进行缩放,然后进行旋转,然后将实体平移到正确的位置。

Matrix4 类的rotate-方法如下所示:

def rotate(axis: Vector3, angle: Float): Unit =
{
    if(angle == 0) return

    axis match
    {
      case Vector3(1,0,0) => rotateX(angle)
      case Vector3(0,1,0) => rotateY(angle)
      case Vector3(0,0,1) => rotateZ(angle)
      case _ => //println("Rotation not yet implemented!")
    }
}

private def rotateX(angle: Float): Unit =
{
    val cos: Float = Math.cos(angle).toFloat
    val sin: Float = Math.sin(angle).toFloat

    this.m11 = cos
    this.m12 = -sin
    this.m21 = sin
    this.m22 = cos
}

private def rotateY(angle: Float): Unit =
{
    val cos: Float = Math.cos(angle).toFloat
    val sin: Float = Math.sin(angle).toFloat

    this.m00 = cos
    this.m02 = sin
    this.m20 = -sin
    this.m22 = cos
}

private def rotateZ(angle: Float): Unit =
{
    val cos: Float = Math.cos(angle).toFloat
    val sin: Float = Math.sin(angle).toFloat

    this.m00 = cos
    this.m01 = -sin
    this.m10 = sin
    this.m12 = cos
}

对于我严格遵守数学的帮助方法(或至少尝试过)(参考:http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation/https://en.wikipedia.org/wiki/Rotation_matrix

理论 #2 - 投影和/或视图矩阵的计算是错误的

对于每一帧,我都会调用camera.update()。它应该根据相机的位置更新我的视图和投影矩阵:

def update(): Unit =
{
    updateViewMatrix()
    updateViewProjectionMatrix()
}   

private def calculateViewProjectionMatrix(): Matrix4 =
{
    Matrix4.multiply(this.projectionMatrix, this.viewMatrix)
}

private def updateViewProjectionMatrix(): Unit =
{
    this.viewProjectionMatrix = calculateViewProjectionMatrix()
}

private 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 yScale: Float = (1.0f / Math.tan(Math.toRadians(FOV / 2f))).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
}

private 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.rotate(new Vector3(0,0,1), Math.toRadians(this.roll).toFloat)
    matrix.translate(new Vector3(-this.position.x, -this.position.y, -this.position.z))

    matrix
}

结果如下:

基本上绝对垃圾!围绕 y 轴(在中间)的一次旋转是唯一在旋转时不平移的一次。它仍然看起来有点压缩/捣碎(或者这只是我吗?!)围绕z旋转的那个?它完全关闭了!

现在我也尝试从https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/util/vector/Matrix4f.java 复制rotate

在代码中看起来像这样:

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.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

    this.m00 = t00
    this.m01 = t01
    this.m02 = t02
    this.m03 = t03

    this.m10 = t10
    this.m11 = t11
    this.m12 = t12
    this.m13 = t13
}

结果如下:

它看起来比我自己的实现要好,但对于 x 轴和 z 轴,实体在旋转时仍在平移。

我不明白为什么会这样,我调试了很长时间,但没有真正的用处。我的所作所为一定有问题。

后来我想切换到Quaternions,但我想,如果基本的旋转不起作用,那么现在实现四元数并不是一个好主意。

【问题讨论】:

  • 旋转总是围绕原点。所以你可以先将球的中心平移到原点,然后旋转再平移回来。
  • @ratchetfreak:这就是我使用单位矩阵开始的原因。所以开头的matrix.translate(new Vector3(0,0,0)) 不会改变任何事情。我也在我的帖子中明确提到了这一点。
  • 到代码 1:矩阵不能通过简单地覆盖其中的值来组合。相反,您必须将所有原始矩阵相乘。例如,在您当前的实现中,rotate 将覆盖一些由 scale 设置的值。
  • 至代码 2:旋转时平移,因为球体的原点似乎不在其中心,而是在球体的最底部。这就是球体旋转的点。

标签: scala opengl matrix rotation


【解决方案1】:

所以,根据@BDL,有两个错误,我(有点)修复了它们:

  1. 旋转时平移-错误

问题是 .obj 文件没有以原点为中心,所以我在 Blender 的帮助下解决了这个问题。当它居中时,不再发生翻译。愚蠢的错误!

  1. 实际的旋转错误

lwjgl 实现中没有错误。在我修复1. 之后,一切正常。但我也想修复我自己的实现,所以再次感谢 BDL,我知道我必须乘以我的矩阵。

对于 X 和 Y,这已经有效,对于 Z 不太好,但基本上是我所做的:

protected def calculateModelMatrix(position: Vector3, orientation: Vector3, scale: Float): Matrix4 =
{
    val matrix: Matrix4 = Matrix4.Identity

    matrix.scale(new Vector3(scale, scale, scale))
    matrix.rotate(new Vector3(1,0,0), Math.toRadians(orientation.x).toFloat)
    val rotXYMatrix: Matrix4 = Matrix4.multiply(Matrix4.rotate(new Vector3(0,1,0), Math.toRadians(orientation.y).toFloat), matrix)
    val rotXYZMatrix: Matrix4 = Matrix4.multiply(Matrix4.rotate(new Vector3(0,0,1), Math.toRadians(orientation.z).toFloat), rotXYMatrix)
    rotXYZMatrix.translate(position)

    rotXYZMatrix
}

不确定为什么它对 z 不起作用,但这是(半)工作结果:

编辑:现在也修复了:

是一个错误:

private def rotateZ(angle: Float): Unit =
  {
    val cos: Float = Math.cos(angle).toFloat
    val sin: Float = Math.sin(angle).toFloat

    this.m00 = cos
    this.m01 = -sin
    this.m10 = sin
    this.m12 = cos
  }

当然不是this.m12 = cos,而是this.m11 = cos。现在按预期工作!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-06
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多