为什么一个顶点的着色与其他顶点不同

本文关键字:顶点 其他 一个 为什么 | 更新日期: 2023-09-27 18:22:11

我遇到的问题是,每个面的一个顶点的着色总是与其他顶点不同(其他顶点亮时是暗的,其他顶点暗时是亮的)。我怀疑法线的计算不正确,但我画了它们,所有的法线都指向垂直于曲面的外部,就像在逐顶点照明中应该指向的那样(或者我的假设错了吗)。

以下是我绘制一个简单四边形金字塔的代码:

    static float anglea = 0f;
    /// <summary>Creates a 800x600 window with the specified title.</summary>
    public Program() : base(800, 600, GraphicsMode.Default, "OpenTK Quick Start Sample")
    {
        VSync = VSyncMode.On;
    }
    /// <summary>Load resources here.</summary>
    /// <param name="e">Not used.</param>
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        GL.ClearColor(0.1f, 0.2f, 0.5f, 0.0f);
        GL.Enable(EnableCap.DepthTest);
        GL.Enable(EnableCap.Lighting);
        GL.Enable(EnableCap.Light0);
        GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Ambient, new float[] { 0f, 0f, 0f, 0f });
        GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Diffuse, new float[] { 0.2f, 0.7f, 0.2f, 0f });
        GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Specular, new float[] { 0.2f, 0.7f, 0.2f, 0f });
        GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Shininess, 100f);
        GL.Light(LightName.Light0, LightParameter.Ambient, new float[] { 0f, 0f, 0f, 0f });
        GL.Light(LightName.Light0, LightParameter.Diffuse, new float[] { 1f, 1f, 1f, 0f });
        GL.Light(LightName.Light0, LightParameter.Specular, new float[] { 0.2f, 0.7f, 0.2f, 0f });
    }
    /// <summary>
    /// Called when your window is resized. Set your viewport here. It is also
    /// a good place to set up your projection matrix (which probably changes
    /// along when the aspect ratio of your window).
    /// </summary>
    /// <param name="e">Not used.</param>
    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
        Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f);
        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadMatrix(ref projection);
    }
    /// <summary>
    /// Called when it is time to setup the next frame. Add you game logic here.
    /// </summary>
    /// <param name="e">Contains timing information for framerate independent logic.</param>
    protected override void OnUpdateFrame(FrameEventArgs e)
    {
        base.OnUpdateFrame(e);
        if (Keyboard[Key.Escape])
            Exit();
        if (Keyboard[Key.Left])
            anglea -= 1.5f;
        if (Keyboard[Key.Right])
            anglea += 1.5f;
    }
    /// <summary>
    /// Called when it is time to render the next frame. Add your rendering code here.
    /// </summary>
    /// <param name="e">Contains timing information.</param>
    protected override void OnRenderFrame(FrameEventArgs e)
    {
        base.OnRenderFrame(e);
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        //Matrix4 modelview = Matrix4.LookAt(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);
        Matrix4 modelview = Matrix4.LookAt(0f, 0f, 8f, 0f, 0f, 0f, 0f, 1f, 0f);
        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadMatrix(ref modelview);
        GL.Light(LightName.Light0, LightParameter.Position, new float[] { 0f, 0f, 1f, 0f });
        GL.Rotate(anglea, -Vector3.UnitY);
        Vector3 a, b, c, n;
        List<Vector3> tocke = new List<Vector3>();
        List<Vector3> normale = new List<Vector3>();
        //front face
        GL.Begin(BeginMode.Triangles);
        a = new Vector3(-1.0f, -1.0f, 1.0f);
        b = new Vector3(1.0f, -1.0f, 1.0f);
        c = new Vector3(0.0f, 1.0f, 0.0f);
        n = Vector3.Cross(new Vector3(a) - new Vector3(b), new Vector3(b) - new Vector3(c));
        n.Normalize();
        tocke.Add(a);
        tocke.Add(b);
        tocke.Add(c);
        normale.Add(n);
        normale.Add(n);
        normale.Add(n);
        GL.Vertex3(a);
        GL.Normal3(n);
        GL.Vertex3(b);
        GL.Normal3(n);
        GL.Vertex3(c);
        GL.Normal3(n);
        GL.End();
        //left face
        GL.Begin(BeginMode.Triangles);
        a = new Vector3(-1.0f, -1.0f, -1.0f);
        b = new Vector3(-1.0f, -1.0f, 1.0f);
        c = new Vector3(0.0f, 1.0f, 0.0f);
        n = Vector3.Cross(new Vector3(a) - new Vector3(b), new Vector3(b) - new Vector3(c));
        n.Normalize();
        tocke.Add(a);
        tocke.Add(b);
        tocke.Add(c);
        normale.Add(n);
        normale.Add(n);
        normale.Add(n);
        GL.Vertex3(a);
        GL.Normal3(n);
        GL.Vertex3(b);
        GL.Normal3(n);
        GL.Vertex3(c);
        GL.Normal3(n);
        GL.End();
        //back face
        GL.Begin(BeginMode.Triangles);
        a = new Vector3(1.0f, -1.0f, -1.0f);
        b = new Vector3(-1.0f, -1.0f, -1.0f);
        c = new Vector3(0.0f, 1.0f, 0.0f);
        n = Vector3.Cross(new Vector3(a) - new Vector3(b), new Vector3(b) - new Vector3(c));
        n.Normalize();
        tocke.Add(a);
        tocke.Add(b);
        tocke.Add(c);
        normale.Add(n);
        normale.Add(n);
        normale.Add(n);
        GL.Vertex3(a);
        GL.Normal3(n);
        GL.Vertex3(b);
        GL.Normal3(n);
        GL.Vertex3(c);
        GL.Normal3(n);
        GL.End();
        //right face
        GL.Begin(BeginMode.Triangles);
        a = new Vector3(1.0f, -1.0f, 1.0f);
        b = new Vector3(1.0f, -1.0f, -1.0f);
        c = new Vector3(0.0f, 1.0f, 0.0f);
        n = Vector3.Cross(new Vector3(a) - new Vector3(b), new Vector3(b) - new Vector3(c));
        n.Normalize();
        tocke.Add(a);
        tocke.Add(b);
        tocke.Add(c);
        normale.Add(n);
        normale.Add(n);
        normale.Add(n);
        GL.Vertex3(a);
        GL.Normal3(n);
        GL.Vertex3(b);
        GL.Normal3(n);
        GL.Vertex3(c);
        GL.Normal3(n);
        GL.End();
        //Drawing normals
        for (int i = 0; i < tocke.Count; i++)
        {
            GL.Begin(BeginMode.Lines);
            GL.Vertex3(tocke[i]);
            GL.Vertex3(tocke[i] + normale[i]);
            GL.End();
        }
        SwapBuffers();
    }
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        // The 'using' idiom guarantees proper resource cleanup.
        // We request 30 UpdateFrame events per second, and unlimited
        // RenderFrame events (as fast as the computer can handle).
        using (Program game = new Program())
        {
            game.Run(30.0);
        }
    }

我看不出我做错了什么。

还有一件事。当我使用法线指向正z轴(0f,0f,1f)的单个曲面时,效果非常好。只有当我添加更多具有不同法线的面时,我才会遇到这个问题。

为什么一个顶点的着色与其他顶点不同

您没有正确指定法线。以下代码不正确:

    GL.Vertex3(a);
    GL.Normal3(n);
    GL.Vertex3(b);
    GL.Normal3(n);
    GL.Vertex3(c);
    GL.Normal3(n);

GL是一个状态机。通过glNormal3,您将设置当前法线向量。顶点由glVertex调用生成。它将使用当前状态的所有属性。因此,在调用glVertex之前,必须指定所有属性(法线、颜色、TexCourds…)。在您的情况下,您最终只是混合了两个连续基本体之间的法线。

它似乎确实适用于单个基本体,就像您可能使用渲染循环一样。在第一次迭代中,第一个顶点的法线保留在GL的默认值,但在接下来的所有迭代中,都使用了您设置的最后一个,所以看起来还可以。