سؤال

The problem I encountered is one vertex per face always being shaded differently than the others (it is dark when others are lit and lit when others are dark). I suspected normals not being computed correctly, but I drew them and all of them are pointing outward perpendicular to the surface as they are supposed to in per-vertex lighting (or am I wrong in that assumption).

Here is my code for drawing a simple four sided pyramid:

    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);
        }
    }

I can´t see what it is I am doing wrong.

One more thing. When I use a single surface with normals pointing on the positive z axis (0f, 0f, 1f) it works great. It´s only when I add more faces with different normals that I get this problem.

هل كانت مفيدة؟

المحلول

You do not correctly specify the normals right. The following code is not correct:

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

The GL is a state machine.By glNormal3 you will set the current normal vector. A Vertex is generated by the glVertex call. It will use all the attributes of the current state. So you have to specify all the attributes (Normals,Colors,TexCoords,...) before you call glVertex. In your case, you just end up mixing the normals between two consecutive primitives.

It did seem to work with a single primitive, as you probably work with a render loop. In the first iteration, the normal of the first vertex was left at the GL's default, but with all following iterations, the last one you had set was used, so it looked OK.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top