Go-GL的“Project”方法给出了意外的结果。

huangapple go评论154阅读模式
英文:

Go-GL "Project" method giving unexpected results

问题

Go-GL的Project方法给出了我意外地大的屏幕坐标。

总结一下:

// 屏幕尺寸为800x600。
projection := mgl32.Perspective(
mgl32.DegToRad(45), // 视角(45度)。
800.0 / 600.0, // 宽高比。
0.1, // 近平面距离0.1。
10) // 远平面距离10。
camera := mgl32.LookAtV(
mgl32.Vec3{0, 0.1, 10}, // 相机位置在Z轴上方一点点。
mgl32.Vec3{0, 0, 0}, // 相机看向原点。
mgl32.Vec3{0, 1, 0} // 上方向为正Y轴。
)
model := mgl32.Ident4() // 简单的模型矩阵,避免混淆。
modelView := camera.Mul4(model) // 模型视图矩阵(在这里等同于相机)。

// 好的,那么原点在屏幕上的坐标是多少?预期是屏幕中心,深度看起来是任意的。
origin := mgl32.Vec3{0, 0, 0}
screenOrigin := mgl32.Project(origin, modelView, projection, 0, 0, 800, 600)
fmt.Printf("原点: (%v, %v, %v)", screenOrigin[0], screenOrigin[1], screenOrigin[2])

// 那么原点右边5个单位的点呢?
// 预期X坐标增加,但仍然小于屏幕宽度。
// Y和Z坐标应与原点相同。
// 在我的实际程序中,我在(5,0,0)处绘制了一个(-1,-1,-1)-(1,1,1)的立方体,
// 它完全可见在窗口中。
test := mgl32.Vec3{5, 0, 0}
screenTest := mgl32.Project(test, modelView, projection, 0, 0, 800, 600)
fmt.Printf("测试点: (%v, %v, %v)", screenTest[0], screenTest[1], screenTest[2])

结果是?

原点: (400, 300, 5.500255)
测试点: (4021.32, 300, 5.500255)

4021.32?那远超出了屏幕范围!

除了我正在使用的立方体渲染之外,我几乎排除了所有我能想到的变量。我的代码基于这个示例,但我移动了相机和立方体:https://github.com/go-gl/examples/tree/master/gl41core-cube

如果我将输入向量设为(0, 0, 0),并将Ident4()在+X方向上平移5个单位(这是有意义的),我得到的结果是相同的。

那么我做错了什么?根据我绘制的立方体的位置,我预期的X坐标应该是625。

英文:

Go-GL's Project method is giving me unexpectedly large screen coordinates.

To summarize:

// Screen is 800x600.
projection := mgl32.Perspective(
    mgl32.DegToRad(45), // Field of view (45 degrees).
    800.0 / 600.0,      // Aspect ratio.
    0.1,                // Near Z at 0.1.
    10)                 // Far Z at 10.
camera := mgl32.LookAtV(
    mgl32.Vec3{0, 0.1, 10}, // Camera out on Z and slightly above.
    mgl32.Vec3{0, 0, 0},    // Looking at the origin.
    mgl32.Vec3{0, 1, 0}     // Up is positive Y.
model := mgl32.Ident4()     // Simple model matrix, to avoid confusion.
modelView := camera.Mul4(model) // The model-view matrix (== camera, here).

// Okay, so what does the origin translate to? Expect center-of-screen, with arbitrary-seeming depth.
origin := mgl32.Vec3{0, 0, 0}
screenOrigin := mgl32.Project(origin, modelView, projection, 0, 0, 800, 600)
fmt.Printf("Origin: (%v, %v, %v)", screenOrigin[0], screenOrigin[1], screenOrigin[2])

// What about the point 5 to the right of the origin?
// Expect increased X, but still less than screenWidth.
// Y and Z should be the same as for the origin.
// In my actual program, I drew (-1,-1,-1)-(1,1,1) cube at (5,0,0) and
// it is completely visible in the window.
test := mgl32.Vec3{5, 0, 0}
screenTest := mgl32.Project(test, modelView, projection, 0, 0, 800, 600)
fmt.Printf("Test:   (%v, %v, %v)", screenTest[0], screenTest[1], screenTest[2])

The results?

Origin: (400, 300, 5.500255)
Test:   (4021.32, 300, 5.500255)

4021.32? That's WAY off the screen!

I've pretty much eliminated all the variables I can think of except for the cube rendering I'm using as a hint basicall. My code is based on this, but I moved the camera and the cube: https://github.com/go-gl/examples/tree/master/gl41core-cube

I get the same results if I use (0, 0, 0) as the input vector and translate Ident4() by 5 units in +X (which makes sense).

So what am I doing wrong? Based on the position of the cube I'm drawing, I would expect something like X = 625.

答案1

得分: 3

出于好奇,我查看了mgl32的源代码。看起来project方法是错误的:

obj4 := obj.Vec4(1)

vpp := projection.Mul4(modelview).Mul4x1(obj4)
win[0] = float32(initialX) + (float32(width)*(vpp[0]+1))/2
win[1] = float32(initialY) + (float32(height)*(vpp[1]+1))/2
win[2] = (vpp[2] + 1) / 2

正如你可能注意到的,矩阵相乘后缺少透视除法,因此当w != 1.0f时,该函数将无法正常工作。

在第一个示例中,由于矩阵相乘后x和y都为零,因此除以w并没有什么区别(除了z)。在第二个示例中,x坐标不再为零,这个错误就会显现出来。

英文:

Out of curiosity I looked into the source code of mgl32. It seems that the project method is simply wrong:

obj4 := obj.Vec4(1)

vpp := projection.Mul4(modelview).Mul4x1(obj4)
win[0] = float32(initialX) + (float32(width)*(vpp[0]+1))/2
win[1] = float32(initialY) + (float32(height)*(vpp[1]+1))/2
win[2] = (vpp[2] + 1) / 2

As one might notice, the perspective divide is missing after the matrix multiplication, thus the function will not work whenever w != 1.0f.

In the first example, one cannot notice the error since x and y are zero after the matrix multiplication, thus dividing by w does not make a difference (except for z). In the second example, the x coordinate is not zero anymore and the bug gets visible.

huangapple
  • 本文由 发表于 2016年7月20日 11:14:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/38471708.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定