private int FindNearestSourceVertex(int subMeshIndex, Vector3 vertex) { DebugLog("FindNearestSourceVertex(" + subMeshIndex + ", " + V3ToStr(vertex)); SubMeshInfo smi = m_sourceSubMeshes[subMeshIndex]; int bestIndex = smi.startIndex; Vector3 bestVertex = sourceMesh.vertices[bestIndex]; float bestMagnitude = (bestVertex - vertex).magnitude; for (int i = smi.startIndex; i < smi.endIndex; i++) { //DebugLog("i=" + i); Vector3 nextVertex = sourceMesh.vertices[i]; float nextMagnitude = (nextVertex - vertex).magnitude; if (nextMagnitude < bestMagnitude) { //DebugLog("better! i=" + i + " v=" + V3ToStr(nextVertex)); bestIndex = i; bestVertex = nextVertex; bestMagnitude = nextMagnitude; } } DebugLog("Returning " + bestIndex); return(bestIndex); }
/// <summary> /// サブメッシュのリストを取得する /// </summary> /// <param name="mesh"></param> /// <returns></returns> private List <SubMeshInfo> GetSubMeshList(Mesh mesh) { List <SubMeshInfo> subMeshList = new List <SubMeshInfo>(); for (int subMeshIndex = 0; subMeshIndex < mesh.subMeshCount; subMeshIndex++) { var meshInfo = new SubMeshInfo(mesh, subMeshIndex); subMeshList.Add(meshInfo); } return(subMeshList); }
public MeshGeometry Clone(string id, GeometrySet geoSet) { MeshGeometry clone = new MeshGeometry(id, geoSet); foreach (int ii in this.inputSources.Keys) { clone.AddInputs(ii, this.inputSources[ii]); } foreach (PointComponents pc in this.pointSets) { clone.pointSets.Add(pc); } foreach (int[] f in this.faces) { clone.faces.Add(f); } foreach (string vs in this.vertexDict.Keys) { clone.vertexDict[vs] = this.vertexDict[vs]; } foreach (int vi in this.vertexIds.Keys) { clone.vertexIds[vi] = this.vertexIds[vi]; } foreach (VertexDataEntry vde in this.vertexDataEntries) { clone.vertexDataEntries.Add(vde.Clone()); } clone.VertexData = this.VertexData.Clone(); if (this.boneAssignmentList != null) { foreach (int vba in this.boneAssignmentList.Keys) { clone.boneAssignmentList[vba] = this.boneAssignmentList[vba]; } } int smi_count = 0; foreach (SubMeshInfo smi in this.subMeshes) { SubMeshInfo new_smi = new SubMeshInfo(); new_smi.name = this.subMeshes.Count > 1 ? id + "." + (smi_count++).ToString() : id; new_smi.material = smi.material; clone.subMeshes.Add(new_smi); } return(clone); }
private void CopyBlendShapesOfFrame(string shapeName, int shapeIndex, int frameIndex) { Vector3[] sourceDeltaVertices = new Vector3[sourceMesh.vertexCount]; Vector3[] sourceDeltaNormals = new Vector3[sourceMesh.vertexCount]; Vector3[] sourceDeltaTangents = new Vector3[sourceMesh.vertexCount]; Vector3[] targetDeltaVertices = new Vector3[targetMesh.vertexCount]; Vector3[] targetDeltaNormals = new Vector3[targetMesh.vertexCount]; Vector3[] targetDeltaTangents = new Vector3[targetMesh.vertexCount]; float frameWeight = sourceMesh.GetBlendShapeFrameWeight(shapeIndex, frameIndex); sourceMesh.GetBlendShapeFrameVertices(shapeIndex, frameIndex, sourceDeltaVertices, sourceDeltaNormals, sourceDeltaTangents); string debugOut = ""; for (int sm = 0; sm < m_targetSubMeshes.Length; sm++) { SubMeshInfo targetSm = m_targetSubMeshes[sm]; SetStatusMessage("Copying sub mesh " + targetSm.name); // Convert Target vertex to an approximate location in the source mesh. for (int i = targetSm.startIndex; i < targetSm.endIndex; i++) { SetStatusMessage("Copying mesh " + targetSm.name + ", vertext " + i); Vector3 targetVertex = targetMesh.vertices[i]; Vector3 sourceVertex = m_targetToSourceWarps[sm](targetVertex); //Vector3 sourceVertex = targetVertex; debugOut += "WARP: " + V3ToStr(targetVertex) + " -> " + V3ToStr(sourceVertex) + "\n"; // Find index of nearest vertex in source mesh. int nearest = FindNearestSourceVertex(sm, sourceVertex); // Copy details from that source to target blend shape. targetDeltaVertices[i] = sourceDeltaVertices[nearest]; targetDeltaNormals[i] = sourceDeltaNormals[nearest]; targetDeltaTangents[i] = sourceDeltaTangents[nearest]; } } SetStatusMessage("Finished copying " + shapeName); DebugLog(debugOut); targetMesh.AddBlendShapeFrame(shapeName, frameWeight, targetDeltaVertices, targetDeltaNormals, targetDeltaTangents); }
private static SubMeshInfo[] LocateSubMeshes(Mesh mesh) { var subMeshes = new SubMeshInfo[9]; // For now this is a bit hacky - can improve over time if needed. // If VRoid character has 9 meshes, then the ears have been merged into the face already. // If 10 meshes, index 7 and 8 are face and ears - lets merge them together. // Some tools merge them, so let's work with those tools as well. int j = 0; for (int i = 0; i < mesh.subMeshCount; i++) { UnityEngine.Rendering.SubMeshDescriptor smd = mesh.GetSubMesh(i); SubMeshInfo smi = new SubMeshInfo(); smi.name = m_subMeshNames[j]; smi.startIndex = smd.firstVertex; // Or is it indexStart? smi.endIndex = smd.firstVertex + smd.vertexCount; smi.bounds = smd.bounds; // HACK: If size 10, do some magic at index 7 (face) to include following submesh (ears) // They share the same material and some tools merge them. // (If VRoid changes the order of subMeshes this will stuff things up big time!) if (i == 7 && mesh.subMeshCount == 10) { i++; smd = mesh.GetSubMesh(i); smi.bounds.Encapsulate(smd.bounds); smi.endIndex = smd.firstVertex + smd.vertexCount; } subMeshes[j++] = smi; } return(subMeshes); }
/// <summary> /// Initializes the current instance with values from specified prefab. /// </summary> /// <param name="prefab">The prefab.</param> protected override bool InitializeData(PrefabInfo prefab) { bool success = base.InitializeData(prefab); BuildingInfo building = (BuildingInfo)prefab; if (building.m_class != null && building.m_class.m_service != ItemClass.Service.None && building.m_class.m_service <= ItemClass.Service.Office && building.m_placementStyle == ItemClass.Placement.Automatic && building.m_cellWidth > 0 && building.m_cellWidth <= 4 && building.m_cellLength > 0 && building.m_cellLength <= 4 && ItemClass.GetPrivateServiceIndex(building.m_class.m_service) != -1) { this.type = AssetTypes.Growable; } else { this.type = AssetTypes.Building; } if (building.m_props != null) { for (int i = 0; i < building.m_props.Length; i++) { if (building.m_props[i] != null) { if ((UnityEngine.Object)building.m_props[i].m_prop != (UnityEngine.Object)null) { this.AddReferencedAsset <PropInfo>(Reference.ReferenceTypes.Prop, building.m_props[i].m_prop); } if ((UnityEngine.Object)building.m_props[i].m_tree != (UnityEngine.Object)null) { this.AddReferencedAsset <TreeInfo>(Reference.ReferenceTypes.Tree, building.m_props[i].m_tree); } } } } if (building.m_subMeshes != null) { for (int i = 0; i < building.m_subMeshes.Length; i++) { if (building.m_subMeshes[i] != null && (UnityEngine.Object)building.m_subMeshes[i].m_subInfo != (UnityEngine.Object)null && building.m_subMeshes[i].m_subInfo is BuildingInfoSub) { AssetInfo subAsset = new SubMeshInfo((BuildingInfoSub)building.m_subMeshes[i].m_subInfo); if (subAsset.Initialized) { this.Add(subAsset); } } } } if (building.m_subBuildings != null) { for (int i = 0; i < building.m_subBuildings.Length; i++) { if (building.m_subBuildings[i] != null && (UnityEngine.Object)building.m_subBuildings[i].m_buildingInfo != (UnityEngine.Object)null) { this.AddReferencedAsset <BuildingInfo>(Reference.ReferenceTypes.SubAssset, building.m_subBuildings[i].m_buildingInfo); AssetInfo subAsset = new SubBuildingInfo(building.m_subBuildings[i].m_buildingInfo); if (subAsset.Initialized) { this.Add(subAsset); // todo: Add references. } } } } return(success); }
/// <summary> /// ReadPolygons basically corresponds to reading in a SubMesh. /// The grandparent of this node is probably the geometry node /// with the submesh name. /// </summary> /// <param name="node">The node corresponding to the 'polygons' element</param> public void ReadPolygons( MeshGeometry geometry, Dictionary<string, VertexSet> vertexSets, XmlNode node, ColladaMeshInfo meshInfo ) { bool doubleSided = false; Dictionary<int, List<InputSourceCollection>> inputSources = new Dictionary<int, List<InputSourceCollection>>(); // First pass to get params and inputs foreach( XmlNode childNode in node.ChildNodes ) { switch( childNode.Name ) { case "param": if( childNode.Attributes[ "name" ].Value == "DOUBLE_SIDED" ) doubleSided = bool.Parse( childNode.InnerText ); break; case "input": ReadInput( inputSources, vertexSets, childNode, meshInfo ); break; case "p": // ignore on this pass break; default: DebugMessage( childNode ); break; } } foreach( int inputIndex in inputSources.Keys ) geometry.AddInputs( inputIndex, inputSources[ inputIndex ] ); // TODO: If we are double sided, we probably need to build a // negated version of the normals. // second pass to handle the 'p' entries foreach( XmlNode childNode in node.ChildNodes ) { switch( childNode.Name ) { case "param": case "input": // ignore on this pass break; case "p": ReadPolygon( geometry, doubleSided, childNode ); break; default: DebugMessage( childNode ); break; } } string materialId = null; string submeshName = geometry.Id; if( node.Attributes[ "material" ] != null && node.Attributes[ "material" ].Value != null ) { materialId = node.Attributes[ "material" ].Value; // strip off the leading '#' if( materialId.StartsWith( "#" ) ) { log.InfoFormat( "Material {0} starts with '#'", materialId ); materialId = materialId.Substring( 1 ); } // I used to append the material name to the submesh name, // but now I want to leave it alone. //submeshName = submeshName + "/" + materialId; } SubMeshInfo smInfo = new SubMeshInfo(); smInfo.name = submeshName; if( materialId != null ) { if( MaterialScriptBuilder.MaterialNamespace != null ) smInfo.material = MaterialScriptBuilder.MaterialNamespace + "." + materialId; else smInfo.material = materialId; } else { smInfo.material = "BaseWhite"; } geometry.AddSubMesh( smInfo ); }
private void Render(NativeArray <UIVertexData> vertices, UIContextData *context, ref MeshData meshData, UIGraphData graph, NativeArray <NodeInfo> layout, GraphInfo graphInfo, NativeArray <UIPassState> stateLayout) { var indices = meshData.GetIndexData <ushort>(); var subMeshes = new NativeArray <SubMeshInfo>(graphInfo.subMeshCount, Allocator.Temp); int submeshIndex = 0; int renderIndex = 0; float4 bounds = float4.zero; RenderMesh(0, -1, 0, vertices, context, indices, graph, graphInfo, layout, stateLayout, subMeshes, true, true, true, ref submeshIndex, ref renderIndex, ref bounds); float4 totalBounds = bounds; int submesh0RenderIndexCount = renderIndex; for (int i = 0; i < subMeshes.Length; i++) { SubMeshInfo current = subMeshes[i]; var initialRenderIndex = renderIndex; RenderMesh(current.nodeIndex, -1, current.nodeIndex, vertices, context, indices, graph, graphInfo, layout, stateLayout, subMeshes, true, false, false, ref submeshIndex, ref renderIndex, ref bounds); totalBounds = new float4(math.min(totalBounds.x, bounds.x), math.min(totalBounds.y, bounds.y), math.max(totalBounds.z, bounds.z), math.max(totalBounds.w, bounds.w)); current.meshIndexStart = initialRenderIndex * 6; current.meshIndexCount = (renderIndex - initialRenderIndex) * 6; current.bounds = bounds; subMeshes[i] = current; for (int j = 0; j < (renderIndex - initialRenderIndex); j++) { for (int k = 0; k < 4; k++) { UIVertexData vertex = vertices[(initialRenderIndex + j) * 4 + k]; vertex.position.z -= 0.001f * (i + 1); vertices[(initialRenderIndex + j) * 4 + k] = vertex; } } } //Center Mesh float3 totalSize = new float3(math.abs(totalBounds.z - totalBounds.x), math.abs(totalBounds.y - totalBounds.w), 0f); var adjust = new float3(totalSize.x / 2f, totalSize.y / 2f, 0); for (int i = 0; i < vertices.Length; i++) { UIVertexData vertex = vertices[i]; vertex.position -= adjust; vertices[i] = vertex; } for (int i = 0; i < subMeshes.Length; i++) { SubMeshInfo current = subMeshes[i]; var size = new float3(math.abs(current.bounds.z - current.bounds.x), math.abs(current.bounds.y - current.bounds.w), 0.00001f); meshData.SetSubMesh(meshData.subMeshCount - (i + 1), new UnityEngine.Rendering.SubMeshDescriptor(current.meshIndexStart, current.meshIndexCount) { //bounds = new Bounds(new float3(current.bounds.x + (size.x / 2f), bounds.y + (size.y / 2f), 0f) - adjust, size), bounds = new Bounds(float3.zero, size), firstVertex = (current.meshIndexStart / 6) * 4, vertexCount = (current.meshIndexCount / 6) * 4 } //,MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices ); } meshData.SetSubMesh(0, new UnityEngine.Rendering.SubMeshDescriptor(0, submesh0RenderIndexCount * 6) { bounds = new Bounds(float3.zero, new float3(totalSize.x, totalSize.y, 0.00001f)), firstVertex = 0, vertexCount = submesh0RenderIndexCount * 4 } //,MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontValidateIndices ); subMeshes.Dispose(); }
private void RenderMesh( int startIndex, int parentIndex, int currentIndex, NativeArray <UIVertexData> vertexData, UIContextData *context, NativeArray <ushort> indices, UIGraphData graph, GraphInfo graphInfo, NativeArray <NodeInfo> nodeInfo, NativeArray <UIPassState> stateLayout, NativeArray <SubMeshInfo> subMeshes, bool renderNow, bool updateSubmeshCount, bool accumulate, ref int subMeshIndex, ref int renderIndex, ref float4 bounds ) { var info = nodeInfo[currentIndex]; HeaderConfig *headerConfig = (HeaderConfig *)(graph.value + info.nodeOffset).ToPointer(); var state = stateLayout[currentIndex]; if (accumulate) { state.globalBox += state.localBox; if (parentIndex >= 0) { state.globalBox += stateLayout[parentIndex].inner; } stateLayout[currentIndex] = state; } if (headerConfig->IsDedicatedNode) { if (updateSubmeshCount) { subMeshes[subMeshIndex] = new SubMeshInfo(++subMeshIndex, currentIndex); } renderNow = currentIndex == startIndex; } if (renderNow) { bool display = true; bool visible = true; if (graph.TryGetConfigBlock(currentIndex, UIConfigLayoutTable.DisplayConfig, out IntPtr displayConfig)) { var dc = ((DisplayConfig *)displayConfig.ToPointer()); display = dc->display == VisibilityStyle.Visible; visible = dc->visible == VisibilityStyle.Visible; } if (display) { FunctionPointer <UIRenderPass> render = headerConfig->schemaIndex >= 0 ? schema.Value.elements[headerConfig->schemaIndex].render : default; if (render.IsCreated) { render.Invoke( graph.value, (NodeInfo *)UnsafeUtility.AddressOf(ref info), (UIPassState *)UnsafeUtility.AddressOf(ref state), (UIVertexData *)(((IntPtr)vertexData.GetUnsafePtr()) + (renderIndex * UnsafeUtility.SizeOf <UIVertexData>() * 4)).ToPointer(), context ); } for (int j = 0; j < info.renderBoxCount; j++) { indices[(renderIndex + j) * 6] = (ushort)((renderIndex + j) * 4); indices[((renderIndex + j) * 6) + 1] = (ushort)(((renderIndex + j) * 4) + 2); indices[((renderIndex + j) * 6) + 2] = (ushort)(((renderIndex + j) * 4) + 1); indices[((renderIndex + j) * 6) + 3] = (ushort)(((renderIndex + j) * 4) + 2); indices[((renderIndex + j) * 6) + 4] = (ushort)(((renderIndex + j) * 4) + 3); indices[((renderIndex + j) * 6) + 5] = (ushort)(((renderIndex + j) * 4) + 1); UpdateBounds(vertexData, (renderIndex + j) * 4, ref bounds); } } if (!display || !visible) { UnsafeUtility.MemClear((((IntPtr)vertexData.GetUnsafePtr()) + (renderIndex * UnsafeUtility.SizeOf <UIVertexData>() * 4)).ToPointer(), UnsafeUtility.SizeOf <UIVertexData>() * info.renderBoxCount * 4); UnsafeUtility.MemClear((((IntPtr)indices.GetUnsafePtr()) + (renderIndex * UnsafeUtility.SizeOf <ushort>() * 6)).ToPointer(), UnsafeUtility.SizeOf <ushort>() * info.renderBoxCount * 6); } renderIndex += info.renderBoxCount; } for (int i = 0; i < headerConfig->childCount; i++) { RenderMesh(startIndex, currentIndex, UnsafeUtility.ReadArrayElement <int>((graph.value + info.childrenOffset).ToPointer(), i), vertexData, context, indices, graph, graphInfo, nodeInfo, stateLayout, subMeshes, renderNow, updateSubmeshCount, accumulate, ref subMeshIndex, ref renderIndex, ref bounds); } }
/// <summary> /// Load the material and visibility information from SubMeshInfo into the actual subMesh /// </summary> /// <param name="subMeshInfo"></param> private void ValidateSubMesh(SubMeshInfo subMeshInfo) { entity.GetSubEntity(subMeshInfo.Name).IsVisible = subMeshInfo.Show; entity.GetSubEntity(subMeshInfo.Name).MaterialName = subMeshInfo.MaterialName; }
/// <summary> /// The geometry object has a list of polygon faces. /// Take those, and use them to populate the subMesh object. /// TODO: Do I need to compact those first? /// Do I need to build consolidated sets of points that the face indexes can refer to? /// </summary> /// <param name="subMesh">the Axiom SubMesh object that we will populate</param> /// <param name="geometry">the geometry information that contains the polygons</param> /// <param name="indexType">the type of face index (16 bit or 32 bit)</param> protected void ProcessFaces( SubMeshInfo subMeshInfo, MeshGeometry geometry, IndexType indexType ) { SubMesh subMesh = m_AxiomMesh.CreateSubMesh( subMeshInfo.name ); subMesh.MaterialName = subMeshInfo.material; int[ , ] data = geometry.GetFaceData(); subMesh.indexData.indexStart = 0; subMesh.indexData.indexCount = data.GetLength( 0 ) * data.GetLength( 1 ); HardwareIndexBuffer idxBuffer = null; // create the index buffer idxBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( indexType, subMesh.indexData.indexCount, m_AxiomMesh.IndexBufferUsage, m_AxiomMesh.UseIndexShadowBuffer ); HWBuffer.FillBuffer( idxBuffer, subMesh.indexData.indexCount, indexType, data ); // save the index buffer subMesh.indexData.indexBuffer = idxBuffer; }
private static void BuildSegmentIndices( Mesh mesh, out int[][] subMeshSegmentIndices, out HashSet <int>[] subMeshVertexIndices, out SubMeshInfo[] subMeshInfos) { int subMeshCount = mesh.subMeshCount; subMeshSegmentIndices = new int[subMeshCount][]; subMeshVertexIndices = new HashSet <int> [subMeshCount]; subMeshInfos = new SubMeshInfo[subMeshCount]; var indexPairs = new HashSet <int> [mesh.vertexCount]; for (int i = 0; i < subMeshCount; ++i) { MeshTopology topology = mesh.GetTopology(i); int[] indices = mesh.GetIndices(i); subMeshInfos[i] = new SubMeshInfo(topology, (uint)indices.Length); if (topology != MeshTopology.Triangles) { subMeshSegmentIndices[i] = new int[0]; subMeshVertexIndices[i] = new HashSet <int>(); continue; } for (int ti = 0; ti < indices.Length; ti += 3) { int i0 = indices[ti]; int i1 = indices[ti + 1]; int i2 = indices[ti + 2]; if (i1 < i0) { Swap(ref i0, ref i1); } if (i2 < i1) { Swap(ref i1, ref i2); if (i1 < i0) { Swap(ref i0, ref i1); } } var pair0 = indexPairs[i0] ?? (indexPairs[i0] = new HashSet <int>()); var pair1 = indexPairs[i1] ?? (indexPairs[i1] = new HashSet <int>()); var pair2 = indexPairs[i2] ?? (indexPairs[i2] = new HashSet <int>()); pair0.Add(i1); pair1.Add(i2); pair2.Add(i0); } var segmentIndices = new List <int>(); var vertexIndices = new HashSet <int>(); for (int startIndex = 0; startIndex < indexPairs.Length; ++startIndex) { HashSet <int> pairs = indexPairs[startIndex]; if (pairs == null || pairs.Count == 0) { continue; } vertexIndices.Add(startIndex); foreach (var endIndex in pairs) { segmentIndices.Add(startIndex); segmentIndices.Add(endIndex); vertexIndices.Add(endIndex); } } Array.Clear(indexPairs, 0, indexPairs.Length); subMeshSegmentIndices[i] = segmentIndices.ToArray(); subMeshVertexIndices[i] = vertexIndices; } }
public void AddSubMesh(SubMeshInfo subMesh) { subMeshes.Add(subMesh); }