这个问题有2个原因。
第一个确实是一个Z-战斗 https://en.wikipedia.org/wiki/Z-fighting问题是由近平面和远平面之间的巨大距离引起的
gl.Perspective(30, 1, 0.1F, 1.0E+7F);
事实上,在透视投影中,深度不是线性的。也可以看看如何线性渲染深度... https://stackoverflow.com/questions/7777913/how-to-render-depth-linearly-in-modern-opengl-with-gl-fragcoord-z-in-fragment-sh/45710371#45710371.
这可以通过将近平面尽可能靠近几何体来改进。由于到物体的距离为 3000.0 并且球体的半径为 300,因此近平面必须小于 2700.0:
e.g.
gl.Perspective(30, 1, 2690.0F, 5000.0F);
第二个问题是由球体由三角形基元组成的事实引起的。正如您在答案中所建议的,您可以通过增加基元的数量来改进这一点。
我将通过使用剪切平面提供替代解决方案。夹住底部的红色球体和顶部的蓝色球体。正好在球体相交的平面上,以便从每个球体上切掉一个盖子。
剪裁平面可以通过以下方式设置glClipPlane https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glClipPlane.xml并通过以下方式启用glEnable
.
剪裁平面的参数被解释为平面方程 http://www.songho.ca/math/plane/plane.html。
平面方程的前 3 个分量是剪切平面的法向量。第四个分量是到原点的距离。
所以红色球体的剪切平面方程必须是{0, 0, -1, 50}
对于蓝色球体{0, 0, 1, -50}
.
注意,当glClipPlane
被调用,然后通过模型视图矩阵的逆来变换方程。因此,必须在模型转换(如旋转、平移和缩放)之前设置裁剪平面。
e.g.
private void Render(int angle)
{
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT | OpenGL.GL_STENCIL_BUFFER_BIT);
double[] plane1 = new double[] {0, 0, -1, 50};
RenderSphere(gl, 0, 0, 0, 0, 300, Color.Red, plane1);
double[] plane2 = new double[] {0, 0, 1, -50};
RenderSphere(gl, 0, 0, 100, angle, 300, Color.Blue, plane2);
gl.Blit(hdc);
}
private void RenderSphere(
OpenGL gl, int x, int y, int z, int angle, int radius,
Color col, double[] plane)
{
IntPtr obj = gl.NewQuadric();
gl.ClipPlane(OpenGL.GL_CLIP_PLANE0, plane);
gl.Enable(OpenGL.GL_CLIP_PLANE0);
gl.PushMatrix();
gl.Translate(x, y, z);
gl.Rotate(angle, 0, 0);
gl.Color(new float[] { col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f });
gl.QuadricDrawStyle(obj, OpenGL.GLU_FILL);
gl.Sphere(obj, radius, 20, 10);
gl.Color(new float[] { 0, 0, 0, 1 });
gl.QuadricDrawStyle(obj, OpenGL.GLU_SILHOUETTE);
gl.Sphere(obj, radius, 20, 10);
gl.DeleteQuadric(obj);
gl.PopMatrix();
gl.Disable(OpenGL.GL_CLIP_PLANE0);
}