public void ExportToFile(string resourceName, string fileName, VModel model) { var exportedModel = ModelRoot.CreateModel(); exportedModel.Asset.Generator = GENERATOR; var scene = exportedModel.UseScene(Path.GetFileName(resourceName)); var embeddedMeshIndex = 0; foreach (var mesh in model.GetEmbeddedMeshes()) { var name = $"Embedded Mesh {++embeddedMeshIndex}"; var exportedMesh = CreateGltfMesh(name, mesh, exportedModel); scene.CreateNode(name) .WithMesh(exportedMesh); } foreach (var meshReference in model.GetReferencedMeshNames()) { var meshResource = GuiContext.LoadFileByAnyMeansNecessary(meshReference + "_c"); if (meshResource == null) { continue; } var nodeName = Path.GetFileNameWithoutExtension(meshReference); var mesh = new VMesh(meshResource); var exportedMesh = CreateGltfMesh(nodeName, mesh, exportedModel); scene.CreateNode(nodeName) .WithMesh(exportedMesh); } exportedModel.Save(fileName); }
public virtual void Render(VMesh m) { foreach (VRenderLayer rl in Layers) { rl.Render(m, m.Viz); } }
public void Init(EditableMesh m) { sm_Instance = this; m_EditMesh = m; m_RealMesh = m_EditMesh.mesh; //ETimeProf prof = new ETimeProf(); m_DegRTriCont = new DegradeRTriCont(); // map VV <-> RV m_VVertCont = new VVertCont(); _InitVVertTable(); //prof.Click("VMesh.Init.VVertTable:"); // establish VEdge table m_VEdgeCont = new VEdgeCont(); _InitVEdgeTable(); //prof.Click("VMesh.Init.VEdgeTable:"); // establish VQuad table m_VFaceCont = new VFaceCont(); _InitVFaceTable(); //prof.Click("VMesh.Init.VQuadTable:"); }
/// <summary> /// Export a Valve VMDL to GLTF. /// </summary> /// <param name="resourceName">The name of the resource being exported.</param> /// <param name="fileName">Target file name.</param> /// <param name="model">The model resource to export.</param> public void ExportToFile(string resourceName, string fileName, VModel model) { var exportedModel = ModelRoot.CreateModel(); exportedModel.Asset.Generator = GENERATOR; var scene = exportedModel.UseScene(Path.GetFileName(resourceName)); var embeddedMeshIndex = 0; void AddMeshNode(string name, VMesh mesh) { var exportedMesh = CreateGltfMesh(name, mesh, exportedModel, true); // Add skeleton and skin var modelSkeleton = model.GetSkeleton(); if (modelSkeleton.AnimationTextureSize > 0) { var skeleton = scene.CreateNode(name); var joints = CreateGltfSkeleton(modelSkeleton, skeleton); scene.CreateNode(name) .WithSkinnedMesh(exportedMesh, Matrix4x4.Identity, joints); // Rotate upright, scale inches to meters. skeleton.WorldMatrix = TRANSFORMSOURCETOGLTF; } else { var meshNode = scene.CreateNode(name) .WithMesh(exportedMesh); // Rotate upright, scale inches to meters. meshNode.WorldMatrix = TRANSFORMSOURCETOGLTF; } } // Add embedded meshes foreach (var mesh in model.GetEmbeddedMeshes()) { var name = $"Embedded Mesh {++embeddedMeshIndex}"; AddMeshNode(name, mesh); } // Add external meshes foreach (var meshReference in model.GetReferencedMeshNames()) { var meshResource = GuiContext.LoadFileByAnyMeansNecessary(meshReference + "_c"); if (meshResource == null) { continue; } var nodeName = Path.GetFileNameWithoutExtension(meshReference); var mesh = new VMesh(meshResource); AddMeshNode(nodeName, mesh); } exportedModel.Save(fileName); }
// private method private void _PrepareEdgeIndices() { VMesh vmesh = VMesh.Instance; VVert[] allVVerts = vmesh.GetAllVVerts(); VEdge[] allVEdges = vmesh.GetAllVActiveEdges(); Dictionary <VVert, int> vert2idx = new Dictionary <VVert, int>(); for (int i = 0; i < allVVerts.Length; ++i) { VVert v = allVVerts[i]; vert2idx[v] = i; } m_EdgeIndices = new int[allVEdges.Length * 2]; for (int i = 0; i < allVEdges.Length; i++) { VEdge e = allVEdges[i]; VVert v0 = e.GetVVert(0); VVert v1 = e.GetVVert(1); int vidx0 = vert2idx[v0]; int vidx1 = vert2idx[v1]; m_EdgeIndices[i * 2] = vidx0; m_EdgeIndices[i * 2 + 1] = vidx1; } }
public static void Cube(float s) { VMesh m = new VMesh(32, 8); VSceneEntity e = new VSceneEntity(); e.AddMesh(m); e.Meshes[0].Final(); }
public override void Render(VMesh m, VVisualizer v) { // m.Mat.Bind(); fx.Bind(); v.SetMesh(m); v.Bind(); v.Visualize(); v.Release(); fx.Release(); //m.Mat.Release(); }
public override void Render(VMesh m, VVisualizer v) { m.Mat.Bind(); Lighting.GraphLight3D.Active.ShadowFB.Cube.Bind(2); fx.Bind(); v.SetMesh(m); v.Bind(); v.Visualize(); v.Release(); fx.Release(); Lighting.GraphLight3D.Active.ShadowFB.Cube.Release(2); m.Mat.Release(); }
/// <summary> /// update the markers, if not dirty, do nothing; /// /// will retrieve info from Mesh & Selection & other related external data-structures /// </summary> public void UpdateMarkers() { if (!Dirty) { return; } //Mesh m = m_EditMesh.mesh; //Transform meshTr = m_EditMesh.transform; //Vector3[] verts = MeshCache.Instance.vertices; VMesh vmesh = VMesh.Instance; // vert positions VVert[] allVVerts = vmesh.GetAllVVerts(); int vcnt = allVVerts.Length; Vector3[] allVVertPos = new Vector3[vcnt]; for (int i = 0; i < vcnt; ++i) { allVVertPos[i] = allVVerts[i].GetWorldPos(); } // colors Color32[] colors = new Color32[vcnt]; for (int i = 0; i < vcnt; ++i) { VVert oneVVert = allVVerts[i]; if (m_Selection.IsSelectedVert(oneVVert.RepVert)) { colors[i] = SelectedVertColor; } else { colors[i] = NonSelectedVertColor; } } // set to mesh(vert) m_VertMarker.SetVerts(allVVertPos); //indices are set altogether with vertices m_VertMarker.SetColors(colors); // set to mesh(edge) m_EdgeMarker.SetVerts(allVVertPos); m_EdgeMarker.SetColors(colors); m_EdgeMarker.SetIndices(m_EdgeIndices); Dirty = false; }
public void ExportToFile(string resourceName, string fileName, VMesh mesh) { var exportedModel = ModelRoot.CreateModel(); exportedModel.Asset.Generator = GENERATOR; var name = Path.GetFileName(resourceName); var scene = exportedModel.UseScene(name); var exportedMesh = CreateGltfMesh(name, mesh, exportedModel); scene.CreateNode(name) .WithMesh(exportedMesh); exportedModel.Save(fileName); }
/// <summary> /// get VFaces that containing this VEdge /// </summary> public void GetVFaces(List <VFace> vFaces) { vFaces.Clear(); VMesh vmesh = VMesh.Instance; for (int i = 0; i < m_TriCont.Count; ++i) { int triIdx = m_TriCont[i]; VFace vf = vmesh.GetVFaceFromRTri(triIdx); if (!vFaces.Contains(vf)) { vFaces.Add(vf); } } }
/// <summary> /// NOTE: when with 2 tris, the order is: /// tri0: 012, tri1: 123 /// /// </summary> public void AddRTri(int rTriIdx) { //Dbg.Log("VFace{0}, AddRTri: {1}", m_Idx, rTriIdx); Dbg.Assert(m_rTriCnt < 2, "VFace.AddRTri: already have 2 rtris"); m_rTriIdxs[m_rTriCnt] = rTriIdx; ++m_rTriCnt; VVert vv0, vv1, vv2; VMesh vmesh = VMesh.Instance; vmesh.GetVVertsFromRTri(rTriIdx, out vv0, out vv1, out vv2); if (m_rTriCnt == 1) { m_VVertLst.Add(vv0); m_VVertLst.Add(vv1); m_VVertLst.Add(vv2); } else { //merge with another tri, must ensure order of verts // set lst[0] for (int i = 0; i < 3; ++i) { if (m_VVertLst[i] != vv0 && m_VVertLst[i] != vv1 && m_VVertLst[i] != vv2) { if (i != 0) { VVert tmp = m_VVertLst[0]; m_VVertLst[0] = m_VVertLst[i]; m_VVertLst[i] = tmp; } break; } } //set lst[3] VVert[] verts = new VVert[] { vv0, vv1, vv2 }; for (int i = 0; i < 3; ++i) { if (verts[i] != m_VVertLst[1] && verts[i] != m_VVertLst[2]) { m_VVertLst.Add(verts[i]); break; } } Dbg.Assert(m_VVertLst.Count == 4, "VFace.AddTri: adding new tri, but no new vert added?!"); } }
/// <summary> /// Export a Valve VMESH to Gltf. /// </summary> /// <param name="resourceName">The name of the resource being exported.</param> /// <param name="fileName">Target file name.</param> /// <param name="mesh">The mesh resource to export.</param> public void ExportToFile(string resourceName, string fileName, VMesh mesh) { var exportedModel = ModelRoot.CreateModel(); exportedModel.Asset.Generator = GENERATOR; var name = Path.GetFileName(resourceName); var scene = exportedModel.UseScene(name); var exportedMesh = CreateGltfMesh(name, mesh, exportedModel, false); var meshNode = scene.CreateNode(name) .WithMesh(exportedMesh); // Swap Rotate upright, scale inches to meters. meshNode.WorldMatrix = TRANSFORMSOURCETOGLTF; exportedModel.Save(fileName); }
public virtual void RenderDepth(VMesh m) { RLD.Render(m, m.Viz); }
public void Fini() { sm_Instance = null; }
public virtual void Bind(VMesh m) { }
public override void SetMesh(VMesh m) { md = m; }
public virtual void Release(VMesh m, VVisualizer v) { }
public virtual void Render(VMesh m, VVisualizer v) { }
public virtual void SetMesh(VMesh m) { }
/// <summary> /// Loads the VMesh into our Objmesh /// </summary> /// <param name="objMesh">The objmesh to load into</param> /// <param name="mesh">The VMesh to load</param> private void LoadVMeshIntoMesh(ObjMesh objMesh, VMesh mesh) { var data = mesh.GetData(); var vbib = mesh.VBIB; foreach (var sceneObject in data.GetArray("m_sceneObjects")) { foreach (var drawCall in sceneObject.GetArray("m_drawCalls")) { var startingVertexCount = objMesh.Positions.Count; // Set this so we can offset the indicies for triangles correctly var vertexBufferInfo = drawCall.GetArray("m_vertexBuffers")[0]; // In what situation can we have more than 1 vertex buffer per draw call? var vertexBufferIndex = (int)vertexBufferInfo.GetIntegerProperty("m_hBuffer"); var vertexBuffer = vbib.VertexBuffers[vertexBufferIndex]; var indexBufferInfo = drawCall.GetSubCollection("m_indexBuffer"); var indexBufferIndex = (int)indexBufferInfo.GetIntegerProperty("m_hBuffer"); var indexBuffer = vbib.IndexBuffers[indexBufferIndex]; // Set vertex attributes foreach (var attribute in vertexBuffer.Attributes) { var buffer = ReadAttributeBuffer(vertexBuffer, attribute); var numComponents = buffer.Length / vertexBuffer.Count; if (attribute.Name == "BLENDINDICES") { var byteBuffer = buffer.Select(f => (byte)f).ToArray(); var rawBufferData = new byte[buffer.Length]; System.Buffer.BlockCopy(byteBuffer, 0, rawBufferData, 0, rawBufferData.Length); var blendIndices = rawBufferData.ChunkBy(4); objMesh.BlendIndices.AddRange(blendIndices); continue; } if (attribute.Name == "BLENDWEIGHT") { var vectors = ToVector4Array(buffer); objMesh.BlendWeights.AddRange(vectors); } if (attribute.Name == "POSITION") { var vectors = ToVector3Array(buffer); objMesh.Positions.AddRange(vectors); } if (attribute.Name == "NORMAL") { if (VMesh.IsCompressedNormalTangent(drawCall)) { var vectors = ToVector4Array(buffer); var(normals, tangents) = DecompressNormalTangents(vectors); objMesh.Normals.AddRange(normals); } else { var vectors = ToVector3Array(buffer); objMesh.Normals.AddRange(vectors); } continue; } if (attribute.Name == "TEXCOORD") { if (numComponents != 2) { // ignore textcoords that arent 2 continue; } var vectors = ToVector2Array(buffer); objMesh.TextureCoords.AddRange(vectors); } } // Set index buffer var startIndex = (int)drawCall.GetIntegerProperty("m_nStartIndex"); var indexCount = (int)drawCall.GetIntegerProperty("m_nIndexCount"); var indices = ReadIndices(indexBuffer, startIndex, indexCount); var newFaces = indices.ChunkBy(3).Select(idxList => idxList.Select(idx => new ObjFaceVertex(idx + startingVertexCount)).ToList()).ToList(); objMesh.Faces.AddRange(newFaces); var materialPath = drawCall.GetProperty <string>("m_material"); var materialResource = VpkLoader.LoadFile(materialPath + "_c"); var renderMaterial = (VMaterial)materialResource.DataBlock; var matName = Path.GetFileNameWithoutExtension(materialPath); if (objMesh.Material == null) { objMesh.Material = ObjMaterial.FromVMaterial(renderMaterial, Path.GetFileNameWithoutExtension(materialPath), VpkLoader); } else if (matName != objMesh.Material.Name) { // throw new Exception("2 different mats in same object"); } } } }
public override void Render(VMesh m, VVisualizer v) { v.SetMesh(m); v.Visualize(); }
public override GraphNode3D LoadNode(string path) { GraphEntity3D root = new GraphEntity3D(); string file = path; var e = new Assimp.AssimpContext(); var c1 = new Assimp.Configs.NormalSmoothingAngleConfig(45); e.SetConfig(c1); Console.WriteLine("Impporting:" + file); Assimp.Scene s = null; try { s = e.ImportFile(file, PostProcessSteps.CalculateTangentSpace | PostProcessSteps.GenerateSmoothNormals | PostProcessSteps.Triangulate | PostProcessSteps.GenerateNormals); } catch (AssimpException ae) { Console.WriteLine(ae); Console.WriteLine("Failed to import"); } Console.WriteLine("Imported."); Dictionary <string, VMesh> ml = new Dictionary <string, VMesh>(); List <VMesh> ml2 = new List <VMesh>(); foreach (var m in s.Meshes) { var vm = new Material.Material3D(); var m2 = new VMesh(m.VertexCount, m.GetIndices().Length); ml2.Add(m2); // ml.Add(m.Name, m2); m2.Mat = vm; // root.AddMesh(m2); m2.Name = m.Name; var mat = s.Materials[m.MaterialIndex]; TextureSlot t1; if (mat.GetMaterialTextureCount(TextureType.Diffuse) > 0) { t1 = mat.GetMaterialTextures(TextureType.Diffuse)[0]; if (t1.FilePath != null) { vm.TCol = new Tex.Tex2D(IPath + t1.FilePath, false); Console.WriteLine("TexLoaded"); } if (true) { if (new FileInfo(t1.FilePath).Exists == true) { // var tex = App.AppSal.CreateTex2D(); // tex.Path = t1.FilePath; // tex.Load(); //m2.DiffuseMap = tex; } } } for (int i = 0; i < m2.NumVertices; i++) { var v = m.Vertices[i]; var n = m.Normals[i]; var t = m.TextureCoordinateChannels[0]; Vector3D tan, bi; if (m.Tangents != null && m.Tangents.Count > 0) { tan = m.Tangents[i]; bi = m.BiTangents[i]; } else { tan = new Vector3D(0, 0, 0); bi = new Vector3D(0, 0, 0); } if (t.Count() == 0) { m2.SetVertex(i, Cv(v), Cv(tan), Cv(bi), Cv(n), Cv2(t[i])); } else { m2.SetVertex(i, Cv(v), Cv(tan), Cv(bi), Cv(n), Cv2(t[i])); } } int[] id = m.GetIndices(); int fi = 0; uint[] nd = new uint[id.Length]; for (int i = 0; i < id.Length; i++) { nd[i] = (uint)id[i]; } m2.Indices = nd; m2.Final(); } ProcessNode(root, s.RootNode, ml2); return(root as GraphNode3D); }
private Mesh CreateGltfMesh(string meshName, VMesh vmesh, ModelRoot model) { ProgressDialog.SetProgress($"Creating mesh: {meshName}"); var data = vmesh.GetData(); var vbib = vmesh.VBIB; var mesh = model.CreateMesh(meshName); mesh.Name = meshName; foreach (var sceneObject in data.GetArray("m_sceneObjects")) { foreach (var drawCall in sceneObject.GetArray("m_drawCalls")) { var vertexBufferInfo = drawCall.GetArray("m_vertexBuffers")[0]; // In what situation can we have more than 1 vertex buffer per draw call? var vertexBufferIndex = (int)vertexBufferInfo.GetIntegerProperty("m_hBuffer"); var vertexBuffer = vbib.VertexBuffers[vertexBufferIndex]; var indexBufferInfo = drawCall.GetSubCollection("m_indexBuffer"); var indexBufferIndex = (int)indexBufferInfo.GetIntegerProperty("m_hBuffer"); var indexBuffer = vbib.IndexBuffers[indexBufferIndex]; // Create one primitive per draw call var primitive = mesh.CreatePrimitive(); // Avoid duplicate attribute names var uniqueAttributes = vertexBuffer.Attributes.GroupBy(a => a.Name).Select(g => g.First()); // Set vertex attributes foreach (var attribute in uniqueAttributes) { if (AccessorInfo.TryGetValue(attribute.Name, out var accessorInfo)) { var buffer = ReadAttributeBuffer(vbib, vertexBuffer, attribute); if (accessorInfo.NumComponents == 4) { var vectors = ToVector4Array(buffer); primitive.WithVertexAccessor(accessorInfo.GltfAccessorName, vectors); } else if (attribute.Name == "NORMAL" && DrawCall.IsCompressedNormalTangent(drawCall)) { var vectors = ToVector4Array(buffer); var(normals, tangents) = DecompressNormalTangents(vectors); primitive.WithVertexAccessor("NORMAL", normals); primitive.WithVertexAccessor("TANGENT", tangents); } else if (accessorInfo.NumComponents == 3) { var vectors = ToVector3Array(buffer, true, accessorInfo.Resize); primitive.WithVertexAccessor(accessorInfo.GltfAccessorName, vectors); } else if (accessorInfo.NumComponents == 2) { var vectors = ToVector2Array(buffer); primitive.WithVertexAccessor(accessorInfo.GltfAccessorName, vectors); } } } // Set index buffer var indices = ReadIndices(indexBuffer); // For triangle primitives, the front face has to be in counter-clockwise (CCW) winding order. for (var i = 0; i < indices.Length; i += 3) { var b = indices[i + 2]; indices[i + 2] = indices[i + 1]; indices[i + 1] = b; } primitive.WithIndicesAccessor(PrimitiveType.TRIANGLES, indices); // Add material var materialPath = drawCall.GetProperty <string>("m_material"); ProgressDialog.SetProgress($"Loading material: {materialPath}"); var materialResource = GuiContext.LoadFileByAnyMeansNecessary(materialPath + "_c"); if (materialResource == null) { continue; } var renderMaterial = (VMaterial)materialResource.DataBlock; var materialNameTrimmed = Path.GetFileNameWithoutExtension(materialPath); var bestMaterial = GenerateGLTFMaterialFromRenderMaterial(renderMaterial, model, materialNameTrimmed); primitive.WithMaterial(bestMaterial); } } return(mesh); }
public void CreateMesh(object lod) { threadReady = false; VMesh mesh = new VMesh(this); for (int x = 0; x < map.size; x++) { for (int y = 0; y < map.size; y++) { for (int z = 0; z < map.size; z++) { Vector3 pos = new Vector3(x, y, z); Color blockC = map.GetBlock(pos); if (blockC.a == 0) { continue; } Vector3 vertexpos = pos / blocksPerUnit; mesh.SetDrawingColor(blockC); if (map.GetBlock(pos + new Vector3(0, 1, 0)).a == 0) { //Top Face mesh.AddQuad( vertexpos + new Vector3(0, 1, 0) / blocksPerUnit, vertexpos + new Vector3(0, 1, 1) / blocksPerUnit, vertexpos + new Vector3(1, 1, 1) / blocksPerUnit, vertexpos + new Vector3(1, 1, 0) / blocksPerUnit, Vector3.up); } if (map.GetBlock(pos + new Vector3(0, -1, 0)).a == 0) { //Bottom Face mesh.AddQuadFlipped( vertexpos + new Vector3(0, 0, 0) / blocksPerUnit, vertexpos + new Vector3(0, 0, 1) / blocksPerUnit, vertexpos + new Vector3(1, 0, 1) / blocksPerUnit, vertexpos + new Vector3(1, 0, 0) / blocksPerUnit, Vector3.down); } if (map.GetBlock(pos + new Vector3(1, 0, 0)).a == 0) { //Right Face mesh.AddQuadFlipped( vertexpos + new Vector3(1, 0, 0) / blocksPerUnit, vertexpos + new Vector3(1, 0, 1) / blocksPerUnit, vertexpos + new Vector3(1, 1, 1) / blocksPerUnit, vertexpos + new Vector3(1, 1, 0) / blocksPerUnit, Vector3.right); } if (map.GetBlock(pos + new Vector3(-1, 0, 0)).a == 0) { //Left Face mesh.AddQuad( vertexpos + new Vector3(0, 0, 0) / blocksPerUnit, vertexpos + new Vector3(0, 0, 1) / blocksPerUnit, vertexpos + new Vector3(0, 1, 1) / blocksPerUnit, vertexpos + new Vector3(0, 1, 0) / blocksPerUnit, Vector3.left); } if (map.GetBlock(pos + new Vector3(0, 0, 1)).a == 0) { //Front Face mesh.AddQuadFlipped( vertexpos + new Vector3(0, 0, 1) / blocksPerUnit, vertexpos + new Vector3(0, 1, 1) / blocksPerUnit, vertexpos + new Vector3(1, 1, 1) / blocksPerUnit, vertexpos + new Vector3(1, 0, 1) / blocksPerUnit, Vector3.forward); } if (map.GetBlock(pos + new Vector3(0, 0, -1)).a == 0) { //Front Face mesh.AddQuad( vertexpos + new Vector3(0, 0, 0) / blocksPerUnit, vertexpos + new Vector3(0, 1, 0) / blocksPerUnit, vertexpos + new Vector3(1, 1, 0) / blocksPerUnit, vertexpos + new Vector3(1, 0, 0) / blocksPerUnit, Vector3.back); } } } } mesh.GenArrays(); this.mesh = mesh; VoxelWorld.QueueDirtyChunk(this); }
public virtual void Release(VMesh m) { }
public virtual void Bind(VMesh m, VVisualizer v) { }
public void AddMesh(VMesh mesh) { Meshes.Add(mesh); }
private Mesh CreateGltfMesh(string meshName, VMesh vmesh, ModelRoot model, bool includeJoints) { ProgressDialog.SetProgress($"Creating mesh: {meshName}"); var data = vmesh.GetData(); var vbib = vmesh.VBIB; var mesh = model.CreateMesh(meshName); mesh.Name = meshName; foreach (var sceneObject in data.GetArray("m_sceneObjects")) { foreach (var drawCall in sceneObject.GetArray("m_drawCalls")) { var vertexBufferInfo = drawCall.GetArray("m_vertexBuffers")[0]; // In what situation can we have more than 1 vertex buffer per draw call? var vertexBufferIndex = (int)vertexBufferInfo.GetIntegerProperty("m_hBuffer"); var vertexBuffer = vbib.VertexBuffers[vertexBufferIndex]; var indexBufferInfo = drawCall.GetSubCollection("m_indexBuffer"); var indexBufferIndex = (int)indexBufferInfo.GetIntegerProperty("m_hBuffer"); var indexBuffer = vbib.IndexBuffers[indexBufferIndex]; // Create one primitive per draw call var primitive = mesh.CreatePrimitive(); // Avoid duplicate attribute names var attributeCounters = new Dictionary <string, int>(); // Set vertex attributes foreach (var attribute in vertexBuffer.Attributes) { attributeCounters.TryGetValue(attribute.Name, out var attributeCounter); attributeCounters[attribute.Name] = attributeCounter + 1; var accessorName = GetAccessorName(attribute.Name, attributeCounter); var buffer = ReadAttributeBuffer(vertexBuffer, attribute); var numComponents = buffer.Length / vertexBuffer.Count; if (attribute.Name == "BLENDINDICES") { if (!includeJoints) { continue; } var byteBuffer = buffer.Select(f => (byte)f).ToArray(); var rawBufferData = new byte[buffer.Length]; System.Buffer.BlockCopy(byteBuffer, 0, rawBufferData, 0, rawBufferData.Length); var bufferView = mesh.LogicalParent.UseBufferView(rawBufferData); var accessor = mesh.LogicalParent.CreateAccessor(); accessor.SetVertexData(bufferView, 0, buffer.Length / 4, DimensionType.VEC4, EncodingType.UNSIGNED_BYTE); primitive.SetVertexAccessor(accessorName, accessor); continue; } if (attribute.Name == "NORMAL" && DrawCall.IsCompressedNormalTangent(drawCall)) { var vectors = ToVector4Array(buffer); var(normals, tangents) = DecompressNormalTangents(vectors); primitive.WithVertexAccessor("NORMAL", normals); primitive.WithVertexAccessor("TANGENT", tangents); continue; } if (attribute.Name == "BLENDINDICES") { var byteBuffer = buffer.Select(f => (byte)f).ToArray(); var bufferView = mesh.LogicalParent.UseBufferView(byteBuffer); var accessor = mesh.LogicalParent.CreateAccessor(); accessor.SetVertexData(bufferView, 0, buffer.Length / 4, DimensionType.VEC4, EncodingType.UNSIGNED_BYTE); primitive.SetVertexAccessor(accessorName, accessor); continue; } if (attribute.Name == "TEXCOORD" && numComponents != 2) { // We are ignoring some data, but non-2-component UVs cause failures in gltf consumers continue; } switch (numComponents) { case 4: { var vectors = ToVector4Array(buffer); primitive.WithVertexAccessor(accessorName, vectors); break; } case 3: { var vectors = ToVector3Array(buffer); primitive.WithVertexAccessor(accessorName, vectors); break; } case 2: { var vectors = ToVector2Array(buffer); primitive.WithVertexAccessor(accessorName, vectors); break; } case 1: { primitive.WithVertexAccessor(accessorName, buffer); break; } default: throw new NotImplementedException($"Attribute \"{attribute.Name}\" has {numComponents} components"); } } // For some reason soruce models can have joints but no weights, check if that is the case var jointAccessor = primitive.GetVertexAccessor("JOINTS_0"); if (jointAccessor != null && primitive.GetVertexAccessor("WEIGHTS_0") == null) { // If this occurs, give default weights var defaultWeights = Enumerable.Repeat(Vector4.UnitX, jointAccessor.Count).ToList(); primitive.WithVertexAccessor("WEIGHTS_0", defaultWeights); } // Set index buffer var startIndex = (int)drawCall.GetIntegerProperty("m_nStartIndex"); var indexCount = (int)drawCall.GetIntegerProperty("m_nIndexCount"); var indices = ReadIndices(indexBuffer, startIndex, indexCount); primitive.WithIndicesAccessor(PrimitiveType.TRIANGLES, indices); // Add material var materialPath = drawCall.GetProperty <string>("m_material"); ProgressDialog.SetProgress($"Loading material: {materialPath}"); var materialResource = GuiContext.LoadFileByAnyMeansNecessary(materialPath + "_c"); if (materialResource == null) { continue; } var renderMaterial = (VMaterial)materialResource.DataBlock; var materialNameTrimmed = Path.GetFileNameWithoutExtension(materialPath); var bestMaterial = GenerateGLTFMaterialFromRenderMaterial(renderMaterial, model, materialNameTrimmed); primitive.WithMaterial(bestMaterial); } } return(mesh); }