Skip to content

Commit

Permalink
ecere/gfx/3D/Display: Support for picking skinned meshes
Browse files Browse the repository at this point in the history
  • Loading branch information
jerstlouis committed Apr 1, 2023
1 parent 1625a0f commit 23c7bbc
Showing 1 changed file with 80 additions and 5 deletions.
85 changes: 80 additions & 5 deletions ecere/src/gfx/Display.ec
Original file line number Diff line number Diff line change
Expand Up @@ -1697,10 +1697,11 @@ private class Display3D : struct

bool PickPrimitives(Mesh mesh, PrimitiveSingle primitive, Vector3D rayDiff, Vector3D rayIntersect)
{
return PickPrimitivesEx(mesh, primitive, rayDiff, rayIntersect, 0, null);
float * vertices = (float *)(mesh.skin && mesh.skin.vertices ? mesh.skin.vertices : mesh.vertices);
return PickPrimitivesEx(mesh, vertices, primitive, rayDiff, rayIntersect, 0, null);
}

bool PickPrimitivesEx(Mesh mesh, PrimitiveSingle primitive, Vector3D rayDiff, Vector3D rayIntersect,
bool PickPrimitivesEx(Mesh mesh, float * vertices, PrimitiveSingle primitive, Vector3D rayDiff, Vector3D rayIntersect,
int groupIx, uint64 * id)
{
Plane * planes = localPickingPlanes;
Expand All @@ -1720,7 +1721,7 @@ private class Display3D : struct
Array<MeshPart> parts = mesh.parts;
int pi;
int firstPart = 0, lastPart = 0;
float * vertices = (float *)(mesh.skin && mesh.skin.vertices ? mesh.skin.vertices : mesh.vertices);
// float * vertices = (float *)(mesh.skin && mesh.skin.vertices ? mesh.skin.vertices : mesh.vertices);
int vStride = mesh.flags.interleaved ? 8 : 3;

if(!vertices || (!indices32 && !indices16)) return false; // Need vertices and indices here...
Expand Down Expand Up @@ -2000,11 +2001,83 @@ private class Display3D : struct
return PickMeshEx(object, rayIntersect, null);
}

#define GPU_SKIN
static inline void ::inlineMultMatrix(Vector3Df dest, const Vector3Df source, const Matrixf matrix)
{
dest.x = (float)(source.x * matrix.m[0][0] + source.y * matrix.m[1][0] + source.z * matrix.m[2][0] + matrix.m[3][0]);
dest.y = (float)(source.x * matrix.m[0][1] + source.y * matrix.m[1][1] + source.z * matrix.m[2][1] + matrix.m[3][1]);
dest.z = (float)(source.x * matrix.m[0][2] + source.y * matrix.m[1][2] + source.z * matrix.m[2][2] + matrix.m[3][2]);
}

bool PickMeshEx(Object object, Vector3D rayIntersect, uint64 * id)
{
Mesh mesh = object.mesh;
bool result = false;
Vector3D rayDiff { MAXFLOAT, MAXFLOAT, MAXFLOAT };
Vector3Df * vertices = mesh.vertices;
Vector3Df * tmpVertices = null;

#ifdef GPU_SKIN
// We need to apply bone weights for picking
MeshSkin skin = mesh.skin;
if(skin)
{
Vector3Df * oVertices = mesh.vertices;
int nVertices = skin.skinVerts.count;
Array<Matrixf> matBones = mesh.matBones;
int i;

// Lock({ vertices = true });
vertices = tmpVertices = new Vector3Df[mesh.nVertices];

for(i = 0; i < nVertices; i++)
{
Vector3Df * vert = &vertices[i];
SkinVert * sv = &skin.skinVerts[i];
int j;
float tw = 0;
Vector3Df vt { };
for(j = 0; j < MAX_BONES; j++)
{
int b = sv->bones[j];
if(b != NO_BONE)
{
float w = sv->weights[j] / 255.0f;
Vector3Df v;
inlineMultMatrix(v, oVertices[i], matBones[b]);
tw += w;
vt.x += w * v.x;
vt.y += w * v.y;
vt.z += w * v.z;
}
else
break;
}

if(tw)
{
tw = 1.0f / tw;
vert->x = vt.x * tw;
vert->y = vt.y * tw;
vert->z = vt.z * tw;
}
else
*vert = oVertices[i];
}

if(mesh.dupVerts)
{
int * dv = mesh.dupVerts.array - nVertices;
int count = nVertices + mesh.dupVerts.count;
for(i = nVertices; i < count; i++)
{
int ix = dv[i];
vertices[i] = vertices[ix];
}
}
}
#endif

if(rayIntersect != null)
rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };

Expand All @@ -2015,7 +2088,7 @@ private class Display3D : struct

for(group = mesh.groups.first; group; group = group.next)
{
if(!group.type.hide && PickPrimitivesEx(mesh, (PrimitiveSingle *)&group.type, rayDiff, rayIntersect, groupIX, id))
if(!group.type.hide && PickPrimitivesEx(mesh, (float *) vertices, (PrimitiveSingle *)&group.type, rayDiff, rayIntersect, groupIX, id))
{
result = true;
if(!intersecting)
Expand All @@ -2030,14 +2103,16 @@ private class Display3D : struct
int c;
for(c = 0; c < mesh.nPrimitives; c++)
{
if(PickPrimitives(mesh, mesh.primitives[c], rayDiff, rayIntersect))
if(PickPrimitivesEx(mesh, (float *) vertices, mesh.primitives[c], rayDiff, rayIntersect, 0, null))
{
result = true;
if(!intersecting)
break;
}
}
}
delete tmpVertices;

return result;
}
};
Expand Down

0 comments on commit 23c7bbc

Please sign in to comment.