opengl - OpenGL重叠丑陋渲染
问题描述
我正在尝试使用 OpenGL 2.1 渲染场景,但重叠形状的边界很奇怪。我测试了一些 OpenGL 初始化,但没有任何变化。我将问题简化为具有相同结果的 2 个球体的简单测试应用程序。
我尝试了一些关于 Gl_DEPTH_TEST 的事情,启用/禁用平滑但没有成功。
这是我使用 2 gluSphere 的结果:
当一条线足以分开蓝色和红色的脸时,我们可以看到某种混叠......
我使用SharpGL,但我认为它并不重要(因为我只将它用作 OpenGL 包装器)。这是我最简单的代码来呈现相同的东西(您可以将其复制到表单中进行测试):
OpenGL gl;
IntPtr hdc;
int cpt;
private void Init()
{
cpt = 0;
hdc = this.Handle;
gl = new OpenGL();
gl.Create(SharpGL.Version.OpenGLVersion.OpenGL2_1, RenderContextType.NativeWindow, 500, 500, 32, hdc);
gl.Enable(OpenGL.GL_DEPTH_TEST);
gl.DepthFunc(OpenGL.GL_LEQUAL);
gl.ClearColor(1.0F, 1.0F, 1.0F, 0);
gl.ClearDepth(1);
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.Perspective(30, 1, 0.1F, 1.0E+7F);
gl.MatrixMode(OpenGL.GL_MODELVIEW);
gl.LookAt(0, 3000, 0, 0, 0, 0, 0, 0, 1);
}
private void Render(int angle)
{
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT | OpenGL.GL_STENCIL_BUFFER_BIT);
RenderSphere(gl, 0, 0, 0, 0, 300, Color.Red);
RenderSphere(gl, 0, 0, 100, angle, 300, Color.Blue);
gl.Blit(hdc);
}
private void RenderSphere(OpenGL gl, int x, int y, int z, int angle, int radius, Color col)
{
IntPtr obj = gl.NewQuadric();
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.Enable(OpenGL.GL_LINE_SMOOTH);
gl.Enable(OpenGL.GL_POLYGON_SMOOTH);
gl.ShadeModel(OpenGL.GL_SMOOTH);
gl.Hint(OpenGL.GL_LINE_SMOOTH_HINT, OpenGL.GL_NICEST);
gl.Hint(OpenGL.GL_POLYGON_SMOOTH_HINT, OpenGL.GL_NICEST);
gl.Hint(OpenGL.GL_PERSPECTIVE_CORRECTION_HINT, OpenGL.GL_NICEST);
EDIT2:有更多的面孔,有和没有线条的图像
它是......不同......但并不令人愉快。
解决方案
这个问题有两个原因。
第一个确实是Z-fighting问题,这是由近平面和远平面之间的巨大距离引起的
gl.Perspective(30, 1, 0.1F, 1.0E+7F);
以及在透视投影中,深度不是线性的事实。另请参阅如何线性渲染深度...。
这可以通过将近平面尽可能靠近几何体来改善。由于到对象的距离为 3000.0,球体的半径为 300,因此近平面必须小于 2700.0:
例如
gl.Perspective(30, 1, 2690.0F, 5000.0F);
第二个问题是由球体由三角形基元组成的事实引起的。正如您在回答中所建议的那样,您可以通过增加基元的数量来改进它。
我将提供另一种解决方案,即使用剪切平面。夹住底部的红色球体和顶部的蓝色球体。正好在球体相交的平面上,因此每个球体上都有一个盖子。
剪切平面可以通过 设置glClipPlane
和启用glEnable
。
剪裁平面的参数被解释为平面方程。平面方程的前 3 个分量是剪切平面的法向量。第 4 个分量是到原点的距离。
所以红色球体的剪裁平面方程必须是{0, 0, -1, 50}
和蓝色球体{0, 0, 1, -50}
。
注意,当glClipPlane
被调用时,方程会被模型视图矩阵的逆转换。因此,必须在模型转换(如旋转、平移和缩放)之前设置裁剪平面。
例如
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);
}
推荐阅读
- graphql - graphql-tools mergeSchemas 和 makeExecutableSchema 之间的区别
- c# - Dapper 没有反序列化 nvarchar 类型
- r - 在ggplot中绘制具有伽马分布的模型
- video-streaming - 用于直播的媒体服务器
- database - 是否可以在单个更新查询中更新多个列
- javascript - 如何使用 Javascript 更改 chrome 浏览器标签的颜色?
- java - 如何通过意图访问通知可访问性页面?
- php - 添加到带有 id 的链接
- makefile - 如何使用 Makefile 将多个 C 源文件编译为目标文件
- excel - 跨度 id 值没有用 excel VBA 刮掉