private void _Create(int divisions) { var icoSphereCreator = new IcoSphereCreator(); geom = icoSphereCreator.Create(divisions); var positions = geom.Positions.ToArray(); var vertexSoup = new Util3d.VertexSoup <SSVertex_PosNormDiffTex1>(); var indexList = new List <UInt16>(); // we have to process each face in the IcoSphere, so we can // properly "wrap" the texture-coordinates that fall across the left/right border foreach (TriangleIndices face in geom.Faces) { var vp1 = positions[face.v1]; var vp2 = positions[face.v2]; var vp3 = positions[face.v3]; var normal1 = vp1.Normalized(); var normal2 = vp2.Normalized(); var normal3 = vp3.Normalized(); float s1, s2, s3, t1, t2, t3; _computeEquirectangularUVForSpherePoint(normal1, out s1, out t1); _computeEquirectangularUVForSpherePoint(normal2, out s2, out t2); _computeEquirectangularUVForSpherePoint(normal3, out s3, out t3); // configure verticies var v1 = new SSVertex_PosNormDiffTex1(); v1.Position = vp1; v1.Normal = normal1; v1.Tu = s1; v1.Tv = t1; var v2 = new SSVertex_PosNormDiffTex1(); v2.Position = vp2; v2.Normal = normal2; v2.Tu = s2; v2.Tv = t2; var v3 = new SSVertex_PosNormDiffTex1(); v3.Position = vp3; v3.Normal = normal3; v3.Tu = s3; v3.Tv = t3; // if a triangle spans the left/right seam where U transitions from 1 to -1 bool v1_left = vp1.X < 0.0f; bool v2_left = vp2.X < 0.0f; bool v3_left = vp3.X < 0.0f; if (vp1.Z < 0.0f && vp2.Z < 0.0f && vp3.Z < 0.0f && ((v2_left != v1_left) || (v3_left != v1_left))) { // we need to "wrap" texture coordinates if (v1.Tu < 0.5f) { v1.Tu += 1.0f; } if (v2.Tu < 0.5f) { v2.Tu += 1.0f; } if (v3.Tu < 0.5f) { v3.Tu += 1.0f; } } // add configured verticies to mesh.. UInt16 idx1 = vertexSoup.digestVertex(ref v1); UInt16 idx2 = vertexSoup.digestVertex(ref v2); UInt16 idx3 = vertexSoup.digestVertex(ref v3); indexList.Add(idx1); indexList.Add(idx2); indexList.Add(idx3); } var vertexArr = vertexSoup.verticies.ToArray(); var idxArr = indexList.ToArray(); // upload to GL vbo = new SSVertexBuffer <SSVertex_PosNormDiffTex1>(vertexArr); ibo = new SSIndexBuffer(idxArr, vbo); }
// generateDrawIndexBuffer(..) // // Walks the wavefront faces, feeds pre-configured verticies to the VertexSoup, // and returns a new index-buffer pointing to the new VertexSoup.verticies indicies. public static void generateDrawIndexBuffer( WavefrontObjLoader wff, out UInt16[] indicies_return, out SSVertex_PosNormDiffTex1[] verticies_return) { const bool shouldDedup = true; // this lets us turn on/of vertex-soup deduping var soup = new VertexSoup <SSVertex_PosNormDiffTex1>(deDup: shouldDedup); List <UInt16> draw_indicies = new List <UInt16>(); // (0) go throu`gh the materials and faces, DENORMALIZE from WF-OBJ into fully-configured verticies // load indexes foreach (var mtl in wff.materials) { // wavefrontOBJ stores color in CIE-XYZ color space. Convert this to Alpha-RGB var materialDiffuseColor = WavefrontObjLoader.CIEXYZtoColor(mtl.vDiffuse).ToArgb(); foreach (var face in mtl.faces) { // iterate over the vericies of a wave-front FACE... // DEREFERENCE each .obj vertex paramater (position, normal, texture coordinate) SSVertex_PosNormDiffTex1[] vertex_list = new SSVertex_PosNormDiffTex1[face.v_idx.Length]; for (int facevertex = 0; facevertex < face.v_idx.Length; facevertex++) { // position vertex_list[facevertex].Position = CV(wff.positions[face.v_idx[facevertex]]); // normal int normal_idx = face.n_idx[facevertex]; if (normal_idx != -1) { vertex_list[facevertex].Normal = CV(wff.normals[normal_idx]); } // texture coordinate int tex_index = face.tex_idx[facevertex]; if (tex_index != -1) { vertex_list[facevertex].Tu = wff.texCoords[tex_index].U; vertex_list[facevertex].Tv = 1 - wff.texCoords[tex_index].V; } // assign our material's diffusecolor to the vertex diffuse color... vertex_list [facevertex].DiffuseColor = materialDiffuseColor; } // turn them into indicies in the vertex soup.. // .. we hand the soup a set of fully configured verticies. It // .. dedups and accumulates them, and hands us back indicies // .. relative to it's growing list of deduped verticies. UInt16[] soup_indicies = soup.digestVerticies(vertex_list); // now we add these indicies to the draw-list. Right now we assume // draw is using GL_TRIANGLE, so we convert NGONS into triange lists if (soup_indicies.Length == 3) // triangle { draw_indicies.Add(soup_indicies[0]); draw_indicies.Add(soup_indicies[1]); draw_indicies.Add(soup_indicies[2]); } else if (soup_indicies.Length == 4) // quad { draw_indicies.Add(soup_indicies[0]); draw_indicies.Add(soup_indicies[1]); draw_indicies.Add(soup_indicies[2]); draw_indicies.Add(soup_indicies[0]); draw_indicies.Add(soup_indicies[2]); draw_indicies.Add(soup_indicies[3]); } else { // This n-gon algorithm only works if the n-gon is coplanar and convex, // which Wavefront OBJ says they must be. // .. to tesselate concave ngons, one must tesselate using a more complex method, see // http://en.wikipedia.org/wiki/Polygon_triangulation#Ear_clipping_method // manually generate a triangle-fan for (int x = 1; x < (soup_indicies.Length - 1); x++) { draw_indicies.Add(soup_indicies[0]); draw_indicies.Add(soup_indicies[x]); draw_indicies.Add(soup_indicies[x + 1]); } // throw new NotImplementedException("unhandled face size: " + newindicies.Length); } } } // convert the linked-lists into arrays and return indicies_return = draw_indicies.ToArray(); verticies_return = soup.verticies.ToArray(); Console.WriteLine("VertexSoup_VertexFormatBinder:generateDrawIndexBuffer : \r\n {0} verticies, {1} indicies. Dedup = {2}", verticies_return.Length, indicies_return.Length, shouldDedup ? "YES" : "NO"); }