I am having an issue where triangles in a model aren't being shown.
The left is wireframe, the right is the finished image. For some reason a bunch of the triangles aren't being shown.
The project is in C#, using OpenGL (OpenTK). I'll provide more information if neccessary (such as code), but there's a lot of code, so i'd rather check if anyone has a simple solution first... Please comment if you need more info though.
EDIT: Here's the buffer code if it helps...
public void LoadBuffers(MeshData m, out uint indexBuffer, out uint dataBuffer, out int vertOffset, out int normOffset, out int texcoordOffset)
{
float[] verts, norms, texcoords;
uint[] indices;
m.OpenGLArrays(out verts, out norms, out texcoords, out indices);
GL.GenBuffers(1, out dataBuffer);
GL.GenBuffers(1, out indexBuffer);
int buffersize = (verts.Length + norms.Length + texcoords.Length);
float[] bufferdata = new float[buffersize];
vertOffset = 0;
normOffset = verts.Length;
texcoordOffset = (verts.Length + norms.Length);
verts.CopyTo(bufferdata, vertOffset);
norms.CopyTo(bufferdata, normOffset);
texcoords.CopyTo(bufferdata, texcoordOffset);
bool v = false;
for (int i = texcoordOffset; i < bufferdata.Length; i++)
{
if (v)
{
bufferdata[i] = 1 - bufferdata[i];
v = false;
}
else
{
v = true;
}
}
GL.BindBuffer(BufferTarget.ArrayBuffer, dataBuffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(buffersize * sizeof(float)), bufferdata,
BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer);
GL.BufferData(BufferTarget.ElementArrayBuffer,
(IntPtr)(indices.Length * sizeof(uint)), indices, BufferUsageHint.StaticDraw);
}
public bool DrawBuffer(MeshData m, uint tex, uint indexBuffer, uint dataBuffer, int vertOffset, int normOffset, int texcoordOffset)
{
tex = tempTexture;
GL.CullFace(CullFaceMode.Back);
GL.PushClientAttrib(ClientAttribMask.ClientVertexArrayBit);
GL.ClientActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, tex);
GL.BindBuffer(BufferTarget.ArrayBuffer, dataBuffer);
GL.NormalPointer(NormalPointerType.Float, 0, (IntPtr)(normOffset * sizeof(float)));
GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, (IntPtr)(texcoordOffset * sizeof(float)));
GL.VertexPointer(3, VertexPointerType.Float, 0, (IntPtr)(vertOffset * sizeof(float)));
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer);
GL.DrawElements(BeginMode.Triangles, m.Tris.Length * 3, DrawElementsType.UnsignedInt, IntPtr.Zero);
GL.PopClientAttrib();
return true;
}
EDIT 2: And here is my OBJ loader... There's quite a chance this is the problem.
public class ObjLoader
{
public MeshData LoadStream(Stream stream)
{
StreamReader reader = new StreamReader(stream);
List points = new List();
List normals = new List();
List texCoords = new List();
List tris = new List();
string line;
char[] splitChars = { ' ' };
while ((line = reader.ReadLine()) != null)
{
line = line.Trim(splitChars);
line = line.Replace(" ", " ");
string[] parameters = line.Split(splitChars);
switch (parameters[0])
{
case "p":
// Point
break;
case "v":
// Vertex
float x = float.Parse(parameters[1], CultureInfo.InvariantCulture.NumberFormat);
float y = float.Parse(parameters[2], CultureInfo.InvariantCulture.NumberFormat);
float z = float.Parse(parameters[3], CultureInfo.InvariantCulture.NumberFormat);
points.Add(new Vector3(x, y, z));
break;
case "vt":
// TexCoord
float u = float.Parse(parameters[1], CultureInfo.InvariantCulture.NumberFormat);
float v = float.Parse(parameters[2], CultureInfo.InvariantCulture.NumberFormat);
texCoords.Add(new Vector2(u, v));
break;
case "vn":
// Normal
float nx = float.Parse(parameters[1], CultureInfo.InvariantCulture.NumberFormat);
float ny = float.Parse(parameters[2], CultureInfo.InvariantCulture.NumberFormat);
float nz = float.Parse(parameters[3], CultureInfo.InvariantCulture.NumberFormat);
normals.Add(new Vector3(nx, ny, nz));
break;
case "f":
// Face
tris.AddRange(parseFace(parameters));
break;
}
}
Vector3[] p = points.ToArray();
Vector2[] tc = texCoords.ToArray();
Vector3[] n = normals.ToArray();
Tri[] f = tris.ToArray();
// If there are no specified texcoords or normals, we add a dummy one.
// That way the Points will have something to refer to.
if (tc.Length == 0)
{
tc = new Vector2[1];
tc[0] = new Vector2(0, 0);
}
if (n.Length == 0)
{
n = new Vector3[1];
n[0] = new Vector3(1, 0, 0);
}
return new MeshData(p, n, tc, f);
}
public MeshData LoadFile(string file)
{
// Silly me, using() closes the file automatically.
using (FileStream s = File.Open(file, FileMode.Open))
{
return LoadStream(s);
}
}
private static Tri[] parseFace(string[] indices)
{
Point[] p = new Point[indices.Length - 1];
for (int i = 0; i < p.Length; i++)
{
p[i] = parsePoint(indices[i + 1]);
}
return Triangulate(p);
//return new Face(p);
}
// Takes an array of points and returns an array of triangles.
// The points form an arbitrary polygon.
private static Tri[] Triangulate(Point[] ps)
{
List ts = new List();
if (ps.Length < 3)
{
throw new Exception("Invalid shape! Must have >2 points");
}
Point lastButOne = ps[1];
Point lastButTwo = ps[0];
for (int i = 2; i < ps.Length; i++)
{
Tri t = new Tri(lastButTwo, lastButOne, ps[i]);
lastButOne = ps[i];
lastButTwo = ps[i - 1];
ts.Add(t);
}
return ts.ToArray();
}
private static Point parsePoint(string s)
{
s += "//";
char[] splitChars = { '/' };
string[] parameters = s.Split(splitChars);
int vert, tex, norm;
vert = tex = norm = 0;
vert = int.Parse(parameters[0]) - 1;
// Texcoords and normals are optional in .obj files
if (parameters[1] != "")
{
tex = int.Parse(parameters[1]) - 1;
}
if (parameters[2] != "")
{
norm = int.Parse(parameters[2]) - 1;
}
return new Point(vert, norm, tex);
}
}
Answer
Checked the .obj loader, there was a flaw in it so that it didn't correctly load in quads and split them into triangles... It split quad ABCD into ABC and BCA instead of ABC and ACD
Sorry, thanks for all the attempted help though!
next time... I'm writing my own importer :P
No comments:
Post a Comment