Skip to content
Permalink
Browse files

[Physics] In-editor static mesh collider

  • Loading branch information
Eideren committed May 10, 2019
1 parent 8a7126a commit 3a96ee3f0da9c02e5f1221669745316567122e5e
@@ -110,7 +110,7 @@ public override void Serialize(ref T obj, ArchiveMode mode, SerializationStream
else
{
// No real case yet
throw new NotSupportedException();
//throw new NotSupportedException();
}
}
}
@@ -569,7 +569,7 @@ private void BuildInput(StaticColliderData[] collidersLocal, CollisionFilterGrou
indices[i + 1] = (int)mesh.Indices[i + 2];
}

entityNavigationMeshInputBuilder.AppendArrays(mesh.Points.ToArray(), indices, transform);
entityNavigationMeshInputBuilder.AppendArrays(mesh.Vertices.ToArray(), indices, transform);
}
else if (shapeType == typeof(CompoundColliderShape))
{
@@ -1,162 +1,212 @@
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using System.Collections.Generic;
using System;
using Xenko.Core;
using Xenko.Core.Mathematics;
using Xenko.Core.Serialization.Contents;
using Xenko.Graphics;
using Xenko.Rendering;

namespace Xenko.Physics
{
[ContentSerializer(typeof(DataContentSerializer<StaticMeshColliderShapeDesc>))]
[DataContract("StaticMeshColliderShapeDesc")]
[Display(500, "Static Mesh")]
public class StaticMeshColliderShapeDesc : IAssetColliderShapeDesc
public class StaticMeshColliderShapeDesc : IInlineColliderShapeDesc
{
#if XENKO_PLATFORM_WINDOWS_DESKTOP

[Display(Browsable = false)]
#endif
[DataMember(10)]
public List<List<List<Vector3>>> Points; // Multiple meshes -> Multiple Hulls -> Hull points

#if XENKO_PLATFORM_WINDOWS_DESKTOP

[Display(Browsable = false)]
#endif
[DataMember(20)]
public List<List<List<uint>>> Indices; // Multiple meshes -> Multiple Hulls -> Hull tris

/// <userdoc>
/// Model asset from where the engine will derive the collider shape.
/// Model asset from which the engine will derive the collider shape.
/// </userdoc>
[DataMember(30)]
[DataMember(10)]
public Model Model;

/// <userdoc>
/// The offset with the real graphic mesh.
/// The local offset of the collider shape.
/// </userdoc>
[DataMember(31)]
[DataMember(20)]
public Vector3 LocalOffset;

/// <userdoc>
/// The local rotation of the collider shape.
/// </userdoc>
[DataMember(32)]
[DataMember(30)]
public Quaternion LocalRotation = Quaternion.Identity;

/// <userdoc>
/// The scaling of the collider shape.
/// </userdoc>
[DataMember(45)]
[DataMember(40)]
public Vector3 Scaling = Vector3.One;


public bool Match(object obj)
{
var other = obj as StaticMeshColliderShapeDesc;
if (other == null)
return false;

if (other.LocalOffset != LocalOffset || other.LocalRotation != LocalRotation)
return false;
if (obj is StaticMeshColliderShapeDesc other)
{
return other.Model == Model
&& other.LocalOffset == LocalOffset
&& other.LocalRotation == LocalRotation
&& other.Scaling == Scaling;
}

return other.Model == Model &&
other.Scaling == Scaling;
return false;
}

public ColliderShape NewShapeFromDesc()
{
if (Points == null) return null;
if(Model == null)
return null;


if (Points.Count == 1)
int[] indices;
Vector3[] vertices;
{
if (Points[0].Count == 1 && Indices[0][0].Count > 0)
{
var shape = new StaticMeshColliderShape(Points[0][0], Indices[0][0], Scaling)
{
NeedsCustomCollisionCallback = true,
};

//shape.UpdateLocalTransformations();
shape.Description = this;

return shape;
}

if (Points[0].Count <= 1) return null;

var subCompound = new CompoundColliderShape
{
NeedsCustomCollisionCallback = true,
};
int totalIndices = 0;
int totalVerts = 0;

for (var i = 0; i < Points[0].Count; i++)
foreach(var mesh in Model.Meshes)
{
var verts = Points[0][i];
var indices = Indices[0][i];

if (indices.Count == 0) continue;

var subHull = new StaticMeshColliderShape(verts, indices, Scaling);
//subHull.UpdateLocalTransformations();
subCompound.AddChildShape(subHull);
foreach(var bufferBinding in mesh.Draw.VertexBuffers)
{
// We have to duplicate the index buffer for each vertex buffers since
// bullet doesn't have a construct sharing index buffers
totalIndices += mesh.Draw.IndexBuffer.Count;
totalVerts += bufferBinding.Count;
}
}

//subCompound.UpdateLocalTransformations();
subCompound.Description = this;

return subCompound;
if (totalIndices == 0 || totalVerts == 0)
return null;

indices = new int[totalIndices];
vertices = new Vector3[totalVerts];
}

if (Points.Count <= 1) return null;

var compound = new CompoundColliderShape
{
NeedsCustomCollisionCallback = true,
};

for (var i = 0; i < Points.Count; i++)

int iCollOffset = 0;
int vCollOffset = 0;
foreach(var mesh in Model.Meshes)
{
var verts = Points[i];
var indices = Indices[i];

if (verts.Count == 1)
{
if (indices[0].Count == 0) continue;

var subHull = new StaticMeshColliderShape(verts[0], indices[0], Scaling);
//subHull.UpdateLocalTransformations();
compound.AddChildShape(subHull);
}
else if (verts.Count > 1)
var commandList = (CommandList)typeof(GraphicsDevice).GetField("InternalMainCommandList",
System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.GetField
| System.Reflection.BindingFlags.FlattenHierarchy).GetValue(mesh.Draw.IndexBuffer.Buffer.GraphicsDevice);

foreach(var bufferBinding in mesh.Draw.VertexBuffers)
{
var subCompound = new CompoundColliderShape();

for (var b = 0; b < verts.Count; b++)
// Take care of the index buffer
unsafe
{
var binding = mesh.Draw.IndexBuffer;
var buffer = binding.Buffer;
var elementCount = binding.Count;
var sizeInBytes = buffer.Description.SizeInBytes;

byte* window = stackalloc byte[sizeInBytes];
FetchBufferData(buffer, commandList, new DataPointer(window, sizeInBytes));
window += binding.Offset;

if (binding.Is32Bit)
{
// For multiple meshes, indices have to be offset
// since we're merging all the meshes together
int* shortPtr = (int*)window;
for (int i = 0; i < elementCount; i++)
{
indices[iCollOffset++] = vCollOffset + shortPtr[i];
}
}
// convert ushort gpu representation to uint
else
{
ushort* shortPtr = (ushort*)window;
for (int i = 0; i < elementCount; i++)
{
indices[iCollOffset++] = vCollOffset + shortPtr[i];
}
}
}

int stride = 0;
(int offset, VertexElement decl) posData;
// Find position within struct and buffer
{
var subVerts = verts[b];
var subIndex = indices[b];
int tempOffset = 0;
(int offset, VertexElement decl)? posDataNullable = null;
foreach(var elemDecl in bufferBinding.Declaration.VertexElements)
{
if(elemDecl.SemanticName.Equals("POSITION", StringComparison.Ordinal))
{
posDataNullable = (tempOffset, elemDecl);
}

// Get new offset (if specified)
var currentElementOffset = elemDecl.AlignedByteOffset;
if (currentElementOffset != VertexElement.AppendAligned)
tempOffset = currentElementOffset;

var elementSize = elemDecl.Format.SizeInBytes();

// Compute next offset (if automatic)
tempOffset += elementSize;

stride = Math.Max(stride, tempOffset); // element are not necessary ordered by increasing offsets
}

if(posDataNullable == null)
throw new Exception($"No position data within {mesh}'s {nameof(mesh.Draw.VertexBuffers)}");

posData = posDataNullable.Value;
}

// Fetch vertex position data from GPU
unsafe
{
var sizeInBytes = bufferBinding.Buffer.Description.SizeInBytes;
var elementCount = bufferBinding.Count;

byte* window = stackalloc byte[sizeInBytes];
FetchBufferData(bufferBinding.Buffer, commandList, new DataPointer(window, sizeInBytes));

window += bufferBinding.Offset;

if (posData.decl.Format != PixelFormat.R32G32B32_Float)
throw new NotImplementedException(posData.decl.Format.ToString());

for(int i = 0; i < elementCount; i++)
{
byte* vStart = &window[i * stride + posData.offset];
vertices[vCollOffset++] = *(Vector3*)vStart;
}
}
}
}

if (subIndex.Count == 0) continue;
for(int i = 0; i < vertices.Length; i++)
{
LocalRotation.Rotate(ref vertices[i]);
vertices[i] += LocalOffset;
}

var subHull = new StaticMeshColliderShape(subVerts, subIndex, Scaling);
//subHull.UpdateLocalTransformations();
subCompound.AddChildShape(subHull);
}
return new StaticMeshColliderShape(vertices, indices, Scaling);
}

//subCompound.UpdateLocalTransformations();

compound.AddChildShape(subCompound);
}
static unsafe void FetchBufferData(Graphics.Buffer buffer, CommandList commandList, DataPointer ptr)
{
if (buffer.Description.Usage == GraphicsResourceUsage.Staging)
{
// Directly if this is a staging resource
buffer.GetData(commandList, buffer, ptr);
}
else
{
// Unefficient way to use the Copy method using dynamic staging texture
using (var throughStaging = buffer.ToStaging())
buffer.GetData(commandList, throughStaging, ptr);
}
}

//compound.UpdateLocalTransformations();
compound.Description = this;

return compound;
}
}
}

0 comments on commit 3a96ee3

Please sign in to comment.
You can’t perform that action at this time.