0

背景

我正在尝试制作一个 CAD 查看器,我可以将 STL 文件带入其中并简单地旋转、平移等。这不应该像游戏那样先进。

我在照明方面遇到了困难,这可以在以前的帖子中看到: 以前的帖子

问题

基本上我现在已经亮了,我在正确的地方有我的弹出和推送矩阵调用。我现在要做的就是优化我的照明,使其类似于 CAD 环境。如果我错了,请纠正我,但我相信观看零件的最佳照明总是让相机上的光指向物体的方向。如果这不是进行照明的最佳方式,请随时提出更好的方式。

我认为这主要归结为数学。我不知道是否有任何内置函数可以简单地获取相机的位置,或者您是否必须跟踪它。

这是我的显示功能:

Private Sub display()

    Gl.glEnable(Gl.GL_DEPTH_TEST)
    Gl.glClear(Gl.GL_COLOR_BUFFER_BIT)
     Gl.glClear(Gl.GL_DEPTH_BUFFER_BIT)


    Gl.glPushMatrix()

    Gl.glRotatef(rotX, 1.0F, 0.0F, 0.0F)
    ' Rotate on x
    Gl.glRotatef(rotY, 0.0F, 1.0F, 0.0F)
    ' Rotate on y
    Gl.glRotatef(rotZ, 0.0F, 0.0F, 1.0F)
    ' Rotate on z
    Gl.glTranslatef(X, Y, Z)



    'Draw x,y,z axis 
    Gl.glBegin(Gl.GL_LINES)
    Gl.glColor4f(0.0F, 1.0F, 0.0F, 1.0F)

    ' Green for x axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(5000.0F, 0.0F, 0.0F)
    Gl.glColor3f(1.0F, 0.0F, 0.0F)
    ' Red for y axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, 5000.0F, 0.0F)
    Gl.glColor3f(0.0F, 0.0F, 1.0F)
    ' Blue for z axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, 0.0F, 15.0F)
    Gl.glEnd()

    ' Dotted lines for the negative sides of x,y,z
    Gl.glEnable(Gl.GL_LINE_STIPPLE)
    ' Enable line stipple to
    ' use a dotted pattern for
    ' the lines
    Gl.glLineStipple(1, &H101)
    ' Dotted stipple pattern for
    ' the lines
    Gl.glBegin(Gl.GL_LINES)
    Gl.glColor3f(0.0F, 1.0F, 0.0F)
    ' Green for x axis
    Gl.glVertex3f(-5000.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glColor3f(1.0F, 0.0F, 0.0F)
    ' Red for y axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, -5000.0F, 0.0F)
    Gl.glColor3f(0.0F, 0.0F, 1.0F)
    ' Blue for z axis
    Gl.glVertex3f(0.0F, 0.0F, 0.0F)
    Gl.glVertex3f(0.0F, 0.0F, -5000.0F)
    Gl.glEnd()

    Gl.glDisable(Gl.GL_LINE_STIPPLE)

    ' Disable the line stipple

    Gl.glColor3f(1.0F, 1.0F, 1.0F)
    Glut.glutSolidTeapot(5)


    Gl.glEnable(Gl.GL_LIGHTING)

    Label1.Text = "X=" & lighting_x & ", Y=" & lighting_y & " Z=" & lighting_z
    Light1Position = {lighting_x, lighting_y, lighting_z, 0.0F}

    ' Enable Default Light
    Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_AMBIENT, Light1Ambient)
    Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_DIFFUSE, Light1Diffuse)
    Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION, Light1Position)
    Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_SPECULAR, Light1Specular)
    Gl.glEnable(Gl.GL_LIGHT1)

    Gl.glPopMatrix()

    draw_extras()

    Gl.glEnable(Gl.GL_COLOR_MATERIAL)
    Gl.glColorMaterial(Gl.GL_FRONT, Gl.GL_AMBIENT_AND_DIFFUSE)
    Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_SPECULAR, MaterialSpecular)
    Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_SHININESS, SurfaceShininess)

    Gl.glEnable(Gl.GL_COLOR_MATERIAL)
    Glut.glutSwapBuffers()
End Sub

基本上我有 lighting_x、lighting_y 和 lighting_z 作为变量来移动我的光。我有一个变量 X、Y 和 Z 来建立平移 (Gl.glTranslatef(X, Y, Z))。变量 rotx、roty 和 rotz 使用 Gl.glRotatef(rotX, 1.0F, 0.0F, 0.0F) 在主函数中设置旋转。

这些变量被应用于整个场景,这在 CAD 环境中是有意义的,因此我的轴也会移动。

最重要的是,我正在使用 gluLookAt 函数来创建“缩放以适应”函数。据我了解,我的显示功能中的功能移动和旋转我的环境,但 gluLookAt 正在移动我的相机。保持这些之间的关系必须是我的照明计算所需要的:

Private Sub zoom_fit()
    rotX = 0
    rotY = 0
    rotZ = 0
    rotLx = 0
    rotLy = 0
    rotLz = 0


    Dim i As Integer = 1
    Dim maxz As Decimal = -10000

    Do Until i >= ListView1.Items.Count
        If Convert.ToDecimal(ListView1.Items.Item(i).SubItems(2).Text) > maxz Then
            maxz = Convert.ToDecimal(ListView1.Items.Item(i).SubItems(2).Text)
        End If
        If Convert.ToDecimal(ListView1.Items.Item(i + 1).SubItems(2).Text) > maxz Then
            maxz = Convert.ToDecimal(ListView1.Items.Item(i).SubItems(2).Text)
        End If
        If Convert.ToDecimal(ListView1.Items.Item(i + 2).SubItems(2).Text) > maxz Then
            maxz = Convert.ToDecimal(ListView1.Items.Item(i).SubItems(2).Text)
        End If
        i = i + 4
    Loop




    rotLz = Convert.ToSingle((maxz - avgz) * 10)

    Gl.glMatrixMode(Gl.GL_MODELVIEW)
    Gl.glLoadIdentity()
    Glu.gluLookAt(rotLx, rotLy, 15.0 + rotLz, 0.0, 0.0, 0.0, _
        0.0, 1.0, 0.0)


    Glut.glutPostRedisplay()
End Sub

我不知道环境在最初运行时将相机相对于原点放置在哪里,但我认为这也需要考虑在内。

到目前为止我能看到的:

茶壶的光面:

在此处输入图像描述

月之暗面(茶壶):

在此处输入图像描述

所有代码都是用 VB.NET 编写的,但 C# 答案也可以。

4

1 回答 1

2

代码看起来有点粗糙,我不会评论您可能需要修复的每个细节。但这里有一些重要的方面有望帮助您启动并运行:

  • 所有状态都需要在绘制调用之前设置。换句话说,每个绘图调用都使用调用时的确切状态。例如,您在display()函数结束时设置了一些材质属性,在所有绘制调用都已经完成之后。在下一次绘图调用之前,这些状态更改不会影响任何内容。

  • 指定灯光位置时,需要注意当前的变换。从规范:

    当指定位置时,当前模型视图矩阵应用于特定光源的 Light 指示的位置参数。

    因此,如果您想要一个相对于相机静止的光源,您需要glLightfv(.., GL_POSITION, ..)在矩阵堆栈上没有模型转换时进行调用。

我不认为将光准确地放在相机位置是很常见的。对于 CAD 类型的系统,我看到最多的是位于左上方的光源。或者换句话说,光源被放置为相对于相机位置具有负的 x 偏移和正的 y 偏移。为了获得更好的结果,使用一种以上的光源可能是有益的。例如,在物体后面的相反方向放置一个(可能较弱的)光源看起来非常好。但是您必须使用它来查看最适合您的方法。

此外,即使您可能已经知道这一点,但我必须添加(几乎)强制性:您使用的大多数 OpenGL 功能都已过时且已弃用。如果您正在学习,我强烈建议您学习“现代 OpenGL”,这意味着不再使用固定管道并且基于可编程着色器的版本。

于 2015-08-19T15:22:46.033 回答