forked from mirror/DotRecast
refactor: DynamicUpdateSampleTool
This commit is contained in:
parent
c03d3053c5
commit
ab50f0fd53
|
@ -0,0 +1,193 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
using DotRecast.Recast.Toolset.Tools.Gizmos;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
using static DotRecast.Core.RcMath;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools;
|
||||
|
||||
public class ColliderWithGizmo
|
||||
{
|
||||
public readonly IRcGizmoMeshFilter Gizmo;
|
||||
public readonly ICollider Collider;
|
||||
|
||||
public ColliderWithGizmo(ICollider collider, IRcGizmoMeshFilter gizmo)
|
||||
{
|
||||
Collider = collider;
|
||||
Gizmo = gizmo;
|
||||
}
|
||||
|
||||
public void Render(RecastDebugDraw dd)
|
||||
{
|
||||
Render(dd, Gizmo);
|
||||
}
|
||||
|
||||
public static void Render(RecastDebugDraw dd, IRcGizmoMeshFilter gizmo)
|
||||
{
|
||||
if (gizmo is BoxGizmo box)
|
||||
{
|
||||
RenderBox(dd, box);
|
||||
}
|
||||
else if (gizmo is CapsuleGizmo capsule)
|
||||
{
|
||||
RenderCapsule(dd, capsule);
|
||||
}
|
||||
else if (gizmo is TrimeshGizmo trimesh)
|
||||
{
|
||||
RenderTrimesh(dd, trimesh);
|
||||
}
|
||||
else if (gizmo is CylinderGizmo cylinder)
|
||||
{
|
||||
RenderCylinder(dd, cylinder);
|
||||
}
|
||||
else if (gizmo is SphereGizmo sphere)
|
||||
{
|
||||
RenderSphere(dd, sphere);
|
||||
}
|
||||
else if (gizmo is CompositeGizmo composite)
|
||||
{
|
||||
RenderComposite(dd, composite);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetColorByNormal(float[] vertices, int v0, int v1, int v2)
|
||||
{
|
||||
RcVec3f e0 = new RcVec3f();
|
||||
RcVec3f e1 = new RcVec3f();
|
||||
RcVec3f normal = new RcVec3f();
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
e0[j] = vertices[v1 + j] - vertices[v0 + j];
|
||||
e1[j] = vertices[v2 + j] - vertices[v0 + j];
|
||||
}
|
||||
|
||||
normal.x = e0.y * e1.z - e0.z * e1.y;
|
||||
normal.y = e0.z * e1.x - e0.x * e1.z;
|
||||
normal.z = e0.x * e1.y - e0.y * e1.x;
|
||||
RcVec3f.Normalize(ref normal);
|
||||
float c = Clamp(0.57735026f * (normal.x + normal.y + normal.z), -1, 1);
|
||||
int col = DebugDraw.DuLerpCol(
|
||||
DebugDraw.DuRGBA(32, 32, 0, 160),
|
||||
DebugDraw.DuRGBA(220, 220, 0, 160),
|
||||
(int)(127 * (1 + c))
|
||||
);
|
||||
return col;
|
||||
}
|
||||
|
||||
public static void RenderBox(RecastDebugDraw debugDraw, BoxGizmo box)
|
||||
{
|
||||
var trX = RcVec3f.Of(box.halfEdges[0].x, box.halfEdges[1].x, box.halfEdges[2].x);
|
||||
var trY = RcVec3f.Of(box.halfEdges[0].y, box.halfEdges[1].y, box.halfEdges[2].y);
|
||||
var trZ = RcVec3f.Of(box.halfEdges[0].z, box.halfEdges[1].z, box.halfEdges[2].z);
|
||||
float[] vertices = new float[8 * 3];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
vertices[i * 3 + 0] = RcVec3f.Dot(BoxGizmo.VERTS[i], trX) + box.center.x;
|
||||
vertices[i * 3 + 1] = RcVec3f.Dot(BoxGizmo.VERTS[i], trY) + box.center.y;
|
||||
vertices[i * 3 + 2] = RcVec3f.Dot(BoxGizmo.VERTS[i], trZ) + box.center.z;
|
||||
}
|
||||
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
int col = DebugDraw.DuRGBA(200, 200, 50, 160);
|
||||
if (i == 4 || i == 5 || i == 8 || i == 9)
|
||||
{
|
||||
col = DebugDraw.DuRGBA(160, 160, 40, 160);
|
||||
}
|
||||
else if (i > 4)
|
||||
{
|
||||
col = DebugDraw.DuRGBA(120, 120, 30, 160);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
int v = BoxGizmo.TRIANLGES[i * 3 + j] * 3;
|
||||
debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
|
||||
public static void RenderCapsule(RecastDebugDraw debugDraw, CapsuleGizmo capsule)
|
||||
{
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < capsule.triangles.Length; i += 3)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
int v = capsule.triangles[i + j] * 3;
|
||||
float c = capsule.gradient[capsule.triangles[i + j]];
|
||||
int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
|
||||
(int)(127 * (1 + c)));
|
||||
debugDraw.Vertex(capsule.vertices[v], capsule.vertices[v + 1], capsule.vertices[v + 2], col);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
|
||||
public static void RenderCylinder(RecastDebugDraw debugDraw, CylinderGizmo cylinder)
|
||||
{
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < cylinder.triangles.Length; i += 3)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
int v = cylinder.triangles[i + j] * 3;
|
||||
float c = cylinder.gradient[cylinder.triangles[i + j]];
|
||||
int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
|
||||
(int)(127 * (1 + c)));
|
||||
debugDraw.Vertex(cylinder.vertices[v], cylinder.vertices[v + 1], cylinder.vertices[v + 2], col);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
|
||||
public static void RenderSphere(RecastDebugDraw debugDraw, SphereGizmo sphere)
|
||||
{
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < sphere.triangles.Length; i += 3)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
int v = sphere.triangles[i + j] * 3;
|
||||
float c = Clamp(0.57735026f * (sphere.vertices[v] + sphere.vertices[v + 1] + sphere.vertices[v + 2]), -1, 1);
|
||||
int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160), (int)(127 * (1 + c)));
|
||||
|
||||
debugDraw.Vertex(
|
||||
sphere.radius * sphere.vertices[v] + sphere.center.x,
|
||||
sphere.radius * sphere.vertices[v + 1] + sphere.center.y,
|
||||
sphere.radius * sphere.vertices[v + 2] + sphere.center.z,
|
||||
col
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
|
||||
public static void RenderTrimesh(RecastDebugDraw debugDraw, TrimeshGizmo trimesh)
|
||||
{
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < trimesh.triangles.Length; i += 3)
|
||||
{
|
||||
int v0 = 3 * trimesh.triangles[i];
|
||||
int v1 = 3 * trimesh.triangles[i + 1];
|
||||
int v2 = 3 * trimesh.triangles[i + 2];
|
||||
int col = GetColorByNormal(trimesh.vertices, v0, v1, v2);
|
||||
debugDraw.Vertex(trimesh.vertices[v0], trimesh.vertices[v0 + 1], trimesh.vertices[v0 + 2], col);
|
||||
debugDraw.Vertex(trimesh.vertices[v1], trimesh.vertices[v1 + 1], trimesh.vertices[v1 + 2], col);
|
||||
debugDraw.Vertex(trimesh.vertices[v2], trimesh.vertices[v2 + 1], trimesh.vertices[v2 + 2], col);
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
|
||||
public static void RenderComposite(RecastDebugDraw debugDraw, CompositeGizmo composite)
|
||||
{
|
||||
composite.gizmoMeshes.ForEach(g => Render(debugDraw, g));
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ using DotRecast.Detour.Dynamic.Io;
|
|||
using DotRecast.Recast.Toolset.Builder;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
using DotRecast.Recast.Toolset.Geom;
|
||||
using DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
using DotRecast.Recast.Toolset.Tools.Gizmos;
|
||||
using DotRecast.Recast.Demo.UI;
|
||||
using DotRecast.Recast.Toolset;
|
||||
using DotRecast.Recast.Toolset.Tools;
|
||||
|
@ -75,8 +75,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
|
||||
private DynamicNavMesh dynaMesh;
|
||||
private readonly TaskFactory executor;
|
||||
private readonly Dictionary<long, ICollider> colliders = new();
|
||||
private readonly Dictionary<long, IColliderGizmo> colliderGizmos = new();
|
||||
private readonly Dictionary<long, ColliderWithGizmo> colliderGizmos = new();
|
||||
private readonly Random random = Random.Shared;
|
||||
private readonly DemoInputGeomProvider bridgeGeom;
|
||||
private readonly DemoInputGeomProvider houseGeom;
|
||||
|
@ -100,7 +99,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
public void Layout()
|
||||
{
|
||||
var prevModeIdx = mode.Idx;
|
||||
|
||||
|
||||
ImGui.Text($"Dynamic Update Tool Modes");
|
||||
ImGui.Separator();
|
||||
ImGui.RadioButton(DynamicUpdateToolMode.BUILD.Label, ref prevModeIdx, DynamicUpdateToolMode.BUILD.Idx);
|
||||
|
@ -280,7 +279,10 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
{
|
||||
if (showColliders)
|
||||
{
|
||||
colliderGizmos.Values.ForEach(g => g.Render(renderer.GetDebugDraw()));
|
||||
colliderGizmos.Values.ForEach(g =>
|
||||
{
|
||||
g.Render(renderer.GetDebugDraw());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,8 +399,7 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
if (colliderWithGizmo != null)
|
||||
{
|
||||
long id = dynaMesh.AddCollider(colliderWithGizmo.Collider);
|
||||
colliders.Add(id, colliderWithGizmo.Collider);
|
||||
colliderGizmos.Add(id, colliderWithGizmo.Gizmo);
|
||||
colliderGizmos.Add(id, colliderWithGizmo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -525,11 +526,11 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
SphereCollider crown = new SphereCollider(crownCenter, 4f, SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS,
|
||||
dynaMesh.config.walkableClimb);
|
||||
CompositeCollider collider = new CompositeCollider(@base, roof, trunk, crown);
|
||||
IColliderGizmo baseGizmo = GizmoFactory.Box(baseCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(baseUp, forward, baseExtent));
|
||||
IColliderGizmo roofGizmo = GizmoFactory.Box(roofCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(roofUp, forward, roofExtent));
|
||||
IColliderGizmo trunkGizmo = GizmoFactory.Capsule(trunkStart, trunkEnd, 0.5f);
|
||||
IColliderGizmo crownGizmo = GizmoFactory.Sphere(crownCenter, 4f);
|
||||
IColliderGizmo gizmo = GizmoFactory.Composite(baseGizmo, roofGizmo, trunkGizmo, crownGizmo);
|
||||
IRcGizmoMeshFilter baseGizmo = GizmoFactory.Box(baseCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(baseUp, forward, baseExtent));
|
||||
IRcGizmoMeshFilter roofGizmo = GizmoFactory.Box(roofCenter, Detour.Dynamic.Colliders.BoxCollider.GetHalfEdges(roofUp, forward, roofExtent));
|
||||
IRcGizmoMeshFilter trunkGizmo = GizmoFactory.Capsule(trunkStart, trunkEnd, 0.5f);
|
||||
IRcGizmoMeshFilter crownGizmo = GizmoFactory.Sphere(crownCenter, 4f);
|
||||
IRcGizmoMeshFilter gizmo = GizmoFactory.Composite(baseGizmo, roofGizmo, trunkGizmo, crownGizmo);
|
||||
return new ColliderWithGizmo(collider, gizmo);
|
||||
}
|
||||
|
||||
|
@ -610,12 +611,11 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
{
|
||||
if (shift)
|
||||
{
|
||||
foreach (var e in colliders)
|
||||
foreach (var e in colliderGizmos)
|
||||
{
|
||||
if (Hit(start, dir, e.Value.Bounds()))
|
||||
if (Hit(start, dir, e.Value.Collider.Bounds()))
|
||||
{
|
||||
dynaMesh.RemoveCollider(e.Key);
|
||||
colliders.Remove(e.Key);
|
||||
colliderGizmos.Remove(e.Key);
|
||||
break;
|
||||
}
|
||||
|
@ -691,10 +691,11 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
VoxelFile voxelFile = reader.Read(br);
|
||||
dynaMesh = new DynamicNavMesh(voxelFile);
|
||||
dynaMesh.config.keepIntermediateResults = true;
|
||||
|
||||
UpdateUI();
|
||||
BuildDynaMesh();
|
||||
|
||||
colliders.Clear();
|
||||
colliderGizmos.Clear();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public class BoxGizmo : IColliderGizmo
|
||||
{
|
||||
private static readonly int[] TRIANLGES =
|
||||
{
|
||||
0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2,
|
||||
2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7
|
||||
};
|
||||
|
||||
private static readonly RcVec3f[] VERTS =
|
||||
{
|
||||
RcVec3f.Of(-1f, -1f, -1f),
|
||||
RcVec3f.Of(1f, -1f, -1f),
|
||||
RcVec3f.Of(1f, -1f, 1f),
|
||||
RcVec3f.Of(-1f, -1f, 1f),
|
||||
RcVec3f.Of(-1f, 1f, -1f),
|
||||
RcVec3f.Of(1f, 1f, -1f),
|
||||
RcVec3f.Of(1f, 1f, 1f),
|
||||
RcVec3f.Of(-1f, 1f, 1f),
|
||||
};
|
||||
|
||||
private readonly float[] vertices = new float[8 * 3];
|
||||
private readonly RcVec3f center;
|
||||
private readonly RcVec3f[] halfEdges;
|
||||
|
||||
public BoxGizmo(RcVec3f center, RcVec3f extent, RcVec3f forward, RcVec3f up) :
|
||||
this(center, BoxCollider.GetHalfEdges(up, forward, extent))
|
||||
{
|
||||
}
|
||||
|
||||
public BoxGizmo(RcVec3f center, RcVec3f[] halfEdges)
|
||||
{
|
||||
this.center = center;
|
||||
this.halfEdges = halfEdges;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
float s0 = (i & 1) != 0 ? 1f : -1f;
|
||||
float s1 = (i & 2) != 0 ? 1f : -1f;
|
||||
float s2 = (i & 4) != 0 ? 1f : -1f;
|
||||
vertices[i * 3 + 0] = center.x + s0 * halfEdges[0].x + s1 * halfEdges[1].x + s2 * halfEdges[2].x;
|
||||
vertices[i * 3 + 1] = center.y + s0 * halfEdges[0].y + s1 * halfEdges[1].y + s2 * halfEdges[2].y;
|
||||
vertices[i * 3 + 2] = center.z + s0 * halfEdges[0].z + s1 * halfEdges[1].z + s2 * halfEdges[2].z;
|
||||
}
|
||||
}
|
||||
|
||||
public void Render(RecastDebugDraw debugDraw)
|
||||
{
|
||||
var trX = RcVec3f.Of(halfEdges[0].x, halfEdges[1].x, halfEdges[2].x);
|
||||
var trY = RcVec3f.Of(halfEdges[0].y, halfEdges[1].y, halfEdges[2].y);
|
||||
var trZ = RcVec3f.Of(halfEdges[0].z, halfEdges[1].z, halfEdges[2].z);
|
||||
float[] vertices = new float[8 * 3];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
vertices[i * 3 + 0] = RcVec3f.Dot(VERTS[i], trX) + center.x;
|
||||
vertices[i * 3 + 1] = RcVec3f.Dot(VERTS[i], trY) + center.y;
|
||||
vertices[i * 3 + 2] = RcVec3f.Dot(VERTS[i], trZ) + center.z;
|
||||
}
|
||||
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
int col = DebugDraw.DuRGBA(200, 200, 50, 160);
|
||||
if (i == 4 || i == 5 || i == 8 || i == 9)
|
||||
{
|
||||
col = DebugDraw.DuRGBA(160, 160, 40, 160);
|
||||
}
|
||||
else if (i > 4)
|
||||
{
|
||||
col = DebugDraw.DuRGBA(120, 120, 30, 160);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
int v = TRIANLGES[i * 3 + j] * 3;
|
||||
debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
using static DotRecast.Core.RcMath;
|
||||
using static DotRecast.Recast.Demo.Tools.Gizmos.GizmoHelper;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public class CapsuleGizmo : IColliderGizmo
|
||||
{
|
||||
private readonly float[] vertices;
|
||||
private readonly int[] triangles;
|
||||
private readonly float[] center;
|
||||
private readonly float[] gradient;
|
||||
|
||||
public CapsuleGizmo(RcVec3f start, RcVec3f end, float radius)
|
||||
{
|
||||
center = new float[]
|
||||
{
|
||||
0.5f * (start.x + end.x), 0.5f * (start.y + end.y),
|
||||
0.5f * (start.z + end.z)
|
||||
};
|
||||
RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
RcVec3f[] normals = new RcVec3f[3];
|
||||
normals[1] = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
RcVec3f.Normalize(ref normals[1]);
|
||||
normals[0] = GetSideVector(axis);
|
||||
normals[2] = RcVec3f.Zero;
|
||||
RcVec3f.Cross(ref normals[2], normals[0], normals[1]);
|
||||
RcVec3f.Normalize(ref normals[2]);
|
||||
triangles = GenerateSphericalTriangles();
|
||||
var trX = RcVec3f.Of(normals[0].x, normals[1].x, normals[2].x);
|
||||
var trY = RcVec3f.Of(normals[0].y, normals[1].y, normals[2].y);
|
||||
var trZ = RcVec3f.Of(normals[0].z, normals[1].z, normals[2].z);
|
||||
float[] spVertices = GenerateSphericalVertices();
|
||||
float halfLength = 0.5f * axis.Length();
|
||||
vertices = new float[spVertices.Length];
|
||||
gradient = new float[spVertices.Length / 3];
|
||||
RcVec3f v = new RcVec3f();
|
||||
for (int i = 0; i < spVertices.Length; i += 3)
|
||||
{
|
||||
float offset = (i >= spVertices.Length / 2) ? -halfLength : halfLength;
|
||||
float x = radius * spVertices[i];
|
||||
float y = radius * spVertices[i + 1] + offset;
|
||||
float z = radius * spVertices[i + 2];
|
||||
vertices[i] = x * trX.x + y * trX.y + z * trX.z + center[0];
|
||||
vertices[i + 1] = x * trY.x + y * trY.y + z * trY.z + center[1];
|
||||
vertices[i + 2] = x * trZ.x + y * trZ.y + z * trZ.z + center[2];
|
||||
v.x = vertices[i] - center[0];
|
||||
v.y = vertices[i + 1] - center[1];
|
||||
v.z = vertices[i + 2] - center[2];
|
||||
RcVec3f.Normalize(ref v);
|
||||
gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private RcVec3f GetSideVector(RcVec3f axis)
|
||||
{
|
||||
RcVec3f side = RcVec3f.Of(1, 0, 0);
|
||||
if (axis.x > 0.8)
|
||||
{
|
||||
side = RcVec3f.Of(0, 0, 1);
|
||||
}
|
||||
|
||||
RcVec3f forward = new RcVec3f();
|
||||
RcVec3f.Cross(ref forward, side, axis);
|
||||
RcVec3f.Cross(ref side, axis, forward);
|
||||
RcVec3f.Normalize(ref side);
|
||||
return side;
|
||||
}
|
||||
|
||||
public void Render(RecastDebugDraw debugDraw)
|
||||
{
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < triangles.Length; i += 3)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
int v = triangles[i + j] * 3;
|
||||
float c = gradient[triangles[i + j]];
|
||||
int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
|
||||
(int)(127 * (1 + c)));
|
||||
debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public class ColliderWithGizmo
|
||||
{
|
||||
public readonly ICollider Collider;
|
||||
public readonly IColliderGizmo Gizmo;
|
||||
|
||||
public ColliderWithGizmo(ICollider collider, IColliderGizmo gizmo)
|
||||
{
|
||||
Collider = collider;
|
||||
Gizmo = gizmo;
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public class CompositeGizmo : IColliderGizmo
|
||||
{
|
||||
private readonly IColliderGizmo[] gizmos;
|
||||
|
||||
public CompositeGizmo(params IColliderGizmo[] gizmos)
|
||||
{
|
||||
this.gizmos = gizmos;
|
||||
}
|
||||
|
||||
public void Render(RecastDebugDraw debugDraw)
|
||||
{
|
||||
gizmos.ForEach(g => g.Render(debugDraw));
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
using static DotRecast.Core.RcMath;
|
||||
using static DotRecast.Recast.Demo.Tools.Gizmos.GizmoHelper;
|
||||
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public class CylinderGizmo : IColliderGizmo
|
||||
{
|
||||
private readonly float[] vertices;
|
||||
private readonly int[] triangles;
|
||||
private readonly RcVec3f center;
|
||||
private readonly float[] gradient;
|
||||
|
||||
public CylinderGizmo(RcVec3f start, RcVec3f end, float radius)
|
||||
{
|
||||
center = RcVec3f.Of(
|
||||
0.5f * (start.x + end.x), 0.5f * (start.y + end.y),
|
||||
0.5f * (start.z + end.z)
|
||||
);
|
||||
RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
RcVec3f[] normals = new RcVec3f[3];
|
||||
normals[1] = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
RcVec3f.Normalize(ref normals[1]);
|
||||
normals[0] = GetSideVector(axis);
|
||||
normals[2] = RcVec3f.Zero;
|
||||
RcVec3f.Cross(ref normals[2], normals[0], normals[1]);
|
||||
RcVec3f.Normalize(ref normals[2]);
|
||||
triangles = GenerateCylindricalTriangles();
|
||||
RcVec3f trX = RcVec3f.Of(normals[0].x, normals[1].x, normals[2].x);
|
||||
RcVec3f trY = RcVec3f.Of(normals[0].y, normals[1].y, normals[2].y);
|
||||
RcVec3f trZ = RcVec3f.Of(normals[0].z, normals[1].z, normals[2].z);
|
||||
vertices = GenerateCylindricalVertices();
|
||||
float halfLength = 0.5f * axis.Length();
|
||||
gradient = new float[vertices.Length / 3];
|
||||
RcVec3f v = new RcVec3f();
|
||||
for (int i = 0; i < vertices.Length; i += 3)
|
||||
{
|
||||
float offset = (i >= vertices.Length / 2) ? -halfLength : halfLength;
|
||||
float x = radius * vertices[i];
|
||||
float y = vertices[i + 1] + offset;
|
||||
float z = radius * vertices[i + 2];
|
||||
vertices[i] = x * trX.x + y * trX.y + z * trX.z + center.x;
|
||||
vertices[i + 1] = x * trY.x + y * trY.y + z * trY.z + center.y;
|
||||
vertices[i + 2] = x * trZ.x + y * trZ.y + z * trZ.z + center.z;
|
||||
if (i < vertices.Length / 4 || i >= 3 * vertices.Length / 4)
|
||||
{
|
||||
gradient[i / 3] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
v.x = vertices[i] - center.x;
|
||||
v.y = vertices[i + 1] - center.y;
|
||||
v.z = vertices[i + 2] - center.z;
|
||||
RcVec3f.Normalize(ref v);
|
||||
gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RcVec3f GetSideVector(RcVec3f axis)
|
||||
{
|
||||
RcVec3f side = RcVec3f.Of(1, 0, 0);
|
||||
if (axis.x > 0.8)
|
||||
{
|
||||
side = RcVec3f.Of(0, 0, 1);
|
||||
}
|
||||
|
||||
RcVec3f forward = new RcVec3f();
|
||||
RcVec3f.Cross(ref forward, side, axis);
|
||||
RcVec3f.Cross(ref side, axis, forward);
|
||||
RcVec3f.Normalize(ref side);
|
||||
return side;
|
||||
}
|
||||
|
||||
public void Render(RecastDebugDraw debugDraw)
|
||||
{
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < triangles.Length; i += 3)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
int v = triangles[i + j] * 3;
|
||||
float c = gradient[triangles[i + j]];
|
||||
int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
|
||||
(int)(127 * (1 + c)));
|
||||
debugDraw.Vertex(vertices[v], vertices[v + 1], vertices[v + 2], col);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
using DotRecast.Core;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public static class GizmoFactory
|
||||
{
|
||||
public static IColliderGizmo Box(RcVec3f center, RcVec3f[] halfEdges)
|
||||
{
|
||||
return new BoxGizmo(center, halfEdges);
|
||||
}
|
||||
|
||||
public static IColliderGizmo Sphere(RcVec3f center, float radius)
|
||||
{
|
||||
return new SphereGizmo(center, radius);
|
||||
}
|
||||
|
||||
public static IColliderGizmo Capsule(RcVec3f start, RcVec3f end, float radius)
|
||||
{
|
||||
return new CapsuleGizmo(start, end, radius);
|
||||
}
|
||||
|
||||
public static IColliderGizmo Cylinder(RcVec3f start, RcVec3f end, float radius)
|
||||
{
|
||||
return new CylinderGizmo(start, end, radius);
|
||||
}
|
||||
|
||||
public static IColliderGizmo Trimesh(float[] verts, int[] faces)
|
||||
{
|
||||
return new TrimeshGizmo(verts, faces);
|
||||
}
|
||||
|
||||
public static IColliderGizmo Composite(params IColliderGizmo[] gizmos)
|
||||
{
|
||||
return new CompositeGizmo(gizmos);
|
||||
}
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
using System;
|
||||
using DotRecast.Core;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
using static DotRecast.Core.RcMath;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public class GizmoHelper
|
||||
{
|
||||
private static readonly int SEGMENTS = 16;
|
||||
private static readonly int RINGS = 8;
|
||||
|
||||
private static float[] sphericalVertices;
|
||||
|
||||
public static float[] GenerateSphericalVertices()
|
||||
{
|
||||
if (sphericalVertices == null)
|
||||
{
|
||||
sphericalVertices = GenerateSphericalVertices(SEGMENTS, RINGS);
|
||||
}
|
||||
|
||||
return sphericalVertices;
|
||||
}
|
||||
|
||||
private static float[] GenerateSphericalVertices(int segments, int rings)
|
||||
{
|
||||
float[] vertices = new float[6 + 3 * (segments + 1) * (rings + 1)];
|
||||
// top
|
||||
int vi = 0;
|
||||
vertices[vi++] = 0;
|
||||
vertices[vi++] = 1;
|
||||
vertices[vi++] = 0;
|
||||
for (int r = 0; r <= rings; r++)
|
||||
{
|
||||
double theta = Math.PI * (r + 1) / (rings + 2);
|
||||
vi = GenerateRingVertices(segments, vertices, vi, theta);
|
||||
}
|
||||
|
||||
// bottom
|
||||
vertices[vi++] = 0;
|
||||
vertices[vi++] = -1;
|
||||
vertices[vi++] = 0;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
public static float[] GenerateCylindricalVertices()
|
||||
{
|
||||
return GenerateCylindricalVertices(SEGMENTS);
|
||||
}
|
||||
|
||||
private static float[] GenerateCylindricalVertices(int segments)
|
||||
{
|
||||
float[] vertices = new float[3 * (segments + 1) * 4];
|
||||
int vi = 0;
|
||||
for (int r = 0; r < 4; r++)
|
||||
{
|
||||
vi = GenerateRingVertices(segments, vertices, vi, Math.PI * 0.5);
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
private static int GenerateRingVertices(int segments, float[] vertices, int vi, double theta)
|
||||
{
|
||||
double cosTheta = Math.Cos(theta);
|
||||
double sinTheta = Math.Sin(theta);
|
||||
for (int p = 0; p <= segments; p++)
|
||||
{
|
||||
double phi = 2 * Math.PI * p / segments;
|
||||
double cosPhi = Math.Cos(phi);
|
||||
double sinPhi = Math.Sin(phi);
|
||||
vertices[vi++] = (float)(sinTheta * cosPhi);
|
||||
vertices[vi++] = (float)cosTheta;
|
||||
vertices[vi++] = (float)(sinTheta * sinPhi);
|
||||
}
|
||||
|
||||
return vi;
|
||||
}
|
||||
|
||||
public static int[] GenerateSphericalTriangles()
|
||||
{
|
||||
return GenerateSphericalTriangles(SEGMENTS, RINGS);
|
||||
}
|
||||
|
||||
private static int[] GenerateSphericalTriangles(int segments, int rings)
|
||||
{
|
||||
int[] triangles = new int[6 * (segments + rings * (segments + 1))];
|
||||
int ti = GenerateSphereUpperCapTriangles(segments, triangles, 0);
|
||||
ti = GenerateRingTriangles(segments, rings, triangles, 1, ti);
|
||||
GenerateSphereLowerCapTriangles(segments, rings, triangles, ti);
|
||||
return triangles;
|
||||
}
|
||||
|
||||
public static int GenerateRingTriangles(int segments, int rings, int[] triangles, int vertexOffset, int ti)
|
||||
{
|
||||
for (int r = 0; r < rings; r++)
|
||||
{
|
||||
for (int p = 0; p < segments; p++)
|
||||
{
|
||||
int current = p + r * (segments + 1) + vertexOffset;
|
||||
int next = p + 1 + r * (segments + 1) + vertexOffset;
|
||||
int currentBottom = p + (r + 1) * (segments + 1) + vertexOffset;
|
||||
int nextBottom = p + 1 + (r + 1) * (segments + 1) + vertexOffset;
|
||||
triangles[ti++] = current;
|
||||
triangles[ti++] = next;
|
||||
triangles[ti++] = nextBottom;
|
||||
triangles[ti++] = current;
|
||||
triangles[ti++] = nextBottom;
|
||||
triangles[ti++] = currentBottom;
|
||||
}
|
||||
}
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
private static int GenerateSphereUpperCapTriangles(int segments, int[] triangles, int ti)
|
||||
{
|
||||
for (int p = 0; p < segments; p++)
|
||||
{
|
||||
triangles[ti++] = p + 2;
|
||||
triangles[ti++] = p + 1;
|
||||
triangles[ti++] = 0;
|
||||
}
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
private static void GenerateSphereLowerCapTriangles(int segments, int rings, int[] triangles, int ti)
|
||||
{
|
||||
int lastVertex = 1 + (segments + 1) * (rings + 1);
|
||||
for (int p = 0; p < segments; p++)
|
||||
{
|
||||
triangles[ti++] = lastVertex;
|
||||
triangles[ti++] = lastVertex - (p + 2);
|
||||
triangles[ti++] = lastVertex - (p + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] GenerateCylindricalTriangles()
|
||||
{
|
||||
return GenerateCylindricalTriangles(SEGMENTS);
|
||||
}
|
||||
|
||||
private static int[] GenerateCylindricalTriangles(int segments)
|
||||
{
|
||||
int circleTriangles = segments - 2;
|
||||
int[] triangles = new int[6 * (circleTriangles + (segments + 1))];
|
||||
int vi = 0;
|
||||
int ti = GenerateCircleTriangles(segments, triangles, vi, 0, false);
|
||||
ti = GenerateRingTriangles(segments, 1, triangles, segments + 1, ti);
|
||||
int vertexCount = (segments + 1) * 4;
|
||||
ti = GenerateCircleTriangles(segments, triangles, vertexCount - segments, ti, true);
|
||||
return triangles;
|
||||
}
|
||||
|
||||
private static int GenerateCircleTriangles(int segments, int[] triangles, int vi, int ti, bool invert)
|
||||
{
|
||||
for (int p = 0; p < segments - 2; p++)
|
||||
{
|
||||
if (invert)
|
||||
{
|
||||
triangles[ti++] = vi;
|
||||
triangles[ti++] = vi + p + 1;
|
||||
triangles[ti++] = vi + p + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
triangles[ti++] = vi + p + 2;
|
||||
triangles[ti++] = vi + p + 1;
|
||||
triangles[ti++] = vi;
|
||||
}
|
||||
}
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
public static int GetColorByNormal(float[] vertices, int v0, int v1, int v2)
|
||||
{
|
||||
RcVec3f e0 = new RcVec3f();
|
||||
RcVec3f e1 = new RcVec3f();
|
||||
RcVec3f normal = new RcVec3f();
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
e0[j] = vertices[v1 + j] - vertices[v0 + j];
|
||||
e1[j] = vertices[v2 + j] - vertices[v0 + j];
|
||||
}
|
||||
|
||||
normal.x = e0.y * e1.z - e0.z * e1.y;
|
||||
normal.y = e0.z * e1.x - e0.x * e1.z;
|
||||
normal.z = e0.x * e1.y - e0.y * e1.x;
|
||||
RcVec3f.Normalize(ref normal);
|
||||
float c = Clamp(0.57735026f * (normal.x + normal.y + normal.z), -1, 1);
|
||||
int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
|
||||
(int)(127 * (1 + c)));
|
||||
return col;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
using DotRecast.Recast.Demo.Draw;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public interface IColliderGizmo
|
||||
{
|
||||
void Render(RecastDebugDraw debugDraw);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Recast.Demo.Draw;
|
||||
using static DotRecast.Core.RcMath;
|
||||
using static DotRecast.Recast.Demo.Tools.Gizmos.GizmoHelper;
|
||||
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public class SphereGizmo : IColliderGizmo
|
||||
{
|
||||
private readonly float[] vertices;
|
||||
private readonly int[] triangles;
|
||||
private readonly float radius;
|
||||
private readonly RcVec3f center;
|
||||
|
||||
public SphereGizmo(RcVec3f center, float radius)
|
||||
{
|
||||
this.center = center;
|
||||
this.radius = radius;
|
||||
vertices = GenerateSphericalVertices();
|
||||
triangles = GenerateSphericalTriangles();
|
||||
}
|
||||
|
||||
public void Render(RecastDebugDraw debugDraw)
|
||||
{
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < triangles.Length; i += 3)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
int v = triangles[i + j] * 3;
|
||||
float c = Clamp(0.57735026f * (vertices[v] + vertices[v + 1] + vertices[v + 2]), -1, 1);
|
||||
int col = DebugDraw.DuLerpCol(DebugDraw.DuRGBA(32, 32, 0, 160), DebugDraw.DuRGBA(220, 220, 0, 160),
|
||||
(int)(127 * (1 + c)));
|
||||
debugDraw.Vertex(radius * vertices[v] + center.x, radius * vertices[v + 1] + center.y,
|
||||
radius * vertices[v + 2] + center.z, col);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
using DotRecast.Recast.Demo.Draw;
|
||||
|
||||
namespace DotRecast.Recast.Demo.Tools.Gizmos;
|
||||
|
||||
public class TrimeshGizmo : IColliderGizmo
|
||||
{
|
||||
private readonly float[] vertices;
|
||||
private readonly int[] triangles;
|
||||
|
||||
public TrimeshGizmo(float[] vertices, int[] triangles)
|
||||
{
|
||||
this.vertices = vertices;
|
||||
this.triangles = triangles;
|
||||
}
|
||||
|
||||
public void Render(RecastDebugDraw debugDraw)
|
||||
{
|
||||
debugDraw.Begin(DebugDrawPrimitives.TRIS);
|
||||
for (int i = 0; i < triangles.Length; i += 3)
|
||||
{
|
||||
int v0 = 3 * triangles[i];
|
||||
int v1 = 3 * triangles[i + 1];
|
||||
int v2 = 3 * triangles[i + 2];
|
||||
int col = GizmoHelper.GetColorByNormal(vertices, v0, v1, v2);
|
||||
debugDraw.Vertex(vertices[v0], vertices[v0 + 1], vertices[v0 + 2], col);
|
||||
debugDraw.Vertex(vertices[v1], vertices[v1 + 1], vertices[v1 + 2], col);
|
||||
debugDraw.Vertex(vertices[v2], vertices[v2 + 1], vertices[v2 + 2], col);
|
||||
}
|
||||
|
||||
debugDraw.End();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using DotRecast.Core;
|
||||
using DotRecast.Detour.Dynamic.Colliders;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools.Gizmos
|
||||
{
|
||||
public class BoxGizmo : IRcGizmoMeshFilter
|
||||
{
|
||||
public static readonly int[] TRIANLGES =
|
||||
{
|
||||
0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2,
|
||||
2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7
|
||||
};
|
||||
|
||||
public static readonly RcVec3f[] VERTS =
|
||||
{
|
||||
RcVec3f.Of(-1f, -1f, -1f),
|
||||
RcVec3f.Of(1f, -1f, -1f),
|
||||
RcVec3f.Of(1f, -1f, 1f),
|
||||
RcVec3f.Of(-1f, -1f, 1f),
|
||||
RcVec3f.Of(-1f, 1f, -1f),
|
||||
RcVec3f.Of(1f, 1f, -1f),
|
||||
RcVec3f.Of(1f, 1f, 1f),
|
||||
RcVec3f.Of(-1f, 1f, 1f),
|
||||
};
|
||||
|
||||
public readonly float[] vertices = new float[8 * 3];
|
||||
public readonly RcVec3f center;
|
||||
public readonly RcVec3f[] halfEdges;
|
||||
|
||||
public BoxGizmo(RcVec3f center, RcVec3f extent, RcVec3f forward, RcVec3f up) :
|
||||
this(center, BoxCollider.GetHalfEdges(up, forward, extent))
|
||||
{
|
||||
}
|
||||
|
||||
public BoxGizmo(RcVec3f center, RcVec3f[] halfEdges)
|
||||
{
|
||||
this.center = center;
|
||||
this.halfEdges = halfEdges;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
float s0 = (i & 1) != 0 ? 1f : -1f;
|
||||
float s1 = (i & 2) != 0 ? 1f : -1f;
|
||||
float s2 = (i & 4) != 0 ? 1f : -1f;
|
||||
vertices[i * 3 + 0] = center.x + s0 * halfEdges[0].x + s1 * halfEdges[1].x + s2 * halfEdges[2].x;
|
||||
vertices[i * 3 + 1] = center.y + s0 * halfEdges[0].y + s1 * halfEdges[1].y + s2 * halfEdges[2].y;
|
||||
vertices[i * 3 + 2] = center.z + s0 * halfEdges[0].z + s1 * halfEdges[1].z + s2 * halfEdges[2].z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
using DotRecast.Core;
|
||||
using static DotRecast.Core.RcMath;
|
||||
using static DotRecast.Recast.Toolset.Tools.Gizmos.GizmoHelper;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools.Gizmos
|
||||
{
|
||||
public class CapsuleGizmo : IRcGizmoMeshFilter
|
||||
{
|
||||
public readonly float[] vertices;
|
||||
public readonly int[] triangles;
|
||||
public readonly float[] center;
|
||||
public readonly float[] gradient;
|
||||
|
||||
public CapsuleGizmo(RcVec3f start, RcVec3f end, float radius)
|
||||
{
|
||||
center = new float[]
|
||||
{
|
||||
0.5f * (start.x + end.x), 0.5f * (start.y + end.y),
|
||||
0.5f * (start.z + end.z)
|
||||
};
|
||||
RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
RcVec3f[] normals = new RcVec3f[3];
|
||||
normals[1] = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
RcVec3f.Normalize(ref normals[1]);
|
||||
normals[0] = GetSideVector(axis);
|
||||
normals[2] = RcVec3f.Zero;
|
||||
RcVec3f.Cross(ref normals[2], normals[0], normals[1]);
|
||||
RcVec3f.Normalize(ref normals[2]);
|
||||
triangles = GenerateSphericalTriangles();
|
||||
var trX = RcVec3f.Of(normals[0].x, normals[1].x, normals[2].x);
|
||||
var trY = RcVec3f.Of(normals[0].y, normals[1].y, normals[2].y);
|
||||
var trZ = RcVec3f.Of(normals[0].z, normals[1].z, normals[2].z);
|
||||
float[] spVertices = GenerateSphericalVertices();
|
||||
float halfLength = 0.5f * axis.Length();
|
||||
vertices = new float[spVertices.Length];
|
||||
gradient = new float[spVertices.Length / 3];
|
||||
RcVec3f v = new RcVec3f();
|
||||
for (int i = 0; i < spVertices.Length; i += 3)
|
||||
{
|
||||
float offset = (i >= spVertices.Length / 2) ? -halfLength : halfLength;
|
||||
float x = radius * spVertices[i];
|
||||
float y = radius * spVertices[i + 1] + offset;
|
||||
float z = radius * spVertices[i + 2];
|
||||
vertices[i] = x * trX.x + y * trX.y + z * trX.z + center[0];
|
||||
vertices[i + 1] = x * trY.x + y * trY.y + z * trY.z + center[1];
|
||||
vertices[i + 2] = x * trZ.x + y * trZ.y + z * trZ.z + center[2];
|
||||
v.x = vertices[i] - center[0];
|
||||
v.y = vertices[i + 1] - center[1];
|
||||
v.z = vertices[i + 2] - center[2];
|
||||
RcVec3f.Normalize(ref v);
|
||||
gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private RcVec3f GetSideVector(RcVec3f axis)
|
||||
{
|
||||
RcVec3f side = RcVec3f.Of(1, 0, 0);
|
||||
if (axis.x > 0.8)
|
||||
{
|
||||
side = RcVec3f.Of(0, 0, 1);
|
||||
}
|
||||
|
||||
RcVec3f forward = new RcVec3f();
|
||||
RcVec3f.Cross(ref forward, side, axis);
|
||||
RcVec3f.Cross(ref side, axis, forward);
|
||||
RcVec3f.Normalize(ref side);
|
||||
return side;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace DotRecast.Recast.Toolset.Tools.Gizmos
|
||||
{
|
||||
public class CompositeGizmo : IRcGizmoMeshFilter
|
||||
{
|
||||
public readonly IRcGizmoMeshFilter[] gizmoMeshes;
|
||||
|
||||
public CompositeGizmo(params IRcGizmoMeshFilter[] gizmoMeshes)
|
||||
{
|
||||
this.gizmoMeshes = gizmoMeshes;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
using DotRecast.Core;
|
||||
using static DotRecast.Core.RcMath;
|
||||
using static DotRecast.Recast.Toolset.Tools.Gizmos.GizmoHelper;
|
||||
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools.Gizmos
|
||||
{
|
||||
public class CylinderGizmo : IRcGizmoMeshFilter
|
||||
{
|
||||
public readonly float[] vertices;
|
||||
public readonly int[] triangles;
|
||||
public readonly RcVec3f center;
|
||||
public readonly float[] gradient;
|
||||
|
||||
public CylinderGizmo(RcVec3f start, RcVec3f end, float radius)
|
||||
{
|
||||
center = RcVec3f.Of(
|
||||
0.5f * (start.x + end.x), 0.5f * (start.y + end.y),
|
||||
0.5f * (start.z + end.z)
|
||||
);
|
||||
RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
RcVec3f[] normals = new RcVec3f[3];
|
||||
normals[1] = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
|
||||
RcVec3f.Normalize(ref normals[1]);
|
||||
normals[0] = GetSideVector(axis);
|
||||
normals[2] = RcVec3f.Zero;
|
||||
RcVec3f.Cross(ref normals[2], normals[0], normals[1]);
|
||||
RcVec3f.Normalize(ref normals[2]);
|
||||
triangles = GenerateCylindricalTriangles();
|
||||
RcVec3f trX = RcVec3f.Of(normals[0].x, normals[1].x, normals[2].x);
|
||||
RcVec3f trY = RcVec3f.Of(normals[0].y, normals[1].y, normals[2].y);
|
||||
RcVec3f trZ = RcVec3f.Of(normals[0].z, normals[1].z, normals[2].z);
|
||||
vertices = GenerateCylindricalVertices();
|
||||
float halfLength = 0.5f * axis.Length();
|
||||
gradient = new float[vertices.Length / 3];
|
||||
RcVec3f v = new RcVec3f();
|
||||
for (int i = 0; i < vertices.Length; i += 3)
|
||||
{
|
||||
float offset = (i >= vertices.Length / 2) ? -halfLength : halfLength;
|
||||
float x = radius * vertices[i];
|
||||
float y = vertices[i + 1] + offset;
|
||||
float z = radius * vertices[i + 2];
|
||||
vertices[i] = x * trX.x + y * trX.y + z * trX.z + center.x;
|
||||
vertices[i + 1] = x * trY.x + y * trY.y + z * trY.z + center.y;
|
||||
vertices[i + 2] = x * trZ.x + y * trZ.y + z * trZ.z + center.z;
|
||||
if (i < vertices.Length / 4 || i >= 3 * vertices.Length / 4)
|
||||
{
|
||||
gradient[i / 3] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
v.x = vertices[i] - center.x;
|
||||
v.y = vertices[i + 1] - center.y;
|
||||
v.z = vertices[i + 2] - center.z;
|
||||
RcVec3f.Normalize(ref v);
|
||||
gradient[i / 3] = Clamp(0.57735026f * (v.x + v.y + v.z), -1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RcVec3f GetSideVector(RcVec3f axis)
|
||||
{
|
||||
RcVec3f side = RcVec3f.Of(1, 0, 0);
|
||||
if (axis.x > 0.8)
|
||||
{
|
||||
side = RcVec3f.Of(0, 0, 1);
|
||||
}
|
||||
|
||||
RcVec3f forward = new RcVec3f();
|
||||
RcVec3f.Cross(ref forward, side, axis);
|
||||
RcVec3f.Cross(ref side, axis, forward);
|
||||
RcVec3f.Normalize(ref side);
|
||||
return side;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
using DotRecast.Core;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools.Gizmos
|
||||
{
|
||||
public static class GizmoFactory
|
||||
{
|
||||
public static BoxGizmo Box(RcVec3f center, RcVec3f[] halfEdges)
|
||||
{
|
||||
return new BoxGizmo(center, halfEdges);
|
||||
}
|
||||
|
||||
public static SphereGizmo Sphere(RcVec3f center, float radius)
|
||||
{
|
||||
return new SphereGizmo(center, radius);
|
||||
}
|
||||
|
||||
public static CapsuleGizmo Capsule(RcVec3f start, RcVec3f end, float radius)
|
||||
{
|
||||
return new CapsuleGizmo(start, end, radius);
|
||||
}
|
||||
|
||||
public static CylinderGizmo Cylinder(RcVec3f start, RcVec3f end, float radius)
|
||||
{
|
||||
return new CylinderGizmo(start, end, radius);
|
||||
}
|
||||
|
||||
public static TrimeshGizmo Trimesh(float[] verts, int[] faces)
|
||||
{
|
||||
return new TrimeshGizmo(verts, faces);
|
||||
}
|
||||
|
||||
public static CompositeGizmo Composite(params IRcGizmoMeshFilter[] gizmos)
|
||||
{
|
||||
return new CompositeGizmo(gizmos);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
using System;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools.Gizmos
|
||||
{
|
||||
public static class GizmoHelper
|
||||
{
|
||||
private static readonly int SEGMENTS = 16;
|
||||
private static readonly int RINGS = 8;
|
||||
|
||||
private static float[] sphericalVertices;
|
||||
|
||||
public static float[] GenerateSphericalVertices()
|
||||
{
|
||||
if (sphericalVertices == null)
|
||||
{
|
||||
sphericalVertices = GenerateSphericalVertices(SEGMENTS, RINGS);
|
||||
}
|
||||
|
||||
return sphericalVertices;
|
||||
}
|
||||
|
||||
private static float[] GenerateSphericalVertices(int segments, int rings)
|
||||
{
|
||||
float[] vertices = new float[6 + 3 * (segments + 1) * (rings + 1)];
|
||||
// top
|
||||
int vi = 0;
|
||||
vertices[vi++] = 0;
|
||||
vertices[vi++] = 1;
|
||||
vertices[vi++] = 0;
|
||||
for (int r = 0; r <= rings; r++)
|
||||
{
|
||||
double theta = Math.PI * (r + 1) / (rings + 2);
|
||||
vi = GenerateRingVertices(segments, vertices, vi, theta);
|
||||
}
|
||||
|
||||
// bottom
|
||||
vertices[vi++] = 0;
|
||||
vertices[vi++] = -1;
|
||||
vertices[vi++] = 0;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
public static float[] GenerateCylindricalVertices()
|
||||
{
|
||||
return GenerateCylindricalVertices(SEGMENTS);
|
||||
}
|
||||
|
||||
private static float[] GenerateCylindricalVertices(int segments)
|
||||
{
|
||||
float[] vertices = new float[3 * (segments + 1) * 4];
|
||||
int vi = 0;
|
||||
for (int r = 0; r < 4; r++)
|
||||
{
|
||||
vi = GenerateRingVertices(segments, vertices, vi, Math.PI * 0.5);
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
private static int GenerateRingVertices(int segments, float[] vertices, int vi, double theta)
|
||||
{
|
||||
double cosTheta = Math.Cos(theta);
|
||||
double sinTheta = Math.Sin(theta);
|
||||
for (int p = 0; p <= segments; p++)
|
||||
{
|
||||
double phi = 2 * Math.PI * p / segments;
|
||||
double cosPhi = Math.Cos(phi);
|
||||
double sinPhi = Math.Sin(phi);
|
||||
vertices[vi++] = (float)(sinTheta * cosPhi);
|
||||
vertices[vi++] = (float)cosTheta;
|
||||
vertices[vi++] = (float)(sinTheta * sinPhi);
|
||||
}
|
||||
|
||||
return vi;
|
||||
}
|
||||
|
||||
public static int[] GenerateSphericalTriangles()
|
||||
{
|
||||
return GenerateSphericalTriangles(SEGMENTS, RINGS);
|
||||
}
|
||||
|
||||
private static int[] GenerateSphericalTriangles(int segments, int rings)
|
||||
{
|
||||
int[] triangles = new int[6 * (segments + rings * (segments + 1))];
|
||||
int ti = GenerateSphereUpperCapTriangles(segments, triangles, 0);
|
||||
ti = GenerateRingTriangles(segments, rings, triangles, 1, ti);
|
||||
GenerateSphereLowerCapTriangles(segments, rings, triangles, ti);
|
||||
return triangles;
|
||||
}
|
||||
|
||||
public static int GenerateRingTriangles(int segments, int rings, int[] triangles, int vertexOffset, int ti)
|
||||
{
|
||||
for (int r = 0; r < rings; r++)
|
||||
{
|
||||
for (int p = 0; p < segments; p++)
|
||||
{
|
||||
int current = p + r * (segments + 1) + vertexOffset;
|
||||
int next = p + 1 + r * (segments + 1) + vertexOffset;
|
||||
int currentBottom = p + (r + 1) * (segments + 1) + vertexOffset;
|
||||
int nextBottom = p + 1 + (r + 1) * (segments + 1) + vertexOffset;
|
||||
triangles[ti++] = current;
|
||||
triangles[ti++] = next;
|
||||
triangles[ti++] = nextBottom;
|
||||
triangles[ti++] = current;
|
||||
triangles[ti++] = nextBottom;
|
||||
triangles[ti++] = currentBottom;
|
||||
}
|
||||
}
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
private static int GenerateSphereUpperCapTriangles(int segments, int[] triangles, int ti)
|
||||
{
|
||||
for (int p = 0; p < segments; p++)
|
||||
{
|
||||
triangles[ti++] = p + 2;
|
||||
triangles[ti++] = p + 1;
|
||||
triangles[ti++] = 0;
|
||||
}
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
private static void GenerateSphereLowerCapTriangles(int segments, int rings, int[] triangles, int ti)
|
||||
{
|
||||
int lastVertex = 1 + (segments + 1) * (rings + 1);
|
||||
for (int p = 0; p < segments; p++)
|
||||
{
|
||||
triangles[ti++] = lastVertex;
|
||||
triangles[ti++] = lastVertex - (p + 2);
|
||||
triangles[ti++] = lastVertex - (p + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] GenerateCylindricalTriangles()
|
||||
{
|
||||
return GenerateCylindricalTriangles(SEGMENTS);
|
||||
}
|
||||
|
||||
private static int[] GenerateCylindricalTriangles(int segments)
|
||||
{
|
||||
int circleTriangles = segments - 2;
|
||||
int[] triangles = new int[6 * (circleTriangles + (segments + 1))];
|
||||
int vi = 0;
|
||||
int ti = GenerateCircleTriangles(segments, triangles, vi, 0, false);
|
||||
ti = GenerateRingTriangles(segments, 1, triangles, segments + 1, ti);
|
||||
int vertexCount = (segments + 1) * 4;
|
||||
ti = GenerateCircleTriangles(segments, triangles, vertexCount - segments, ti, true);
|
||||
return triangles;
|
||||
}
|
||||
|
||||
private static int GenerateCircleTriangles(int segments, int[] triangles, int vi, int ti, bool invert)
|
||||
{
|
||||
for (int p = 0; p < segments - 2; p++)
|
||||
{
|
||||
if (invert)
|
||||
{
|
||||
triangles[ti++] = vi;
|
||||
triangles[ti++] = vi + p + 1;
|
||||
triangles[ti++] = vi + p + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
triangles[ti++] = vi + p + 2;
|
||||
triangles[ti++] = vi + p + 1;
|
||||
triangles[ti++] = vi;
|
||||
}
|
||||
}
|
||||
|
||||
return ti;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
//using DotRecast.Recast.Demo.Draw;
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools.Gizmos
|
||||
{
|
||||
public interface IRcGizmoMeshFilter
|
||||
{
|
||||
//void Render(RecastDebugDraw debugDraw);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using DotRecast.Core;
|
||||
using static DotRecast.Recast.Toolset.Tools.Gizmos.GizmoHelper;
|
||||
|
||||
|
||||
namespace DotRecast.Recast.Toolset.Tools.Gizmos
|
||||
{
|
||||
public class SphereGizmo : IRcGizmoMeshFilter
|
||||
{
|
||||
public readonly float[] vertices;
|
||||
public readonly int[] triangles;
|
||||
public readonly float radius;
|
||||
public readonly RcVec3f center;
|
||||
|
||||
public SphereGizmo(RcVec3f center, float radius)
|
||||
{
|
||||
this.center = center;
|
||||
this.radius = radius;
|
||||
vertices = GenerateSphericalVertices();
|
||||
triangles = GenerateSphericalTriangles();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
namespace DotRecast.Recast.Toolset.Tools.Gizmos
|
||||
{
|
||||
public class TrimeshGizmo : IRcGizmoMeshFilter
|
||||
{
|
||||
public readonly float[] vertices;
|
||||
public readonly int[] triangles;
|
||||
|
||||
public TrimeshGizmo(float[] vertices, int[] triangles)
|
||||
{
|
||||
this.vertices = vertices;
|
||||
this.triangles = triangles;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue