Android OpenGL ES -我不能做gluLookAt/gluPerspective的工作。

时间:2020-12-26 21:01:28

the following text is a bit lenghty as I wanted to make sure that people with similar problems that e.g. google this page can easily follow the exact problem and its solutions easily. But now on to my issue:

下面的文字是有点冷的,因为我想要确保有类似问题的人,例如谷歌,这个页面可以很容易地跟踪准确的问题和它的解决方案。但是现在我的问题是

I recently started programming OpenGL ES on an Android smartphone and ran into problems understanding how gluPerspective and gluLookAt are used. I think I understand what they do, however I cannot see the triangle I draw. I run the following code in the onDrawFrame-method of my activity. Said activity implements GLSurfaceView.Renderer with the onDrawFrame marked with @Override. My code is:

我最近开始在Android智能手机上为OpenGL ES编程,在理解gluPerspective和gluLookAt是如何使用的问题上遇到了困难。我想我知道他们在做什么,但是我看不到我画的三角形。我在活动的onDrawFrame-method中运行以下代码。活动实现GLSurfaceView说。使用@Override标记为onDrawFrame的渲染器。我的代码是:

gl.glViewport(0, 0, screen_width, screen_height);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //set background to black
gl.glClearDepthf(1.0f); 

gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

gl.glMatrixMode(GL10.GL_PROJECTION); // Change PROJECTION matrix
gl.glLoadIdentity();

float aspect_ratio = (float) screen_width / screen_height;
GLU.gluPerspective(gl, 67, aspect_ratio, 1, 100);

gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glMatrixMode(GL10.GL_MODELVIEW); // Change MODELVIEW matrix
gl.glLoadIdentity();

GLU.gluLookAt(gl, 0, 0, 20, 0, 0, 0, 0, 1, 0);

// make triangle with vertices (-2,0,0), (2,0,0), and (0,.5,0)
float[] vertices = { -2f, 0, 0, 2f, 0, 0, 0, .5f, 0 };
ByteBuffer buffer = ByteBuffer.allocateDirect(vertices.length * 4);
buffer.order(ByteOrder.nativeOrder());
FloatBuffer vertex_buffer = buffer.asFloatBuffer();
for (int i = 0; i < 9; i++) {
    vertex_buffer.put(vertices[i]);
}

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertex_buffer);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_DEPTH_TEST);

The next points are short notes on what I putatively know about camera settings in the above code. PLEASE correct me if I got something wrong in the following explanations, as that might already solve all of my issues!

下面的要点是我对上述代码中相机设置的初步了解。如果我在下面的解释中出错了,请纠正我,因为这可能已经解决了我所有的问题!

  1. glMatrixMode(GL10.GL_PROJECTION) switches to changing the camera matrix (for which I load an identity matrix directly afterwards)
  2. glMatrixMode(gl10 . gl_投影)转换为修改摄像机矩阵(之后直接加载一个单位矩阵)
  3. GLU.gluPerspective(gl, 67, aspect_ratio, 1, 100) sets a perspective projection with a view frustrum of 67 degree view angle in the y-dimension. Using "aspect_ration=(float)width/height" OpenGL computes the view angle in the x-dimension. Further the "1" is the near clipping plane, while "100" is the value of the far clipping plane in this case.
  4. GLU。gluPerspective(gl, 67, aspect_ratio, 1,100)在y维空间中设置了一个视角投影,其视角圆锥为67度。使用“aspect_ration=(float)width/height”OpenGL计算x维的视图角度。进一步的“1”是近剪切面,而“100”是在这种情况下的远剪切面的值。
  5. As far as I know it does not matter, where in the code gluLookAt is called, as long as it is done before the actual drawing (I'm unsure about this though). In this example I change to the MODELVIEW matrix first, load an identity matrix, and then gluLookAt is called. 3.
  6. 就我所知,在代码中调用gluLookAt并不重要,只要它在实际绘制之前完成(我对此不确定)。在这个例子中,我首先更改了MODELVIEW矩阵,加载一个单位矩阵,然后调用gluLookAt。3所示。
  7. "GLU.gluLookAt(gl, 0, 0, 20, 0, 0, 0, 0, 1, 0)" actually consists of three 3-element vectors. The initial one ((0,0,20) in this example) sets the position of the camera in world coordinates (i.e. 20 units on the positive Z-axis, which means it is "sticking out" of the front of the phone's screen). The second vector determines the point in the world coordinate system the camera looks at (in this example the origin of the coordinate system, i.e. the camera looks along the negative z-axis). The third vector is the up-vector that defines the direction of the y-Axis of the cameras coordinate system (and therefore also the x-axis via cross product with the vector from camera position to the point it looks at).
  8. “GLU。gluLookAt(gl, 0,0,0,0,0,0,0,20, 0,0,0,0,0,0,1,0)实际上包含三个元素向量。初始的(本例中为0,0,20)设置了相机在世界坐标中的位置(也就是正z轴上的20个单位,这意味着它“伸出”在手机屏幕的前部)。第二个向量决定了摄像机所看到的世界坐标系中的点(在这个例子中,坐标系统的原点,即摄像机沿着负的z轴)。第三个向量是上向量,它定义了摄像机坐标系y轴的方向(因此也定义了x轴与从摄像机位置到它所看到的点的矢量的叉积)。

The triangle drawing code was copied from a tutorial (but I found similar code also in other tutorials, so I assume this is not the problem).

三角形绘图代码是从教程中复制的(但是我在其他教程中也发现了类似的代码,所以我认为这不是问题所在)。

As far as I get it, the camera is now positioned on (0,0,20) and looks towards the origin of the coordinate system. Its drawing frustrum starts at z-value 19 and goes as far as -80 (the camera is at z-axis point 20 and looks along the negative z-axis; its viewing frustrum has near and far plane at 1 and 100 (both looking along the negative z-axis in this case), respectively). Therefore, the triangle should be visible, as its vertices are positioned around the origin on the z-axis=0 plane (i.e. the xy-plane), which is clearly within the viewing frustrum. Further the drawn vertices are arranged in counter-clockwise order; the default in OpenGL.

就我所知,摄像机现在定位在(0,0,20)上,并朝坐标系统的原点看。从z值19开始,它的拉深开始,最远到-80(相机在z轴点20,沿着负z轴;它的观察挫折有*面和远平面分别在1和100(在本例中都沿着负z轴)。因此,三角形应该是可见的,因为它的顶点位于z轴=0平面上的原点(即xy平面),这显然是在观测器之内。此外,绘制的顶点按逆时针方向排列;默认在OpenGL。

So after this long introduction into the problem my simple question is: What did I mess up so that this code does not do what I expect it to?

在对这个问题进行了长时间的介绍之后,我的简单问题是:我做错了什么,以至于这段代码没有做我预期的事情?

2 个解决方案

#1


5  

I've only ever used OpenGL on PC, Mac and iOS, but from what I can tell, the code looks fine. Then again, mine always does, too, but I still get the empty screen for a while, pretty much any time I start on anything 3D from scratch (regardless of API)... so here are some things to try, pretty much in the order in which to try them. Hopefully at least one of them will be something you haven't tried yet!

我只在PC、Mac和iOS上使用过OpenGL,但从我的经验来看,代码看起来还不错。同样,我的也总是这样,但是我仍然有一段时间是空的屏幕,几乎任何时候我都可以从头开始使用3D(不管API是什么)……这里有一些可以尝试的东西,基本上是按照尝试的顺序来做的。希望至少有一个是你还没有尝试过的东西!

  • Add in a glFlush at the end, because you're not actually drawing all that much. You'd think the driver would do this for you when you do the buffer swap, but it seems that there's no guarantees of that -- Mac OS X doesn't always seem to, for example.
  • 最后添加一个glFlush,因为你实际上并没有画那么多。当你进行缓冲区交换时,你可能会认为驱动程序会为你做这些,但似乎并不能保证这一点——例如,Mac OS X似乎并不总是这样。
  • Set background to non-black. If something is drawing in black, you want to see it.
  • 背景设置为黑色。如果有什么东西在画黑色,你想看到它。
  • Disable GL_LIGHTING. If this is enabled (which I think it is by default?) but you're not supplying normals, everything will come out black. (See above.)
  • 禁用GL_LIGHTING。如果这是启用的(我认为它是默认的吗?)但是你没有提供法线,那么所有的东西都会变成黑色。(见上图)。
  • Disable GL_CULL_FACE. It doesn't matter how carefully you think about the winding order, there's still a possibility you might have got it wrong. But if GL_CULL_FACE is off, that becomes impossible.
  • 禁用GL_CULL_FACE。不管你怎么仔细地考虑缠绕顺序,还是有可能你弄错了。但是如果GL_CULL_FACE关闭,那就不可能了。
  • Disable GL_DEPTH_TEST. This has saved me a couple of times, when I've typed glClearDepth(0) by accident. Looks like you're OK in that respect, but it's still worth a go.
  • 禁用GL_DEPTH_TEST。当我不小心输入了glClearDepth(0)时,这为我节省了几次时间。在这方面你看起来还不错,但还是值得一试。
  • Check glGetError religiously, after EVERY API call, just in case. (assert(glGetError()==GL_NO_ERROR) will do for starters, but you really want to have a little loop that also prints the result of gluErrorString so that it's easier to see at a glance what might be wrong.)
  • 虔诚地检查glGetError,在每次API调用之后,以防万一。(assert(glGetError()==GL_NO_ERROR)对初学者来说是可行的,但您确实希望有一个小循环,该循环也打印gluErrorString的结果,以便更容易一眼就看出哪里出错了。)
  • Make sure you do a glBindBuffer to set your ARRAY_BUFFER and ARRAY_ELEMENT_BUFFER bindings to 0. To initialize a VBO, you have to bind it, so if you've got something somewhere that sets one up it might just leave it bound. This will stuff up your glVertexPointer.
  • 确保使用glBindBuffer将ARRAY_BUFFER和ARRAY_ELEMENT_BUFFER绑定设置为0。要初始化一个VBO,你必须绑定它,所以如果你在某个地方设置了一个,它可能会保留它的绑定。这将填充glVertexPointer。
  • Along the lines of the last few - set up more state explicitly. In this case, for example, you might want to glDisableClientState the other array types, just in case. GL starts up with vertex arrays disabled, according to the docs, but it's a possibility worth eliminating.
  • 沿着最后几行,显式地设置了更多的状态。例如,在本例中,您可能希望glDisableClientState其他数组类型,以防万一。根据文档,GL一开始是禁用顶点数组的,但是它是值得消除的。

#2


2  

I found the answer after looking at further tutorials (and then also noticed it in the ones I used before)! Thank all of you for your answers, they were very helpful in diagnosing OpenGL problems in general and will for sure help me in the future!

我在看了更多的教程后找到了答案(然后在我以前使用的教程中也注意到了)!谢谢大家的回答,它们对诊断OpenGL问题很有帮助,将来肯定会对我有帮助!

The solution to my problem is... that the problem is not glulookat or gluperspective, but in my case the internal position of the FloatBuffer. I did not set the position of variable vertex_buffer to 0 after the for(0 < i < 9) loop. Setting the buffer's position to 0 can be accomplished with at least two commands:

我的问题的解决办法是……问题不在于glulookat或gluperspective,而在于我的FloatBuffer的内部位置。在for(0 < I < 9)循环之后,我没有将变量vertex_buffer的位置设置为0。将缓冲区的位置设置为0可以使用至少两个命令完成:

  • vertex_buffer.rewind()
  • vertex_buffer.rewind()
  • vertex_buffer.position(0)
  • vertex_buffer.position(0)

To my knowledge they do the same thing. I quickly tested where in the code the position reset belongs and in my example code I could call it after gl.glEnableClientState(GL10.GL_VERTEX_ARRAY), however I had to call it before gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertex_buffer), otherwise the initial problem returned.

据我所知,他们也做同样的事。我在代码中快速测试了位置重置属于何处,在示例代码中,我可以在gl.glEnableClientState(GL10.GL_VERTEX_ARRAY)之后调用它,但是我必须在gl.glVertexPointer(3, GL10)之前调用它。GL_FLOAT, 0, vertex_buffer),否则初始问题返回。

I hope this helps other people with similar issues or maybe is just a short of glulookat and gluperspective ;)

我希望这能帮助其他有类似问题的人,或者可能只是一个不太好的glulookat和gluperspective;

Thanks again for your suggestions!

再次感谢您的建议!

#1


5  

I've only ever used OpenGL on PC, Mac and iOS, but from what I can tell, the code looks fine. Then again, mine always does, too, but I still get the empty screen for a while, pretty much any time I start on anything 3D from scratch (regardless of API)... so here are some things to try, pretty much in the order in which to try them. Hopefully at least one of them will be something you haven't tried yet!

我只在PC、Mac和iOS上使用过OpenGL,但从我的经验来看,代码看起来还不错。同样,我的也总是这样,但是我仍然有一段时间是空的屏幕,几乎任何时候我都可以从头开始使用3D(不管API是什么)……这里有一些可以尝试的东西,基本上是按照尝试的顺序来做的。希望至少有一个是你还没有尝试过的东西!

  • Add in a glFlush at the end, because you're not actually drawing all that much. You'd think the driver would do this for you when you do the buffer swap, but it seems that there's no guarantees of that -- Mac OS X doesn't always seem to, for example.
  • 最后添加一个glFlush,因为你实际上并没有画那么多。当你进行缓冲区交换时,你可能会认为驱动程序会为你做这些,但似乎并不能保证这一点——例如,Mac OS X似乎并不总是这样。
  • Set background to non-black. If something is drawing in black, you want to see it.
  • 背景设置为黑色。如果有什么东西在画黑色,你想看到它。
  • Disable GL_LIGHTING. If this is enabled (which I think it is by default?) but you're not supplying normals, everything will come out black. (See above.)
  • 禁用GL_LIGHTING。如果这是启用的(我认为它是默认的吗?)但是你没有提供法线,那么所有的东西都会变成黑色。(见上图)。
  • Disable GL_CULL_FACE. It doesn't matter how carefully you think about the winding order, there's still a possibility you might have got it wrong. But if GL_CULL_FACE is off, that becomes impossible.
  • 禁用GL_CULL_FACE。不管你怎么仔细地考虑缠绕顺序,还是有可能你弄错了。但是如果GL_CULL_FACE关闭,那就不可能了。
  • Disable GL_DEPTH_TEST. This has saved me a couple of times, when I've typed glClearDepth(0) by accident. Looks like you're OK in that respect, but it's still worth a go.
  • 禁用GL_DEPTH_TEST。当我不小心输入了glClearDepth(0)时,这为我节省了几次时间。在这方面你看起来还不错,但还是值得一试。
  • Check glGetError religiously, after EVERY API call, just in case. (assert(glGetError()==GL_NO_ERROR) will do for starters, but you really want to have a little loop that also prints the result of gluErrorString so that it's easier to see at a glance what might be wrong.)
  • 虔诚地检查glGetError,在每次API调用之后,以防万一。(assert(glGetError()==GL_NO_ERROR)对初学者来说是可行的,但您确实希望有一个小循环,该循环也打印gluErrorString的结果,以便更容易一眼就看出哪里出错了。)
  • Make sure you do a glBindBuffer to set your ARRAY_BUFFER and ARRAY_ELEMENT_BUFFER bindings to 0. To initialize a VBO, you have to bind it, so if you've got something somewhere that sets one up it might just leave it bound. This will stuff up your glVertexPointer.
  • 确保使用glBindBuffer将ARRAY_BUFFER和ARRAY_ELEMENT_BUFFER绑定设置为0。要初始化一个VBO,你必须绑定它,所以如果你在某个地方设置了一个,它可能会保留它的绑定。这将填充glVertexPointer。
  • Along the lines of the last few - set up more state explicitly. In this case, for example, you might want to glDisableClientState the other array types, just in case. GL starts up with vertex arrays disabled, according to the docs, but it's a possibility worth eliminating.
  • 沿着最后几行,显式地设置了更多的状态。例如,在本例中,您可能希望glDisableClientState其他数组类型,以防万一。根据文档,GL一开始是禁用顶点数组的,但是它是值得消除的。

#2


2  

I found the answer after looking at further tutorials (and then also noticed it in the ones I used before)! Thank all of you for your answers, they were very helpful in diagnosing OpenGL problems in general and will for sure help me in the future!

我在看了更多的教程后找到了答案(然后在我以前使用的教程中也注意到了)!谢谢大家的回答,它们对诊断OpenGL问题很有帮助,将来肯定会对我有帮助!

The solution to my problem is... that the problem is not glulookat or gluperspective, but in my case the internal position of the FloatBuffer. I did not set the position of variable vertex_buffer to 0 after the for(0 < i < 9) loop. Setting the buffer's position to 0 can be accomplished with at least two commands:

我的问题的解决办法是……问题不在于glulookat或gluperspective,而在于我的FloatBuffer的内部位置。在for(0 < I < 9)循环之后,我没有将变量vertex_buffer的位置设置为0。将缓冲区的位置设置为0可以使用至少两个命令完成:

  • vertex_buffer.rewind()
  • vertex_buffer.rewind()
  • vertex_buffer.position(0)
  • vertex_buffer.position(0)

To my knowledge they do the same thing. I quickly tested where in the code the position reset belongs and in my example code I could call it after gl.glEnableClientState(GL10.GL_VERTEX_ARRAY), however I had to call it before gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertex_buffer), otherwise the initial problem returned.

据我所知,他们也做同样的事。我在代码中快速测试了位置重置属于何处,在示例代码中,我可以在gl.glEnableClientState(GL10.GL_VERTEX_ARRAY)之后调用它,但是我必须在gl.glVertexPointer(3, GL10)之前调用它。GL_FLOAT, 0, vertex_buffer),否则初始问题返回。

I hope this helps other people with similar issues or maybe is just a short of glulookat and gluperspective ;)

我希望这能帮助其他有类似问题的人,或者可能只是一个不太好的glulookat和gluperspective;

Thanks again for your suggestions!

再次感谢您的建议!