【问题标题】:Rotating a cube in modern opengl... looks strange在现代opengl中旋转一个立方体......看起来很奇怪
【发布时间】:2015-09-03 11:45:15
【问题描述】:

我有些失落,真的失落。

我正在尝试旋转一个立方体(现在只是围绕 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
}

从正面渲染立方体就像一个魅力。我还没有实现移动“相机”,所以也许 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
}

如果您需要额外的代码,我可以提供一切,我只是不想发布所有代码并阻止很多人。

编辑

根据 cmets 添加着色器代码和投影矩阵生成:

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
}

(是的,窗口尺寸匹配 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)

viewProjetionMatrix 在哪里:

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

而且,100% 确定,multiply-method...我们这里有一个对象(就像所有 java-devs 的静态方法)

def multiply(left: Matrix4, right: Matrix4): Matrix4 =
{
    val matrix: Matrix4 = new Matrix4(left)
    matrix.multiply(right)

    matrix
}

里面有一个copy-constructor,类实例的multiply-method是:

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)... 所以第一行是 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
  }

也许乘法是错误的(可能是,但对我来说真的很奇怪,因为我之前验证过)

【问题讨论】:

  • 嗯,something 至少有一个矩阵有问题。如果您为某些特定参数(如 90 度和 45 度)转储矩阵的值,这可能会有所帮助。也许你的着色器也错了。
  • 我觉得你的立方体实际上在改变形状很奇怪。从任何角度来看,它甚至都不应缩小为一条垂直线。我觉得你实际上是在修改你的立方体,而不仅仅是视图。
  • 在我看来,当角度 = 90° 时,缩放比例为零
  • 您也必须使用投影矩阵吗?我的钱花在投影矩阵被破坏上。或者,正如@derhass 已经建议的那样,顶点着色器中发生了一些奇怪的事情。例如,您可能以错误的顺序应用矩阵。
  • 我想我找到了问题,将您的 Matrix.rotate 代码与链接代码进行比较,您首先更改“this.m00 = t00”,然后再执行“this.m20 = this.m00” * f20 + this.m10 * f21 + this.m20 * f22",使用修改后的 this.m00。你这样做几次。您链接的代码以相反的方式进行,从逻辑上讲,您的里程会有所不同。只需交换两/三个代码块就可以了,看起来。如果这是问题,请报告。

标签: scala opengl 3d lwjgl opengl-3


【解决方案1】:

将您的Matrix.rotate 代码与链接代码进行比较,您首先要这样做

this.m00 = t00

然后你再做

this.m20 = this.m00 * f20 + this.m10 * f21 + this.m20 * f22

使用您刚刚修改的 this.m00。您以类似的方式执行此操作几次。示例代码以相反的方式执行此操作,这意味着最终结果不同。交换代码块,一切都应该没问题。我希望 LWJGL 很快会决定重新添加线性代数类!

【讨论】:

  • 是的,修补它很有趣。但是做数学运算和煞费苦心地说服你的计算机做数学运算是有区别的,这肯定属于后一类。我觉得矩阵类在那里,所以你可以在没有无聊部分的情况下进行数学运算,基本上:)
  • 真正令人尴尬的部分是,我错过了重用我刚刚设置的变量,同时查看了十几次代码。我非常确定错误出在旋转方法中,但我没有找到它-.-
  • 这是很常见的事情,这就是为什么有时对你的代码有一些新的看法可以在 10 秒内解决问题。这也是为什么有些人建议不要复制粘贴代码的原因。睡一觉也有帮助^^我认为学习调试的最好方法之一就是在这里回答问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-04
  • 1970-01-01
  • 2015-12-07
相关资源
最近更新 更多