我遇到的问题是每个面的一个顶点的阴影总是与其他顶点不同(当其他人亮时它是暗的,而当其他人变暗时它是亮的)。我怀疑法线没有被正确计算,但我画了它们并且它们都指向垂直于表面的向外指向,因为它们在每个顶点照明中应该是这样的(或者我在那个假设中是错误的)。
这是我绘制一个简单的四面金字塔的代码:
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)的单个表面时,效果很好。只有当我添加更多具有不同法线的面时,我才会遇到这个问题。