internal void CacheHulls(ulong meshHash, HacdConvexHull[] retHulls) { //write each state to disk SQLiteTransaction transaction = _connection.BeginTransaction(); try { this.ClearExistingHulls(meshHash); foreach (HacdConvexHull hull in retHulls) { this.WriteHullRow(meshHash, hull); hull._rawVerts = null; } transaction.Commit(); _memCache.Add(meshHash, HacdConvexHull.CloneHullArray(retHulls)); } catch { transaction.Rollback(); throw; } }
private void WriteHullRow(ulong meshHash, HacdConvexHull hull) { using (MemoryStream ms = new MemoryStream()) { ProtoBuf.Serializer.Serialize(ms, hull); const string INSERT_CMD = "INSERT INTO Hulls(hash, hull_data) VALUES(@hhash, @hullData)"; using (SQLiteCommand cmd = new SQLiteCommand(INSERT_CMD, _connection)) { SQLiteParameter hashParam = cmd.CreateParameter(); hashParam.ParameterName = "@hhash"; hashParam.DbType = System.Data.DbType.Int64; hashParam.Value = (Int64)meshHash; SQLiteParameter hullDataParam = cmd.CreateParameter(); hullDataParam.ParameterName = "@hullData"; hullDataParam.Value = ms.ToArray(); cmd.Parameters.Add(hashParam); cmd.Parameters.Add(hullDataParam); cmd.ExecuteNonQuery(); } } }
public bool TryGetHulls(ulong meshHash, out HacdConvexHull[] cachedHulls) { HacdConvexHull[] memHulls; if (_memCache.TryGetValue(meshHash, out memHulls)) { //we must clone here because the hulls will be scaled when they're used which would //change the values in this, inmemory, unscaled array cachedHulls = HacdConvexHull.CloneHullArray(memHulls); return(true); } const string FIND_QRY = "SELECT hull_data FROM Hulls WHERE hash = @hhash"; using (SQLiteCommand cmd = new SQLiteCommand(FIND_QRY, _connection)) { SQLiteParameter hashParam = cmd.CreateParameter(); hashParam.ParameterName = "@hhash"; hashParam.DbType = System.Data.DbType.Int64; hashParam.Value = (Int64)meshHash; cmd.Parameters.Add(hashParam); using (SQLiteDataReader reader = cmd.ExecuteReader()) { if (!reader.HasRows) { cachedHulls = null; return(false); } List <HacdConvexHull> retHulls = new List <HacdConvexHull>(); while (reader.Read()) { byte[] buffer = (byte[])reader[0]; using (MemoryStream hullStream = new MemoryStream(buffer)) { HacdConvexHull hull = ProtoBuf.Serializer.Deserialize <HacdConvexHull>(hullStream); if (hull == null) { throw new Exception("Protobuf deserialization of convex hull failed"); } hull.FillVerticesFromRaw(); retHulls.Add(hull); } } cachedHulls = retHulls.ToArray(); _memCache.Add(meshHash, HacdConvexHull.CloneHullArray(cachedHulls)); return(true); } } }
public static void Scale(OpenMetaverse.Vector3 scale, HacdConvexHull[] hulls) { foreach (HacdConvexHull hull in hulls) { PhysX.Math.Vector3[] vertices = hull.Vertices; for (int i = 0; i < vertices.Length; ++i) { PhysX.Math.Vector3 vert = vertices[i]; vert.X *= scale.X; vert.Y *= scale.Y; vert.Z *= scale.Z; vertices[i] = vert; } } }
public static HacdConvexHull[] CloneHullArray(HacdConvexHull[] hulls) { HacdConvexHull[] retHulls = new HacdConvexHull[hulls.Length]; for (int i = 0; i < hulls.Length; ++i) { HacdConvexHull nextHull = hulls[i]; HacdConvexHull newHull = new HacdConvexHull(); newHull.Indicies = (int[])nextHull.Indicies.Clone(); newHull.Vertices = new PhysX.Math.Vector3[nextHull.Vertices.Length]; for (int j = 0; j < nextHull.Vertices.Length; j++) { PhysX.Math.Vector3 vec = nextHull.Vertices[j]; newHull.Vertices[j] = new PhysX.Math.Vector3(vec.X, vec.Y, vec.Z); } retHulls[i] = newHull; } return(retHulls); }
public static HacdConvexHull[] CloneHullArray(HacdConvexHull[] hulls) { HacdConvexHull[] retHulls = new HacdConvexHull[hulls.Length]; for (int i = 0; i < hulls.Length; ++i) { HacdConvexHull nextHull = hulls[i]; HacdConvexHull newHull = new HacdConvexHull(); newHull.Indicies = (int[])nextHull.Indicies.Clone(); newHull.Vertices = new PhysX.Math.Vector3[nextHull.Vertices.Length]; for (int j = 0; j < nextHull.Vertices.Length; j++) { PhysX.Math.Vector3 vec = nextHull.Vertices[j]; newHull.Vertices[j] = new PhysX.Math.Vector3(vec.X, vec.Y, vec.Z); } retHulls[i] = newHull; } return retHulls; }
public static HacdConvexHull[] DecomposeToConvexHulls(ulong meshHash, bool useCache, HacdPreset preset, float[] verts, int[] indicies) { if (verts.Length % 3 != 0) { throw new InvalidOperationException("Number of verticies must be divisble by 3"); } if (indicies.Length % 3 != 0) { throw new InvalidOperationException("Number of indicies must be divisble by 3"); } if (IsCacheCandidate(useCache, verts.Length)) { //try cache try { HacdConvexHull[] cachedHulls; if (MeshingStage.HullCache.TryGetHulls(meshHash, out cachedHulls)) { return(cachedHulls); } } catch (Exception e) { m_log.ErrorFormat("[InWorldz.PhysX.HACD] Failure retrieving HACD hulls from cache: {0}: {1}", e, e.Message); } } IntPtr session = Decompose(verts, indicies, verts.Length, indicies.Length, preset.DEFAULT_CC_CONNECT_DIST, preset.MIN_HULL_COUNT, preset.CONCAVITY, preset.TARGET_TRIANGLES_IN_FULL_MESH, preset.MAX_VERTS_PER_HULL, true, true, preset.VOLUME_WEIGHT, preset.SMALL_CLUSTER_THRESHOLD); if (session == IntPtr.Zero) { return(null); } HacdConvexHull[] retHulls; try { int hullCount = GetConvexHullCount(session); retHulls = new HacdConvexHull[hullCount]; for (int hullNum = 0; hullNum < hullCount; ++hullNum) { int vertexCount = GetVertexCount(session, hullNum); int indexCount = GetIndexCount(session, hullNum); float[] hullVerts = new float[vertexCount]; int[] hullIndexes = new int[indexCount]; if (!GetConvexVertsAndIndexes(session, hullNum, hullVerts, hullIndexes)) { return(null); } HacdConvexHull hull = new HacdConvexHull { Vertices = PhysUtil.FloatArrayToVectorArray(hullVerts), _rawVerts = IsCacheCandidate(useCache, verts.Length) ? hullVerts : null, Indicies = hullIndexes }; retHulls[hullNum] = hull; } //store in cache for later if (IsCacheCandidate(useCache, verts.Length)) { try { MeshingStage.HullCache.CacheHulls(meshHash, retHulls); } catch (Exception e) { m_log.ErrorFormat("[InWorldz.PhysX.HACD] Failure storing HACD results in cache: {0}: {1}", e, e.Message); } } return(retHulls); } finally { FreeSession(session); } }
public HacdConvexHull[] DecomposeToConvexHulls(ulong meshHash, bool useCache, List <float3> convVertices, List <int> convIndices) { if (convIndices.Count % 3 != 0) { throw new InvalidOperationException("Number of indicies must be divisble by 3"); } if (IsCacheCandidate(useCache, convVertices.Count)) { //try cache try { HacdConvexHull[] cachedHulls; if (MeshingStage.HullCache.TryGetHulls(meshHash, out cachedHulls)) { return(cachedHulls); } } catch (Exception e) { m_log.ErrorFormat("[InWorldz.PhysX.RatcliffACD] Failure retrieving HACD hulls from cache: {0}: {1}", e, e.Message); } } ConvexBuilder builder = new ConvexBuilder(HullReturn); m_hulls = new List <ConvexResult>(); DecompDesc dcomp = new DecompDesc(); dcomp.mIndices = convIndices; dcomp.mVertices = convVertices; builder.process(dcomp); var retHulls = new HacdConvexHull[m_hulls.Count]; for (int i = 0; i < m_hulls.Count; i++) { ConvexResult hull = m_hulls[i]; float[] rawVerts = null; if (IsCacheCandidate(useCache, convVertices.Count)) { rawVerts = new float[hull.HullVertices.Count * 3]; } PhysX.Math.Vector3[] hullVerts = new PhysX.Math.Vector3[hull.HullVertices.Count]; for (int j = 0; j < hull.HullVertices.Count; j++) { hullVerts[j] = new PhysX.Math.Vector3(hull.HullVertices[j].x, hull.HullVertices[j].y, hull.HullVertices[j].z); if (rawVerts != null) { rawVerts[j * 3 + 0] = hull.HullVertices[j].x; rawVerts[j * 3 + 1] = hull.HullVertices[j].y; rawVerts[j * 3 + 2] = hull.HullVertices[j].z; } } retHulls[i] = new HacdConvexHull { Indicies = hull.HullIndices.ToArray(), Vertices = hullVerts, _rawVerts = rawVerts, }; } //store in cache for later if (IsCacheCandidate(useCache, convVertices.Count)) { try { MeshingStage.HullCache.CacheHulls(meshHash, retHulls); } catch (Exception e) { m_log.ErrorFormat("[InWorldz.PhysX.RatcliffACD] Failure storing HACD results in cache: {0}: {1}", e, e.Message); } } return(retHulls); }
private List <PhysX.ConvexMeshGeometry> GenerateComplexPhysXShape(ulong meshHash, string primName, PrimitiveBaseShape shape, OpenMetaverse.Vector3 size, float LOD, bool isDynamic) { //create the mesh and do not prescale it. the ACD algorithm can then cache the output hulls and //scale as appropriate MeshingResult result = _mesher.CreateMesh(primName, shape, size, LOD, ShapeType.DecomposedConvexHulls, false); if (result == null) { return(null); } HacdConvexHull[] hulls = null; if (result.ResultType == ShapeType.TriMesh) { IMesh mesh = result.TriMesh; if (mesh == null) { return(null); } //Debugging.VrmlGenerator.SaveToVrmlFile("lastMesh.wrl", mesh.getVertexListAsArray(), mesh.getTriangleList()); switch (ShapeDeterminer.FindBestAcdAlgorithm(shape)) { case ShapeDeterminer.AcdAlgorithm.HACD: hulls = DecomposeWithHACD(shape, LOD, mesh); break; case ShapeDeterminer.AcdAlgorithm.RATCLIFF: hulls = DecomposeWithRatcliff(shape, LOD, mesh); break; default: throw new PhysxSdkException("GenerateComplexPhysXShape(): Specified ACD algorithm does not exist"); } if (hulls == null) { return(null); } } else if (result.ResultType == ShapeType.DecomposedConvexHulls) { hulls = new HacdConvexHull[result.ConvexVerts.Count]; for (int i = 0; i < result.ConvexVerts.Count; i++) { hulls[i] = new HacdConvexHull { Vertices = new PhysX.Math.Vector3[result.ConvexVerts[i].Count] }; for (int j = 0; j < result.ConvexVerts[i].Count; j++) { var vert = result.ConvexVerts[i][j]; hulls[i].Vertices[j] = new PhysX.Math.Vector3(vert.X, vert.Y, vert.Z); } } } else { return(null); } HacdConvexHull.Scale(size, hulls); List <PhysX.ConvexMeshGeometry> ret = new List <PhysX.ConvexMeshGeometry>(); try { foreach (HacdConvexHull hull in hulls) { PhysX.ConvexMeshDesc convexMeshDesc = new PhysX.ConvexMeshDesc() { Flags = PhysX.ConvexFlag.InflateConvex }; if (hull.Indicies == null) { convexMeshDesc.Flags |= PhysX.ConvexFlag.ComputeConvex; } convexMeshDesc.SetPositions(hull.Vertices); if (hull.Indicies != null) { convexMeshDesc.SetTriangles(hull.Indicies); } if (!convexMeshDesc.IsValid()) { throw new PhysxSdkException("GenerateComplexPhysXShape: Convex mesh description is invalid"); } using (MemoryStream ms = new MemoryStream()) { if (!_cooking.CookConvexMesh(convexMeshDesc, ms)) { throw new PhysxSdkException("GenerateComplexPhysXShape: CookConvexMesh() failed"); } ms.Position = 0; PhysX.ConvexMesh convexMesh = _scene.Physics.CreateConvexMesh(ms); PhysX.ConvexMeshGeometry convexShapeGeom = new PhysX.ConvexMeshGeometry(convexMesh); ret.Add(convexShapeGeom); } } } catch (Exception e) { m_log.WarnFormat("[InWorldz.PhysxPhysics] Unable to create convex hullset for shape: {0}", e); result = _mesher.CreateMesh(primName, shape, size, LOD, ShapeType.SingleConvex, true); if (result == null) { m_log.WarnFormat("[InWorldz.PhysxPhysics] Fallback hull generation failed, giving up", e); return(null); } //direct convex available? if (result.ResultType == ShapeType.SingleConvex) { if (!TryGenerateFallbackHullFromHullData(ret, e, result.SingleConvex)) { return(null); } } else if (result.ResultType == ShapeType.TriMesh) { IMesh mesh = result.TriMesh; if (mesh == null) { m_log.WarnFormat("[InWorldz.PhysxPhysics] Fallback hull generation failed, giving up", e); return(null); } if (!TryGenerateFallbackHullFromTrimesh(ret, e, mesh)) { return(null); } } } return(ret); }
private List<PhysX.ConvexMeshGeometry> GenerateComplexPhysXShape(ulong meshHash, string primName, PrimitiveBaseShape shape, OpenMetaverse.Vector3 size, float LOD, bool isDynamic) { //create the mesh and do not prescale it. the ACD algorithm can then cache the output hulls and //scale as appropriate MeshingResult result = _mesher.CreateMesh(primName, shape, size, LOD, ShapeType.DecomposedConvexHulls, false); if (result == null) return null; HacdConvexHull[] hulls = null; if (result.ResultType == ShapeType.TriMesh) { IMesh mesh = result.TriMesh; if (mesh == null) return null; //Debugging.VrmlGenerator.SaveToVrmlFile("lastMesh.wrl", mesh.getVertexListAsArray(), mesh.getTriangleList()); switch (ShapeDeterminer.FindBestAcdAlgorithm(shape)) { case ShapeDeterminer.AcdAlgorithm.HACD: hulls = DecomposeWithHACD(shape, LOD, mesh); break; case ShapeDeterminer.AcdAlgorithm.RATCLIFF: hulls = DecomposeWithRatcliff(shape, LOD, mesh); break; default: throw new PhysxSdkException("GenerateComplexPhysXShape(): Specified ACD algorithm does not exist"); } if (hulls == null) { return null; } } else if (result.ResultType == ShapeType.DecomposedConvexHulls) { hulls = new HacdConvexHull[result.ConvexVerts.Count]; for (int i = 0; i < result.ConvexVerts.Count; i++) { hulls[i] = new HacdConvexHull { Vertices = new PhysX.Math.Vector3[result.ConvexVerts[i].Count] }; for (int j = 0; j < result.ConvexVerts[i].Count; j++) { var vert = result.ConvexVerts[i][j]; hulls[i].Vertices[j] = new PhysX.Math.Vector3(vert.X, vert.Y, vert.Z); } } } else { return null; } HacdConvexHull.Scale(size, hulls); List<PhysX.ConvexMeshGeometry> ret = new List<PhysX.ConvexMeshGeometry>(); try { foreach (HacdConvexHull hull in hulls) { PhysX.ConvexMeshDesc convexMeshDesc = new PhysX.ConvexMeshDesc() { Flags = PhysX.ConvexFlag.InflateConvex }; if (hull.Indicies == null) convexMeshDesc.Flags |= PhysX.ConvexFlag.ComputeConvex; convexMeshDesc.SetPositions(hull.Vertices); if (hull.Indicies != null) convexMeshDesc.SetTriangles(hull.Indicies); if (!convexMeshDesc.IsValid()) { throw new PhysxSdkException("GenerateComplexPhysXShape: Convex mesh description is invalid"); } using (MemoryStream ms = new MemoryStream()) { if (!_cooking.CookConvexMesh(convexMeshDesc, ms)) { throw new PhysxSdkException("GenerateComplexPhysXShape: CookConvexMesh() failed"); } ms.Position = 0; PhysX.ConvexMesh convexMesh = _scene.Physics.CreateConvexMesh(ms); PhysX.ConvexMeshGeometry convexShapeGeom = new PhysX.ConvexMeshGeometry(convexMesh); ret.Add(convexShapeGeom); } } } catch (Exception e) { m_log.WarnFormat("[InWorldz.PhysxPhysics] Unable to create convex hullset for shape: {0}", e); result = _mesher.CreateMesh(primName, shape, size, LOD, ShapeType.SingleConvex, true); if (result == null) { m_log.WarnFormat("[InWorldz.PhysxPhysics] Fallback hull generation failed, giving up", e); return null; } //direct convex available? if (result.ResultType == ShapeType.SingleConvex) { if (!TryGenerateFallbackHullFromHullData(ret, e, result.SingleConvex)) { return null; } } else if (result.ResultType == ShapeType.TriMesh) { IMesh mesh = result.TriMesh; if (mesh == null) { m_log.WarnFormat("[InWorldz.PhysxPhysics] Fallback hull generation failed, giving up", e); return null; } if (!TryGenerateFallbackHullFromTrimesh(ret, e, mesh)) { return null; } } } return ret; }
public HacdConvexHull[] DecomposeToConvexHulls(ulong meshHash, bool useCache, List<float3> convVertices, List<int> convIndices) { if (convIndices.Count % 3 != 0) throw new InvalidOperationException("Number of indicies must be divisble by 3"); if (IsCacheCandidate(useCache, convVertices.Count)) { //try cache try { HacdConvexHull[] cachedHulls; if (MeshingStage.HullCache.TryGetHulls(meshHash, out cachedHulls)) { return cachedHulls; } } catch (Exception e) { m_log.ErrorFormat("[InWorldz.PhysX.RatcliffACD] Failure retrieving HACD hulls from cache: {0}: {1}", e, e.Message); } } ConvexBuilder builder = new ConvexBuilder(HullReturn); m_hulls = new List<ConvexResult>(); DecompDesc dcomp = new DecompDesc(); dcomp.mIndices = convIndices; dcomp.mVertices = convVertices; builder.process(dcomp); var retHulls = new HacdConvexHull[m_hulls.Count]; for (int i = 0; i < m_hulls.Count; i++) { ConvexResult hull = m_hulls[i]; float[] rawVerts = null; if (IsCacheCandidate(useCache, convVertices.Count)) { rawVerts = new float[hull.HullVertices.Count * 3]; } PhysX.Math.Vector3[] hullVerts = new PhysX.Math.Vector3[hull.HullVertices.Count]; for (int j = 0; j < hull.HullVertices.Count; j++) { hullVerts[j] = new PhysX.Math.Vector3(hull.HullVertices[j].x, hull.HullVertices[j].y, hull.HullVertices[j].z); if (rawVerts != null) { rawVerts[j * 3 + 0] = hull.HullVertices[j].x; rawVerts[j * 3 + 1] = hull.HullVertices[j].y; rawVerts[j * 3 + 2] = hull.HullVertices[j].z; } } retHulls[i] = new HacdConvexHull { Indicies = hull.HullIndices.ToArray(), Vertices = hullVerts, _rawVerts = rawVerts, }; } //store in cache for later if (IsCacheCandidate(useCache, convVertices.Count)) { try { MeshingStage.HullCache.CacheHulls(meshHash, retHulls); } catch (Exception e) { m_log.ErrorFormat("[InWorldz.PhysX.RatcliffACD] Failure storing HACD results in cache: {0}: {1}", e, e.Message); } } return retHulls; }
public static HacdConvexHull[] DecomposeToConvexHulls(ulong meshHash, bool useCache, HacdPreset preset, float[] verts, int[] indicies) { if (verts.Length % 3 != 0) throw new InvalidOperationException("Number of verticies must be divisble by 3"); if (indicies.Length % 3 != 0) throw new InvalidOperationException("Number of indicies must be divisble by 3"); if (IsCacheCandidate(useCache, verts.Length)) { //try cache try { HacdConvexHull[] cachedHulls; if (MeshingStage.HullCache.TryGetHulls(meshHash, out cachedHulls)) { return cachedHulls; } } catch (Exception e) { m_log.ErrorFormat("[InWorldz.PhysX.HACD] Failure retrieving HACD hulls from cache: {0}: {1}", e, e.Message); } } IntPtr session = Decompose(verts, indicies, verts.Length, indicies.Length, preset.DEFAULT_CC_CONNECT_DIST, preset.MIN_HULL_COUNT, preset.CONCAVITY, preset.TARGET_TRIANGLES_IN_FULL_MESH, preset.MAX_VERTS_PER_HULL, true, true, preset.VOLUME_WEIGHT, preset.SMALL_CLUSTER_THRESHOLD); if (session == IntPtr.Zero) { return null; } HacdConvexHull[] retHulls; try { int hullCount = GetConvexHullCount(session); retHulls = new HacdConvexHull[hullCount]; for (int hullNum = 0; hullNum < hullCount; ++hullNum) { int vertexCount = GetVertexCount(session, hullNum); int indexCount = GetIndexCount(session, hullNum); float[] hullVerts = new float[vertexCount]; int[] hullIndexes = new int[indexCount]; if (!GetConvexVertsAndIndexes(session, hullNum, hullVerts, hullIndexes)) { return null; } HacdConvexHull hull = new HacdConvexHull { Vertices = PhysUtil.FloatArrayToVectorArray(hullVerts), _rawVerts = IsCacheCandidate(useCache, verts.Length) ? hullVerts : null, Indicies = hullIndexes }; retHulls[hullNum] = hull; } //store in cache for later if (IsCacheCandidate(useCache, verts.Length)) { try { MeshingStage.HullCache.CacheHulls(meshHash, retHulls); } catch (Exception e) { m_log.ErrorFormat("[InWorldz.PhysX.HACD] Failure storing HACD results in cache: {0}: {1}", e, e.Message); } } return retHulls; } finally { FreeSession(session); } }