NightmareX2000's picture

Can't get lighting to work with Vbo?

There is a weird issue I'm encountering:
I got lighting working with immediate mode but somehow those shapes drawn using VBOs are not lit.
I even tried calculating normals reversed.
It's clear in the picture that the little body is shining and the other is not, and the only difference between them is big body is drawn via VBOs.
nolit

Here is what I got:

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			GL.ClearColor(Color4.CornflowerBlue);
			GL.Disable(EnableCap.CullFace);
			GL.Enable(EnableCap.DepthTest);
			GL.Enable(EnableCap.Texture2D);
			GL.Enable(EnableCap.Blend);
			GL.Enable(EnableCap.AlphaTest);
			GL.Enable(EnableCap.ColorMaterial);
			GL.Enable(EnableCap.IndexArray);
			GL.EnableClientState(ArrayCap.TextureCoordArray);
			GL.EnableClientState(ArrayCap.NormalArray);
			GL.EnableClientState(ArrayCap.VertexArray);
			GL.EnableClientState(ArrayCap.ColorArray);
			GL.Enable(EnableCap.TextureCoordArray);
			GL.Enable(EnableCap.NormalArray);
			GL.Enable(EnableCap.VertexArray);
			GL.Enable(EnableCap.ColorArray);
			GL.Enable(EnableCap.Lighting);
			GL.Enable(EnableCap.Light0);
			GL.Enable(EnableCap.PolygonSmooth);
			GL.Enable(EnableCap.LineSmooth);
			GL.Enable(EnableCap.PointSmooth);
			GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
			GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
			GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
			GL.Hint(HintTarget.PolygonSmoothHint, HintMode.Nicest);
			GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
			GL.Hint(HintTarget.PointSmoothHint, HintMode.Nicest);
 
			float[] mat_specular = { 1f, 1f, 1f, 1f };
			float[] mat_shininess = { 50f };
			float[] light_position = { 10f, 10f, 10f, 0f };
			float[] light_ambient = { 0.5f, 0.5f, 0.5f, 1f };
 
			GL.ShadeModel(ShadingModel.Smooth);
 
			GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Specular, mat_specular);
			GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Shininess, mat_shininess);
			GL.Light(LightName.Light0, LightParameter.Position, light_position);
			GL.Light(LightName.Light0, LightParameter.Ambient, light_ambient);
			GL.Light(LightName.Light0, LightParameter.Diffuse, mat_specular);
 
			(qFont = new QFont(new Font("Courier New", 9.75f))).Options.Monospacing = QFontMonospacing.Yes;
 
			GameData.Load();
			match = new DeathMatch(GameData.CharDatas[0], GameData.CharDatas, this);
 
			ticker.Elapsed += ticker_Elapsed; // it has something to doo with frame counter (fps calculater)
			ticker.Start();
		}
 
		protected override void OnResize(EventArgs e)
		{
			base.OnResize(e);
 
			GL.Viewport(ClientRectangle);
 
			Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, this.Width / (float)this.Height, 1f, 128f);
			GL.MatrixMode(MatrixMode.Projection);
			GL.LoadMatrix(ref projection);
			Matrix4 modelview = Matrix4.LookAt(new Vector3(10, 10, 10), Vector3.UnitZ * 5, Vector3.UnitZ);
			GL.MatrixMode(MatrixMode.Modelview);
			GL.LoadMatrix(ref modelview);
		}
 
		float xrot, yrot, zrot;
		protected override void OnRenderFrame(FrameEventArgs e)
		{
			base.OnRenderFrame(e);
			if (frameCount >= (int)TargetRenderFrequency && TargetRenderFrequency > 0)
				return;
 
			GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
			GL.BindTexture(TextureTarget.Texture2D, 0);
			GL.PushMatrix();
			//GL.Rotate(xrot += 0.1f, Vector3.UnitX);
			//GL.Rotate(yrot += 0.2f, Vector3.UnitY);
			GL.Rotate(zrot += 0.9f, Vector3.UnitZ);
			foreach (MeshState mf in GameData.MeshFramers[0][0])
				GameData.MeshPacks[0][mf.MeshIndex].Draw(mf.Position, mf.Rotation, mf.Scale);   // the VBO-based shape
			GL.PopMatrix();
			GL.PushMatrix();
			GL.Translate(-Vector3.UnitY * 6);
			//GL.Rotate(90f, Vector3.UnitX);
			GL.Rotate(90f, Vector3.UnitY);
			GL.Rotate(90f, Vector3.UnitZ);
			GL.Scale(0.1f, 0.1f, 0.1f);
			MChar.Draw(0.1f);               // this shape is using immediate mode
			GL.PopMatrix();
 
			QFont.Begin();
			qFont.Print(string.Format("FPS: {0}\r\nUPS: {1}", fps, ups), new Vector2(10, 10));
			QFont.End();
 
			SwapBuffers();
 
			frameCount++;
		}

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
winterhell's picture

With VBO you need to bind all your vertex attributes you want to use, like Position, Texture Coordinates and Normals. It seems like you are only passing the positions. Watch your BindBuffer and VertexAttribPointers. In my case, using half floats, this is the code. You are most likely just using regular Floats and Vectors.

 
            GL.BindBuffer(BufferTarget.ArrayBuffer, pModel.positionHalfVboHandle);  
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.HalfFloat, false, Vector3h.SizeInBytes, 0);
            GL.BindBuffer(BufferTarget.ArrayBuffer, pModel.texcoordHalfVboHandle); 
            GL.VertexAttribPointer(1, 2, VertexAttribPointerType.HalfFloat, false, Vector2h.SizeInBytes, 0);
            GL.BindBuffer(BufferTarget.ArrayBuffer, pModel.normalHalfVboHandle);
            GL.VertexAttribPointer(2, 3, VertexAttribPointerType.HalfFloat, false, Vector3h.SizeInBytes, 0);

In this case you are using attrib arrays 0, 1 and 2, you'd need to enable them with

 
            GL.EnableVertexAttribArray(1);
            GL.EnableVertexAttribArray(2);
            GL.EnableVertexAttribArray(3);

At your end it might be only Positions and Normals.

NightmareX2000's picture

I don't think I'm missing normals or any attribute because you clearly see the red-blue colors of big body shape which also comes from vertex data...
That's the code I'm using to handle VBOs, either loading and drawing:

	public struct Vbo
	{
		public uint VboID, EboID;
		public int NumElements;
 
		public void Draw(Vector3 position, Vector3 rotation, Vector3 scale, PrimitiveType primitiveType = PrimitiveType.Triangles)
		{
			// To draw a VBO:
			// 1) Bind the vertex and element buffer handles.
			// 2) Set up the data pointers (vertex, normal, color) according to your vertex format.
			// 3) Call DrawElements. (Note: the last parameter is an offset into the element buffer
			//	and will usually be IntPtr.Zero).
			// These comments are obviously from a tutorial...
 
			GL.BindBuffer(BufferTarget.ArrayBuffer, VboID);
			GL.BindBuffer(BufferTarget.ElementArrayBuffer, EboID);
 
			GL.PushMatrix();
 
			GL.Translate(position);
			GL.Rotate(rotation.X, Vector3.UnitX);
			GL.Rotate(rotation.Y, Vector3.UnitY);
			GL.Rotate(rotation.Z, Vector3.UnitZ);
			GL.Scale(scale);
 
			int stride = BlittableValueType<Vertex>.Stride;
			GL.TexCoordPointer(2, TexCoordPointerType.Float, stride, IntPtr.Zero);
			GL.NormalPointer(NormalPointerType.Float, stride, 2 * sizeof(float));      // HEY! Look what I'm doin here!
			GL.VertexPointer(3, VertexPointerType.Float, stride, 5 * sizeof(float));
			GL.ColorPointer(3, ColorPointerType.UnsignedByte, stride, 8 * sizeof(float));
 
			GL.DrawElements(primitiveType, NumElements, DrawElementsType.UnsignedShort, IntPtr.Zero);
 
			GL.PopMatrix();
		}
	}
 
	[ProtoContract] // It makes it possible to load a mesh from a file with little effort
	public class Mesh
	{
		[ProtoMember(1)]
		public Vertex[] Vertices;
		[ProtoMember(2)]
		public ushort[] Elements;
		[ProtoMember(3)]
		public Vector3 Position = Vector3.Zero;
		[ProtoMember(4)]
		public Vector3 Rotation = Vector3.Zero;
		[ProtoMember(5)]
		public Vector3 Scale = Vector3.One;
 
		public Mesh() { }
 
		public Mesh(Vertex[] vertices, ushort[] elements)
		{
			Vertices = vertices;
			Elements = elements;
		}
 
		public Mesh(Vertex[] vertices, ushort[] elements, Vector3 position)
		{
			Vertices = vertices;
			Elements = elements;
			Position = position;
		}
 
		public Mesh(Vertex[] vertices, ushort[] elements, Vector3 position, Vector3 rotation)
		{
			Vertices = vertices;
			Elements = elements;
			Position = position;
			Rotation = rotation;
		}
 
		public Mesh(Vertex[] vertices, ushort[] elements, Vector3 position, Vector3 rotation, Vector3 scale)
		{
			Vertices = vertices;
			Elements = elements;
			Position = position;
			Rotation = rotation;
			Scale = scale;
		}
 
		public Vbo LoadVbo()
		{
			Vbo handle = new Vbo();
			int size;
 
			// To create a VBO:
			// 1) Generate the buffer handles for the vertex and element buffers.
			// 2) Bind the vertex buffer handle and upload your vertex data. Check that the buffer was uploaded correctly.
			// 3) Bind the element buffer handle and upload your element data. Check that the buffer was uploaded correctly.
			// These comments are obviously from a tutorial too...
 
			GL.GenBuffers(1, out handle.VboID);
			GL.BindBuffer(BufferTarget.ArrayBuffer, handle.VboID);
			GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(Vertices.Length * BlittableValueType.StrideOf(Vertices)), Vertices,
						  BufferUsageHint.StaticDraw);
			GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out size);
			if (Vertices.Length * BlittableValueType.StrideOf(Vertices) != size)
				throw new ApplicationException("Vertex data not uploaded correctly");
 
			GL.GenBuffers(1, out handle.EboID);
			GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle.EboID);
			GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(Elements.Length * sizeof(ushort)), Elements,
						  BufferUsageHint.StaticDraw);
			GL.GetBufferParameter(BufferTarget.ElementArrayBuffer, BufferParameterName.BufferSize, out size);
			if (Elements.Length * sizeof(ushort) != size)
				throw new ApplicationException("Element data not uploaded correctly");
 
			handle.NumElements = Elements.Length;
			return handle;
		}
	}

Also, puting GL.EnableVertexAttribArray(int); at OnLoad method crashes the program for a reason I have no clue while trying to draw VBO mesh (it simply crashes even in debug mode)

winterhell's picture

Oh, you are not drawing with AttribPointers but with all parameters in one VBO. Dont know about that case.

NightmareX2000's picture

I apologise if I wasted people's time to read these, I found the problem:
I am using Blender for modelling and wrote my own export scripts for it, which exports mesh data as json text. Guess what? Json.Net wasn't throwing any error as it reads "Normals" which does not exists in my Vertex struct. I corrected my scripts to write "Normal", and now everything looks as it should :)
All the Normal variables were initialized with Vector.Zero causing objects not to lit at all...