Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

user_profiles
Justin Clark-Casey (justincc) 2013-05-23 23:07:46 +01:00
commit 0d5566e879
5 changed files with 221 additions and 125 deletions

View File

@ -483,8 +483,15 @@ public sealed class BSCharacter : BSPhysObject
{ {
// Bullet assumes we know what we are doing when forcing orientation // Bullet assumes we know what we are doing when forcing orientation
// so it lets us go against all the rules and just compensates for them later. // so it lets us go against all the rules and just compensates for them later.
// This keeps us from flipping the capsule over which the veiwer does not understand. // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
ForceOrientation = new OMV.Quaternion(0, 0, _orientation.Z,0); // This keeps us from flipping the capsule over which the veiwer does not understand.
float oRoll, oPitch, oYaw;
_orientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
// DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
// LocalID, _orientation, OMV.Vector3.UnitX * _orientation,
// trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
ForceOrientation = trimmedOrientation;
}); });
} }
} }

View File

@ -90,6 +90,7 @@ public static class BSParam
public static bool ShouldUseBulletHACD { get; set; } public static bool ShouldUseBulletHACD { get; set; }
public static bool ShouldUseSingleConvexHullForPrims { get; set; } public static bool ShouldUseSingleConvexHullForPrims { get; set; }
public static bool ShouldUseGImpactShapeForPrims { get; set; } public static bool ShouldUseGImpactShapeForPrims { get; set; }
public static bool ShouldUseAssetHulls { get; set; }
public static float TerrainImplementation { get; set; } public static float TerrainImplementation { get; set; }
public static int TerrainMeshMagnification { get; private set; } public static int TerrainMeshMagnification { get; private set; }
@ -372,6 +373,8 @@ public static class BSParam
true ), true ),
new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists",
false ), false ),
new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info",
false ),
new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
5 ), 5 ),

View File

@ -31,6 +31,7 @@ using System.Text;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
using OpenSim.Region.Physics.Meshing;
using OpenSim.Region.Physics.ConvexDecompositionDotNet; using OpenSim.Region.Physics.ConvexDecompositionDotNet;
using OMV = OpenMetaverse; using OMV = OpenMetaverse;
@ -440,10 +441,14 @@ public class BSShapeMesh : BSShape
{ {
BulletShape newShape = new BulletShape(); BulletShape newShape = new BulletShape();
IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, IMesh meshData = null;
false, // say it is not physical so a bounding box is not built lock (physicsScene.mesher)
false // do not cache the mesh and do not use previously built versions {
); meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
false, // say it is not physical so a bounding box is not built
false // do not cache the mesh and do not use previously built versions
);
}
if (meshData != null) if (meshData != null)
{ {
@ -573,13 +578,75 @@ public class BSShapeHull : BSShape
PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
{ {
BulletShape newShape = new BulletShape(); BulletShape newShape = new BulletShape();
IntPtr hullPtr = IntPtr.Zero; newShape.shapeKey = newHullKey;
if (BSParam.ShouldUseBulletHACD) IMesh meshData = null;
List<List<OMV.Vector3>> allHulls = null;
lock (physicsScene.mesher)
{
// Pass true for physicalness as this prevents the creation of bounding box which is not needed
meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
// If we should use the asset's hull info, fetch it out of the locked mesher
if (meshData != null && BSParam.ShouldUseAssetHulls)
{
Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
if (realMesher != null)
{
allHulls = realMesher.GetConvexHulls(size);
}
if (allHulls == null)
{
physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
}
}
}
// If there is hull data in the mesh asset, build the hull from that
if (allHulls != null && BSParam.ShouldUseAssetHulls)
{
int hullCount = allHulls.Count;
int totalVertices = 1; // include one for the count of the hulls
// Using the structure described for HACD hulls, create the memory sturcture
// to pass the hull data to the creater.
foreach (List<OMV.Vector3> hullVerts in allHulls)
{
totalVertices += 4; // add four for the vertex count and centroid
totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
}
float[] convHulls = new float[totalVertices];
convHulls[0] = (float)hullCount;
int jj = 1;
foreach (List<OMV.Vector3> hullVerts in allHulls)
{
convHulls[jj + 0] = hullVerts.Count;
convHulls[jj + 1] = 0f; // centroid x,y,z
convHulls[jj + 2] = 0f;
convHulls[jj + 3] = 0f;
jj += 4;
foreach (OMV.Vector3 oneVert in hullVerts)
{
convHulls[jj + 0] = oneVert.X;
convHulls[jj + 1] = oneVert.Y;
convHulls[jj + 2] = oneVert.Z;
jj += 3;
}
}
// create the hull data structure in Bullet
newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
prim.LocalID, hullCount, totalVertices, newShape);
}
// If no hull specified in the asset and we should use Bullet's HACD approximation...
if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
{ {
// Build the hull shape from an existing mesh shape. // Build the hull shape from an existing mesh shape.
// The mesh should have already been created in Bullet. // The mesh should have already been created in Bullet.
physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
if (meshShape.physShapeInfo.HasPhysicalShape) if (meshShape.physShapeInfo.HasPhysicalShape)
@ -597,128 +664,123 @@ public class BSShapeHull : BSShape
physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
// Now done with the mesh shape. // Now done with the mesh shape.
meshShape.Dereference(physicsScene); meshShape.Dereference(physicsScene);
} }
physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
} }
if (!newShape.HasPhysicalShape)
// If no other hull specifications, use our HACD hull approximation.
if (!newShape.HasPhysicalShape && meshData != null)
{ {
// Build a new hull in the physical world using the C# HACD algorigthm. if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
// Pass true for physicalness as this prevents the creation of bounding box which is not needed
IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
if (meshData != null)
{ {
if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) // Release the fetched asset data once it has been used.
{ pbs.SculptData = new byte[0];
// Release the fetched asset data once it has been used. prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
pbs.SculptData = new byte[0];
prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
}
int[] indices = meshData.getIndexListAsInt();
List<OMV.Vector3> vertices = meshData.getVertexList();
//format conversion from IMesh format to DecompDesc format
List<int> convIndices = new List<int>();
List<float3> convVertices = new List<float3>();
for (int ii = 0; ii < indices.GetLength(0); ii++)
{
convIndices.Add(indices[ii]);
}
foreach (OMV.Vector3 vv in vertices)
{
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
}
uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
{
// Simple primitive shapes we know are convex so they are better implemented with
// fewer hulls.
// Check for simple shape (prim without cuts) and reduce split parameter if so.
if (BSShapeCollection.PrimHasNoCuts(pbs))
{
maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
}
}
// setup and do convex hull conversion
m_hulls = new List<ConvexResult>();
DecompDesc dcomp = new DecompDesc();
dcomp.mIndices = convIndices;
dcomp.mVertices = convVertices;
dcomp.mDepth = maxDepthSplit;
dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
// create the hull into the _hulls variable
convexBuilder.process(dcomp);
physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
// Convert the vertices and indices for passing to unmanaged.
// The hull information is passed as a large floating point array.
// The format is:
// convHulls[0] = number of hulls
// convHulls[1] = number of vertices in first hull
// convHulls[2] = hull centroid X coordinate
// convHulls[3] = hull centroid Y coordinate
// convHulls[4] = hull centroid Z coordinate
// convHulls[5] = first hull vertex X
// convHulls[6] = first hull vertex Y
// convHulls[7] = first hull vertex Z
// convHulls[8] = second hull vertex X
// ...
// convHulls[n] = number of vertices in second hull
// convHulls[n+1] = second hull centroid X coordinate
// ...
//
// TODO: is is very inefficient. Someday change the convex hull generator to return
// data structures that do not need to be converted in order to pass to Bullet.
// And maybe put the values directly into pinned memory rather than marshaling.
int hullCount = m_hulls.Count;
int totalVertices = 1; // include one for the count of the hulls
foreach (ConvexResult cr in m_hulls)
{
totalVertices += 4; // add four for the vertex count and centroid
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
}
float[] convHulls = new float[totalVertices];
convHulls[0] = (float)hullCount;
int jj = 1;
foreach (ConvexResult cr in m_hulls)
{
// copy vertices for index access
float3[] verts = new float3[cr.HullVertices.Count];
int kk = 0;
foreach (float3 ff in cr.HullVertices)
{
verts[kk++] = ff;
}
// add to the array one hull's worth of data
convHulls[jj++] = cr.HullIndices.Count;
convHulls[jj++] = 0f; // centroid x,y,z
convHulls[jj++] = 0f;
convHulls[jj++] = 0f;
foreach (int ind in cr.HullIndices)
{
convHulls[jj++] = verts[ind].x;
convHulls[jj++] = verts[ind].y;
convHulls[jj++] = verts[ind].z;
}
}
// create the hull data structure in Bullet
newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
} }
newShape.shapeKey = newHullKey;
int[] indices = meshData.getIndexListAsInt();
List<OMV.Vector3> vertices = meshData.getVertexList();
//format conversion from IMesh format to DecompDesc format
List<int> convIndices = new List<int>();
List<float3> convVertices = new List<float3>();
for (int ii = 0; ii < indices.GetLength(0); ii++)
{
convIndices.Add(indices[ii]);
}
foreach (OMV.Vector3 vv in vertices)
{
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
}
uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
{
// Simple primitive shapes we know are convex so they are better implemented with
// fewer hulls.
// Check for simple shape (prim without cuts) and reduce split parameter if so.
if (BSShapeCollection.PrimHasNoCuts(pbs))
{
maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
}
}
// setup and do convex hull conversion
m_hulls = new List<ConvexResult>();
DecompDesc dcomp = new DecompDesc();
dcomp.mIndices = convIndices;
dcomp.mVertices = convVertices;
dcomp.mDepth = maxDepthSplit;
dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
// create the hull into the _hulls variable
convexBuilder.process(dcomp);
physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
// Convert the vertices and indices for passing to unmanaged.
// The hull information is passed as a large floating point array.
// The format is:
// convHulls[0] = number of hulls
// convHulls[1] = number of vertices in first hull
// convHulls[2] = hull centroid X coordinate
// convHulls[3] = hull centroid Y coordinate
// convHulls[4] = hull centroid Z coordinate
// convHulls[5] = first hull vertex X
// convHulls[6] = first hull vertex Y
// convHulls[7] = first hull vertex Z
// convHulls[8] = second hull vertex X
// ...
// convHulls[n] = number of vertices in second hull
// convHulls[n+1] = second hull centroid X coordinate
// ...
//
// TODO: is is very inefficient. Someday change the convex hull generator to return
// data structures that do not need to be converted in order to pass to Bullet.
// And maybe put the values directly into pinned memory rather than marshaling.
int hullCount = m_hulls.Count;
int totalVertices = 1; // include one for the count of the hulls
foreach (ConvexResult cr in m_hulls)
{
totalVertices += 4; // add four for the vertex count and centroid
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
}
float[] convHulls = new float[totalVertices];
convHulls[0] = (float)hullCount;
int jj = 1;
foreach (ConvexResult cr in m_hulls)
{
// copy vertices for index access
float3[] verts = new float3[cr.HullVertices.Count];
int kk = 0;
foreach (float3 ff in cr.HullVertices)
{
verts[kk++] = ff;
}
// add to the array one hull's worth of data
convHulls[jj++] = cr.HullIndices.Count;
convHulls[jj++] = 0f; // centroid x,y,z
convHulls[jj++] = 0f;
convHulls[jj++] = 0f;
foreach (int ind in cr.HullIndices)
{
convHulls[jj++] = verts[ind].x;
convHulls[jj++] = verts[ind].y;
convHulls[jj++] = verts[ind].z;
}
}
// create the hull data structure in Bullet
newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
} }
return newShape; return newShape;
} }

View File

@ -64,6 +64,7 @@ namespace OpenSim.Region.Physics.Meshing
public class Meshmerizer : IMesher public class Meshmerizer : IMesher
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[MESH]";
// Setting baseDir to a path will enable the dumping of raw files // Setting baseDir to a path will enable the dumping of raw files
// raw files can be imported by blender so a visual inspection of the results can be done // raw files can be imported by blender so a visual inspection of the results can be done
@ -72,6 +73,8 @@ namespace OpenSim.Region.Physics.Meshing
#else #else
private const string baseDir = null; //"rawFiles"; private const string baseDir = null; //"rawFiles";
#endif #endif
// If 'true', lots of DEBUG logging of asset parsing details
private bool debugDetail = true;
private bool cacheSculptMaps = true; private bool cacheSculptMaps = true;
private string decodedSculptMapPath = null; private string decodedSculptMapPath = null;
@ -357,13 +360,25 @@ namespace OpenSim.Region.Physics.Meshing
OSDMap physicsParms = null; OSDMap physicsParms = null;
OSDMap map = (OSDMap)meshOsd; OSDMap map = (OSDMap)meshOsd;
if (map.ContainsKey("physics_shape")) if (map.ContainsKey("physics_shape"))
{
physicsParms = (OSDMap)map["physics_shape"]; // old asset format physicsParms = (OSDMap)map["physics_shape"]; // old asset format
if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName);
}
else if (map.ContainsKey("physics_mesh")) else if (map.ContainsKey("physics_mesh"))
{
physicsParms = (OSDMap)map["physics_mesh"]; // new asset format physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName);
}
else if (map.ContainsKey("medium_lod")) else if (map.ContainsKey("medium_lod"))
{
physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh
if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName);
}
else if (map.ContainsKey("high_lod")) else if (map.ContainsKey("high_lod"))
{
physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :) physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :)
if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName);
}
if (map.ContainsKey("physics_convex")) if (map.ContainsKey("physics_convex"))
{ // pull this out also in case physics engine can use it { // pull this out also in case physics engine can use it
@ -408,11 +423,16 @@ namespace OpenSim.Region.Physics.Meshing
} }
mConvexHulls = hulls; mConvexHulls = hulls;
if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count);
}
else
{
if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName);
} }
} }
catch (Exception e) catch (Exception e)
{ {
m_log.WarnFormat("[MESH]: exception decoding convex block: {0}", e.Message); m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e);
} }
} }
@ -438,7 +458,7 @@ namespace OpenSim.Region.Physics.Meshing
} }
catch (Exception e) catch (Exception e)
{ {
m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e);
return false; return false;
} }
@ -455,6 +475,9 @@ namespace OpenSim.Region.Physics.Meshing
if (subMeshOsd is OSDMap) if (subMeshOsd is OSDMap)
AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
} }
if (debugDetail)
m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}",
LogHeader, primName, physOffset, physSize, coords.Count, faces.Count);
} }
} }

View File

@ -1753,6 +1753,7 @@
<Reference name="OpenSim.Region.CoreModules"/> <Reference name="OpenSim.Region.CoreModules"/>
<Reference name="OpenSim.Framework.Console"/> <Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Region.Physics.Manager"/> <Reference name="OpenSim.Region.Physics.Manager"/>
<Reference name="OpenSim.Region.Physics.Meshing" path="../../../../bin/Physics/"/>
<Reference name="OpenSim.Region.Physics.ConvexDecompositionDotNet"/> <Reference name="OpenSim.Region.Physics.ConvexDecompositionDotNet"/>
<Reference name="BulletXNA.dll" path="../../../../bin/"/> <Reference name="BulletXNA.dll" path="../../../../bin/"/>
<Reference name="log4net.dll" path="../../../../bin/"/> <Reference name="log4net.dll" path="../../../../bin/"/>