febriano's picture

3d model loader

does any one know any 3d model loader library that i can use for my game project ? is it possible any one knows a tutorial to make my own loader or game engine .Thanks for your time


Comments

Comment viewing options

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

I'm using this one:

http://codentronix.com/2011/10/07/5-cool-opengl-demos-in-vb-net/#more-63...

It's an md2 model loader written in .NET :)

Seven's picture

I have working obj parsing, loading, and rendering in my project. See "SevenEngine.com". Look at my StaticModelManager class. I do not support animation yet, but If you need a rigid body obj loader you should give it a look.

-Seven

febriano's picture

Hello thanks for the reply i found the md2 loader class but i cant use (don't know how to )the .vb class in the c# , any other loader would be appreciated too

OGI's picture

Both C# and VB .NET are very similar, it's easy to convert the code from VB to C# or vise versa, here I've done it for yourself. I didn't test it, so it might not work properly, but it should be something like this:

//The Q2MD2 model class(model loader):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
 
using System.Runtime.InteropServices;
using System.IO;
using System.Timers.Timer;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
 
public class Q2MD2Model
{
 
	[StructLayout(LayoutKind.Sequential)]
	public struct MD2Header
	{
		public int magicNumber;
		public int version;
		public int skinWidth;
		public int skinHeight;
		public int frameSize;
		public int numSkins;
		public int numVertices;
		public int numTexCoords;
		public int numTriangles;
		public int numGLCommands;
		public int numFrames;
		public int offsetSkins;
		public int offsetTexCoords;
		public int offsetTriangles;
		public int offsetFrames;
		public int offsetGLCommands;
		public int offsetEnd;
	}
 
	[StructLayout(LayoutKind.Sequential)]
	public struct MD2TexCoord
	{
		public short s;
		public short t;
	}
 
	[StructLayout(LayoutKind.Sequential)]
	public struct MD2Frame
	{
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.R4)]
		public float[] scale;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.R4)]
		public float[] translate;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
		public byte[] name;
	}
 
	[StructLayout(LayoutKind.Sequential)]
	public struct MD2Triangle
	{
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
		public short[] vertIndices;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
		public short[] texIndices;
	}
 
	[StructLayout(LayoutKind.Sequential)]
	public struct MD2Vertex
	{
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
		public byte[] vertices;
		public byte lightNormalIndex;
	}
 
	public struct Frame
	{
		public Vector3[] vertices;
		public string name;
	}
 
	public struct MD2Model
	{
		public Frame[] frames;
		public MD2TexCoord[] texCoords;
		public MD2Triangle[] triangles;
	}
 
	public const  MD2_MAGIC_NUMBER = 844121161;
 
	public const  MD2_VERSION = 8;
	protected string filename;
	protected string skinFileName;
	protected float scale;
	public MD2Header header;
	protected float[,] texCoords;
	protected MD2Triangle[] triangles;
	//Protected vertices() As Vector3
	protected int[] textures = new int[2];
 
	protected MD2Model model;
	protected long startFrame;
	protected long endFrame;
	protected long curFrame;
	protected long nextFrame;
	protected long timePerFrame;
 
	protected long lastTime;
	public Q2MD2Model(string modelFileName, string skinFileName, float scale)
	{
		this.filename = modelFileName;
		this.skinFileName = skinFileName;
		this.scale = scale;
		LoadModel();
		LoadTextures();
	}
 
	protected void BytesToStructure(byte[] bytes, ref ValueType t)
	{
		GCHandle gch = GCHandle.Alloc(bytes, GCHandleType.Pinned);
		t = Marshal.PtrToStructure(gch.AddrOfPinnedObject(), t.GetType());
		gch.Free();
	}
 
	protected void LoadModel()
	{
		FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
		BinaryReader br = new BinaryReader(fs);
		byte[] bytes = null;
 
		bytes = br.ReadBytes(Marshal.SizeOf(typeof(MD2Header)));
		BytesToStructure(bytes, ref header);
 
		if ((header.magicNumber != MD2_MAGIC_NUMBER) | (header.version != MD2_VERSION)) {
			throw new ArgumentException("Error: Invalid MD2 Model!");
		}
 
		texCoords = new float[header.numTexCoords + 1, 3];
		br.BaseStream.Seek(header.offsetTexCoords, SeekOrigin.Begin);
		for (i = 0; i <= header.numTexCoords - 1; i++) {
			MD2TexCoord stCoord = default(MD2TexCoord);
			bytes = br.ReadBytes(Marshal.SizeOf(typeof(MD2TexCoord)));
			BytesToStructure(bytes, ref stCoord);
			texCoords[i, 0] = stCoord.s / header.skinWidth;
			texCoords[i, 1] = stCoord.t / header.skinHeight;
		}
 
		triangles = new MD2Triangle[header.numTriangles + 1];
		br.BaseStream.Seek(header.offsetTriangles, SeekOrigin.Begin);
		for (i = 0; i <= header.numTriangles - 1; i++) {
			bytes = br.ReadBytes(Marshal.SizeOf(typeof(MD2Triangle)));
			BytesToStructure(bytes, ref triangles[i]);
		}
 
		model.frames = new Frame[header.numFrames + 1];
		br.BaseStream.Seek(header.offsetFrames, SeekOrigin.Begin);
		for (i = 0; i <= header.numFrames - 1; i++) {
			MD2Frame frame = new MD2Frame();
			model.frames[i].vertices = new Vector3[header.numVertices + 1];
 
			bytes = br.ReadBytes(Marshal.SizeOf(typeof(MD2Frame)));
			BytesToStructure(bytes, ref frame);
 
			//Console.WriteLine(Encoding.ASCII.GetString(frame.name))
 
			MD2Vertex vertex = default(MD2Vertex);
 
			for (j = 0; j <= header.numVertices - 1; j++) {
				bytes = br.ReadBytes(Marshal.SizeOf(typeof(MD2Vertex)));
				BytesToStructure(bytes, ref vertex);
				model.frames[i].vertices[j] = new Vector3(vertex.vertices[0] * frame.scale[0] + frame.translate[0], vertex.vertices[1] * frame.scale[1] + frame.translate[1], vertex.vertices[2] * frame.scale[2] + frame.translate[2]);
			}
		}
 
		SetAnimation(0, header.numFrames - 1, 100, 0);
		//SetAnimation(0, 39, 111, 0)
		//Console.ReadLine()
	}
 
	public void SetAnimation(long startFrame, long endFrame, long timePerFrame, long currentTime)
	{
		this.lastTime = currentTime;
		this.startFrame = startFrame;
		this.endFrame = endFrame;
		this.curFrame = startFrame;
		this.nextFrame = (endFrame > startFrame ? startFrame + 1 : startFrame);
		this.timePerFrame = timePerFrame;
	}
 
	protected void LoadTexture(int textureId, string filename)
	{
		Bitmap bmp = new Bitmap(filename);
 
		BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
		GL.BindTexture(TextureTarget.Texture2D, textureId);
		GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp.Width, bmp.Height, 0, OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
 
		bmp.UnlockBits(data);
 
		GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, TextureMinFilter.Linear);
		GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, TextureMagFilter.Linear);
	}
 
	protected void LoadTextures()
	{
		GL.GenTextures(textures.Length, textures);
		LoadTexture(textures[0], skinFileName);
	}
 
	private long delta;
	private float blend;
	public void Render(long time)
	{
		delta = time - lastTime;
 
		if (delta > timePerFrame) {
			lastTime = time;
			curFrame = nextFrame;
			nextFrame += 1;
			if (nextFrame > endFrame)
				nextFrame = startFrame;
		}
 
		blend = Convert.ToSingle(delta) / Convert.ToSingle(timePerFrame);
 
		Vector3[] vertices = new Vector3[header.numVertices + 1];
 
		for (i = 0; i <= header.numVertices - 1; i++) {
			vertices(i) = Vector3.Lerp(model.frames[curFrame].vertices[i], model.frames[nextFrame].vertices[i], blend) * scale;
		}
 
		GL.PushMatrix();
		GL.Rotate(-90, 1, 0, 0);
		GL.Rotate(-90, 0, 0, 1);
		//GL.Scale(0.2, 0.2, 0.2)
		//GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line)
 
		GL.BindTexture(TextureTarget.Texture2D, textures[0]);
 
		GL.Begin(BeginMode.Triangles);
		for (i = 0; i <= header.numTriangles - 1; i++) {
			GL.TexCoord2(texCoords[triangles[i].texIndices[0], 0], texCoords[triangles[i].texIndices[0], 1]);
			GL.Vertex3(vertices(triangles[i].vertIndices[0]).X, vertices(triangles[i].vertIndices[0]).Y, vertices(triangles[i].vertIndices[0]).Z);
			GL.TexCoord2(texCoords[triangles[i].texIndices[1], 0], texCoords[triangles[i].texIndices[1], 1]);
			GL.Vertex3(vertices(triangles[i].vertIndices[1]).X, vertices(triangles[i].vertIndices[1]).Y, vertices(triangles[i].vertIndices[1]).Z);
			GL.TexCoord2(texCoords[triangles[i].texIndices[2], 0], texCoords[triangles[i].texIndices[2], 1]);
			GL.Vertex3(vertices(triangles[i].vertIndices[2]).X, vertices(triangles[i].vertIndices[2]).Y, vertices(triangles[i].vertIndices[2]).Z);
		}
		GL.End();
		GL.PopMatrix();
	}
}

And here is the test class:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using System.Timers.Timer;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
 
public class MD2Test : GameWindow
{
 
	protected System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
	protected MD2Loader ogros;
	protected MD2Loader gunner_head;
	protected MD2Loader gunner_body;
	protected MD2Loader gunner_weapon;
	protected MD2Loader weapon;
	protected MD2Loader model;
 
	protected float yaw;
	public MD2Test() : base(480, 360, GraphicsMode.Default, "OpenGL MD2 Animation")
	{
		this.VSync = VSyncMode.Off;
	}
 
	protected override void OnLoad(System.EventArgs e)
	{
		base.OnLoad(e);
 
		GL.Enable(EnableCap.DepthTest);
		GL.ClearColor(0.2, 0.2, 0.3, 1.0);
		//GL.ClearColor(0.0, 0.0, 0.0, 1.0)
		GL.Enable(EnableCap.Texture2D);
 
		ogros = new MD2Loader("models\\ogros.md2", "models\\igdosh.png", 0.22);
		weapon = new MD2Loader("models\\weapon.md2", "models\\weapon.png", 0.22);
		model = new MD2Loader("models\\goblin.md2", "models\\goblin.jpg", 0.2);
 
		ogros.SetAnimation(0, 39, 100, 0);
		weapon.SetAnimation(0, 39, 100, 0);
 
		timer.Start();
	}
 
	protected override void OnResize(System.EventArgs e)
	{
		base.OnResize(e);
 
		float aspect = this.Width / Convert.ToSingle(this.Height);
		Matrix4 mat = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect, 0.1, 1000);
		GL.Viewport(0, 0, this.Width, this.Height);
		GL.MatrixMode(MatrixMode.Projection);
		GL.LoadMatrix(mat);
		GL.MatrixMode(MatrixMode.Modelview);
		GL.LoadIdentity();
	}
 
	protected override void OnRenderFrame(OpenTK.FrameEventArgs e)
	{
		base.OnRenderFrame(e);
 
		GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
		GL.MatrixMode(MatrixMode.Modelview);
		GL.LoadIdentity();
		GL.Translate(0, 0, -20);
		GL.Rotate(25, 1, 0, 0);
		GL.Rotate(yaw, 0, 1, 0);
 
		long time = timer.ElapsedMilliseconds;
 
		yaw += 0.05;
 
		GL.PushMatrix();
		GL.Translate(3, 0, 0);
		ogros.Render(time);
		weapon.Render(time);
		GL.PopMatrix();
 
		GL.PushMatrix();
		GL.Translate(-4, 0, 0);
		model.Render(time);
		GL.PopMatrix();
		//gunner_body.Render(time)
		//gunner_head.Render(time)
		//gunner_weapon.Render(time)
 
		SwapBuffers();
	}
 
	public static void Main()
	{
		MD2Test app = new MD2Test();
		app.Run();
	}
}
febriano's picture

thanks for classes much appreciated i have already started on writing a loader my self for the .obj files