public static GlobeMeshData GetGlobeData() { float uScale = 1.0f; float vScale = 1.0f; // Make four rows at the polar caps in the place of one // to diminish the degenerate triangle issue. int poleVertical = 3; int uniformVertical = 64; int horizontal = 128; int vertical = uniformVertical + poleVertical * 2; float radius = 100.0f; int vertexCount = (horizontal + 1) * (vertical + 1); VertexAttribs attribs = new VertexAttribs(); attribs.position = new Vector3[vertexCount]; attribs.uv0 = new Vector2[vertexCount]; attribs.color = new Vector4[vertexCount]; for (int y = 0; y <= vertical; y++) { float yf; if (y <= poleVertical) { yf = (float)y / (poleVertical + 1) / uniformVertical; } else if (y >= vertical - poleVertical) { yf = (float)(uniformVertical - 1 + ((float)(y - (vertical - poleVertical - 1)) / (poleVertical + 1))) / uniformVertical; } else { yf = (float)(y - poleVertical) / uniformVertical; } float lat = (yf - 0.5f) * Mathf.PI; float cosLat = Mathf.Cos(lat); for (int x = 0; x <= horizontal; x++) { float xf = (float)x / (float)horizontal; float lon = (0.5f + xf) * Mathf.PI * 2; int curIndex = y * (horizontal + 1) + x; if (x == horizontal) { // Make sure that the wrap seam is EXACTLY the same // xyz so there is no chance of pixel cracks. attribs.position[curIndex] = attribs.position[y * (horizontal + 1) + 0]; } else { var posX = radius * Mathf.Cos(lon) * cosLat; var posY = radius * Mathf.Sin(lon) * cosLat; var posZ = radius * Mathf.Sin(lat); attribs.position[curIndex] = new Vector3(posX, posY, posZ); } // With a normal mapping, half the triangles degenerate at the poles, // which causes seams between every triangle. It is better to make them // a fan, and only get one seam. attribs.uv0[curIndex] = new Vector2(y == 0 || y == vertical ? 0.5f : xf * uScale, (1.0f - yf) * vScale); attribs.color[curIndex] = new Vector4(1, 1, 1, 1); } } int[] triangleIndices = new int[horizontal * vertical * 6]; int index = 0; for (int x = 0; x < horizontal; x++) { for (int y = 0; y < vertical; y++) { triangleIndices[index + 0] = y * (horizontal + 1) + x; triangleIndices[index + 1] = y * (horizontal + 1) + x + 1; triangleIndices[index + 2] = (y + 1) * (horizontal + 1) + x; triangleIndices[index + 3] = (y + 1) * (horizontal + 1) + x; triangleIndices[index + 4] = y * (horizontal + 1) + x + 1; triangleIndices[index + 5] = (y + 1) * (horizontal + 1) + x + 1; index += 6; } } Vector2[] vec2UVs = attribs.uv0; for (int i = 0; i < vec2UVs.Length; i++) { vec2UVs[i] = new Vector2(1.0f - vec2UVs[i].x, vec2UVs[i].y); } attribs.uv0 = vec2UVs; return(new GlobeMeshData(attribs, triangleIndices)); }
public unsafe static NativeMeshSOA Parse(string path, Allocator outputAllocator = Allocator.Persistent, VertexAttribs vertexAttribs = VertexAttribs.Position, VertexOrder vertexOrder = VertexOrder.ByDefinition) { #if VERBOSE Debug.LogFormat("trying {0}", path); #endif var text = File.ReadAllText(path); //TODO replace with native variant var textSize = text.Length; // measure the data int numPositions = 0; int numTexCoords = 0; int numNormals = 0; int numFaces = 0; for (int i = 0; i < text.Length; i++) { if (ReadChar(text, ref i, 'v')) { if (ReadBlank(text, ref i)) { numPositions++; } else if (ReadChar(text, ref i, 't') && ReadBlank(text, ref i)) { numTexCoords++; } else if (ReadChar(text, ref i, 'n') && ReadBlank(text, ref i)) { numNormals++; } } else if (ReadChar(text, ref i, 'f') && ReadBlankGreedy(text, ref i)) { int readVerts = 0; while (ReadDigit(text, ref i)) { ReadUntilNewlineOrBlank(text, ref i); ReadBlankGreedy(text, ref i); readVerts++; } if (readVerts > 2) { numFaces += readVerts - 2; } } ReadUntilNewline(text, ref i); } #if VERBOSE Debug.LogFormat("-- numPositions = {0}", numPositions); Debug.LogFormat("-- numTexCoords = {0}", numTexCoords); Debug.LogFormat("-- numNormals = {0}", numNormals); Debug.LogFormat("-- numFaces = {0}", numFaces); #endif // allocate buffers var inputPositions = new NativeArray <Vector3>(numPositions, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var inputTexCoords = new NativeArray <Vector2>(numTexCoords, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var inputNormals = new NativeArray <Vector3>(numNormals, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var inputFaces = new NativeArray <InputFace>(numFaces, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var outputIndicesMax = numFaces * 3; var outputIndicesLUT = new NativeHashMap <Hash128, int>(outputIndicesMax, Allocator.Temp); var outputPositions = new NativeArray <Vector3>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var outputTexCoords = new NativeArray <Vector2>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var outputNormals = new NativeArray <Vector3>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var outputIndices = new NativeArray <int>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory); // read the data numPositions = 0; numTexCoords = 0; numNormals = 0; numFaces = 0; for (int i = 0; i < text.Length; i++) { if (ReadChar(text, ref i, 'v')) { if (ReadBlank(text, ref i)) { Vector3 position; ReadFloat(text, ref i, out position.x); position.x *= -1.0f; //TODO remove this hack ReadBlankGreedy(text, ref i); ReadFloat(text, ref i, out position.y); ReadBlankGreedy(text, ref i); ReadFloat(text, ref i, out position.z); inputPositions[numPositions++] = position; } else if (ReadChar(text, ref i, 't') && ReadBlank(text, ref i)) { Vector2 texCoord; ReadFloat(text, ref i, out texCoord.x); ReadBlankGreedy(text, ref i); ReadFloat(text, ref i, out texCoord.y); inputTexCoords[numTexCoords++] = texCoord; } else if (ReadChar(text, ref i, 'n') && ReadBlank(text, ref i)) { Vector3 normal; ReadFloat(text, ref i, out normal.x); normal.x *= -1.0f; //TODO remove this hack ReadBlankGreedy(text, ref i); ReadFloat(text, ref i, out normal.y); ReadBlankGreedy(text, ref i); ReadFloat(text, ref i, out normal.z); inputNormals[numNormals++] = normal; } } else if (ReadChar(text, ref i, 'f') && ReadBlankGreedy(text, ref i)) { InputFace face = new InputFace(); if (ReadUInt(text, ref i, out face.v0.idxPosition)) { ReadChar(text, ref i, '/'); ReadUInt(text, ref i, out face.v0.idxTexCoord); ReadChar(text, ref i, '/'); ReadUInt(text, ref i, out face.v0.idxNormal); int readVerts = 1; while (ReadBlankGreedy(text, ref i)) { face.v1 = face.v2; if (ReadUInt(text, ref i, out face.v2.idxPosition)) { ReadChar(text, ref i, '/'); ReadUInt(text, ref i, out face.v2.idxTexCoord); ReadChar(text, ref i, '/'); ReadUInt(text, ref i, out face.v2.idxNormal); if (++readVerts > 2) { inputFaces[numFaces++] = face; } } } } } ReadUntilNewline(text, ref i); } // process the data int numOutputVertices = 0; int numOutputIndices = 0; if (vertexOrder == VertexOrder.ByReference) { for (int i = 0; i != numFaces; i++) { InputFace face = inputFaces[i]; var key0 = Hash(in face.v0); var key1 = Hash(in face.v1); var key2 = Hash(in face.v2); int idx0, idx1, idx2; if (outputIndicesLUT.TryGetValue(key0, out idx0) == false) { outputIndicesLUT[key0] = idx0 = numOutputVertices++; } if (outputIndicesLUT.TryGetValue(key1, out idx1) == false) { outputIndicesLUT[key1] = idx1 = numOutputVertices++; } if (outputIndicesLUT.TryGetValue(key2, out idx2) == false) { outputIndicesLUT[key2] = idx2 = numOutputVertices++; } outputPositions[idx0] = inputPositions[(int)face.v0.idxPosition - 1]; outputPositions[idx1] = inputPositions[(int)face.v1.idxPosition - 1]; outputPositions[idx2] = inputPositions[(int)face.v2.idxPosition - 1]; outputTexCoords[idx0] = inputTexCoords[(int)face.v0.idxTexCoord - 1]; outputTexCoords[idx1] = inputTexCoords[(int)face.v1.idxTexCoord - 1]; outputTexCoords[idx2] = inputTexCoords[(int)face.v2.idxTexCoord - 1]; outputNormals[idx0] = inputNormals[(int)face.v0.idxNormal - 1]; outputNormals[idx1] = inputNormals[(int)face.v1.idxNormal - 1]; outputNormals[idx2] = inputNormals[(int)face.v2.idxNormal - 1]; outputIndices[numOutputIndices++] = idx0; outputIndices[numOutputIndices++] = idx1; outputIndices[numOutputIndices++] = idx2; } } else if (vertexOrder == VertexOrder.ByDefinition) { numOutputVertices = numPositions; var indexVisited = new NativeArray <bool>(numPositions, Allocator.Temp, NativeArrayOptions.ClearMemory); for (int i = 0; i != numFaces; i++) { InputFace face = inputFaces[i]; var key0 = Hash(in face.v0); var key1 = Hash(in face.v1); var key2 = Hash(in face.v2); int idx0, idx1, idx2; if (outputIndicesLUT.TryGetValue(key0, out idx0) == false) { if (indexVisited[idx0 = (int)face.v0.idxPosition - 1]) { outputIndicesLUT[key0] = idx0 = numOutputVertices++; } else { outputIndicesLUT[key0] = idx0; } } if (outputIndicesLUT.TryGetValue(key1, out idx1) == false) { if (indexVisited[idx1 = (int)face.v1.idxPosition - 1]) { outputIndicesLUT[key1] = idx1 = numOutputVertices++; } else { outputIndicesLUT[key1] = idx1; } } if (outputIndicesLUT.TryGetValue(key2, out idx2) == false) { if (indexVisited[idx2 = (int)face.v2.idxPosition - 1]) { outputIndicesLUT[key2] = idx2 = numOutputVertices++; } else { outputIndicesLUT[key2] = idx2; } } indexVisited[(int)face.v0.idxPosition - 1] = true; indexVisited[(int)face.v1.idxPosition - 1] = true; indexVisited[(int)face.v2.idxPosition - 1] = true; outputPositions[idx0] = inputPositions[(int)face.v0.idxPosition - 1]; outputPositions[idx1] = inputPositions[(int)face.v1.idxPosition - 1]; outputPositions[idx2] = inputPositions[(int)face.v2.idxPosition - 1]; outputTexCoords[idx0] = inputTexCoords[(int)face.v0.idxTexCoord - 1]; outputTexCoords[idx1] = inputTexCoords[(int)face.v1.idxTexCoord - 1]; outputTexCoords[idx2] = inputTexCoords[(int)face.v2.idxTexCoord - 1]; outputNormals[idx0] = inputNormals[(int)face.v0.idxNormal - 1]; outputNormals[idx1] = inputNormals[(int)face.v1.idxNormal - 1]; outputNormals[idx2] = inputNormals[(int)face.v2.idxNormal - 1]; outputIndices[numOutputIndices++] = idx0; outputIndices[numOutputIndices++] = idx1; outputIndices[numOutputIndices++] = idx2; } indexVisited.Dispose(); } #if VERBOSE Debug.LogFormat("output vertex count = {0}", numOutputVertices); Debug.LogFormat("output index count = {0}", numOutputIndices); #endif // copy to container NativeMeshSOA mesh = new NativeMeshSOA() { vertexPositions = new NativeArray <Vector3>(numOutputVertices, outputAllocator, NativeArrayOptions.UninitializedMemory), vertexTexCoords = new NativeArray <Vector2>(numOutputVertices, outputAllocator, NativeArrayOptions.UninitializedMemory), vertexNormals = new NativeArray <Vector3>(numOutputVertices, outputAllocator, NativeArrayOptions.UninitializedMemory), vertexCount = numOutputVertices, faceIndices = new NativeArray <int>(numOutputIndices, outputAllocator, NativeArrayOptions.UninitializedMemory), faceIndicesCount = numOutputIndices, }; NativeArray <Vector3> .Copy(outputPositions, mesh.vertexPositions, numOutputVertices); NativeArray <Vector2> .Copy(outputTexCoords, mesh.vertexTexCoords, numOutputVertices); NativeArray <Vector3> .Copy(outputNormals, mesh.vertexNormals, numOutputVertices); NativeArray <int> .Copy(outputIndices, mesh.faceIndices, numOutputIndices); // free buffers inputPositions.Dispose(); inputTexCoords.Dispose(); inputNormals.Dispose(); inputFaces.Dispose(); outputIndicesLUT.Dispose(); outputPositions.Dispose(); outputTexCoords.Dispose(); outputNormals.Dispose(); outputIndices.Dispose(); // done return(mesh); }
public GlobeMeshData(VertexAttribs attribs, int[] triangleIndices) { this.attribs = attribs; this.triangleIndices = triangleIndices; }