Skip to content

Commit

Permalink
feat: add createCapsule in PrimitiveMesh (#515)
Browse files Browse the repository at this point in the history
* feat: add createCapsule in PrimitiveMesh
  • Loading branch information
JujieX authored Oct 11, 2021
1 parent 8c517ad commit 0e14a9f
Showing 1 changed file with 178 additions and 0 deletions.
178 changes: 178 additions & 0 deletions packages/core/src/mesh/PrimitiveMesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,127 @@ export class PrimitiveMesh {
return mesh;
}

/**
* Create a capsule mesh.
* @param engine - Engine
* @param radius - The radius of the two hemispherical ends
* @param height - The height of the cylindrical part, measured between the centers of the hemispherical ends
* @param radialSegments - Hemispherical end radial segments
* @param heightSegments - Cylindrical part height segments
* @param noLongerAccessible - No longer access the vertices of the mesh after creation
* @returns Capsule model mesh
*/
static createCapsule(
engine: Engine,
radius: number = 0.5,
height: number = 2,
radialSegments: number = 6,
heightSegments: number = 1,
noLongerAccessible: boolean = true
): ModelMesh {
const mesh = new ModelMesh(engine);

radialSegments = Math.max(2, Math.floor(radialSegments));
heightSegments = Math.floor(heightSegments);

const radialCount = radialSegments + 1;
const verticalCount = heightSegments + 1;
const halfHeight = height * 0.5;
const unitHeight = height / heightSegments;
const torsoVertexCount = radialCount * verticalCount;
const torsoRectangleCount = radialSegments * heightSegments;

const capVertexCount = radialCount * radialCount;
const capRectangleCount = radialSegments * radialSegments;

const totalVertexCount = torsoVertexCount + 2 * capVertexCount;
const indices = PrimitiveMesh._generateIndices(
engine,
totalVertexCount,
(torsoRectangleCount + 2 * capRectangleCount) * 6
);

const radialCountReciprocal = 1.0 / radialCount;
const radialSegmentsReciprocal = 1.0 / radialSegments;
const heightSegmentsReciprocal = 1.0 / heightSegments;

const halfPI = Math.PI / 2;
const doublePI = Math.PI * 2;

const positions = new Array<Vector3>(totalVertexCount);
const normals = new Array<Vector3>(totalVertexCount);
const uvs = new Array<Vector2>(totalVertexCount);

let indicesOffset = 0;

// create torso
for (let i = 0; i < torsoVertexCount; ++i) {
const x = i % radialCount;
const y = (i * radialCountReciprocal) | 0;
const u = x * radialSegmentsReciprocal;
const v = y * heightSegmentsReciprocal;
const theta = -halfPI + u * doublePI;
const sinTheta = Math.sin(theta);
const cosTheta = Math.cos(theta);

positions[i] = new Vector3(radius * sinTheta, y * unitHeight - halfHeight, radius * cosTheta);
normals[i] = new Vector3(sinTheta, 0, cosTheta);
uvs[i] = new Vector2(u, 1 - v);
}

for (let i = 0; i < torsoRectangleCount; ++i) {
const x = i % radialSegments;
const y = (i * radialSegmentsReciprocal) | 0;

const a = y * radialCount + x;
const b = a + 1;
const c = a + radialCount;
const d = c + 1;

indices[indicesOffset++] = b;
indices[indicesOffset++] = c;
indices[indicesOffset++] = a;
indices[indicesOffset++] = b;
indices[indicesOffset++] = d;
indices[indicesOffset++] = c;
}

PrimitiveMesh._createCapsuleCap(
radius,
height,
radialSegments,
doublePI,
torsoVertexCount,
1,
positions,
normals,
uvs,
indices,
indicesOffset
);

PrimitiveMesh._createCapsuleCap(
radius,
height,
radialSegments,
-doublePI,
torsoVertexCount + capVertexCount,
-1,
positions,
normals,
uvs,
indices,
indicesOffset + 6 * capRectangleCount
);

const { bounds } = mesh;
bounds.min.setValue(-radius, -radius - halfHeight, -radius);
bounds.max.setValue(radius, radius + halfHeight, radius);

PrimitiveMesh._initialize(mesh, positions, normals, uvs, indices, noLongerAccessible);
return mesh;
}

private static _initialize(
mesh: ModelMesh,
positions: Vector3[],
Expand Down Expand Up @@ -702,4 +823,61 @@ export class PrimitiveMesh {
}
return indices;
}

private static _createCapsuleCap(
radius: number,
height: number,
radialSegments: number,
capAlphaRange: number,
offset: number,
posIndex: number,
positions: Vector3[],
normals: Vector3[],
uvs: Vector2[],
indices: Uint16Array | Uint32Array,
indicesOffset: number
) {
const radialCount = radialSegments + 1;
const halfHeight = height * 0.5;
const capVertexCount = radialCount * radialCount;
const capRectangleCount = radialSegments * radialSegments;
const radialCountReciprocal = 1.0 / radialCount;
const radialSegmentsReciprocal = 1.0 / radialSegments;

for (let i = 0; i < capVertexCount; ++i) {
const x = i % radialCount;
const y = (i * radialCountReciprocal) | 0;
const u = x * radialSegmentsReciprocal;
const v = y * radialSegmentsReciprocal;
const alphaDelta = u * capAlphaRange;
const thetaDelta = (v * Math.PI) / 2;
const sinTheta = Math.sin(thetaDelta);

const posX = -radius * Math.cos(alphaDelta) * sinTheta;
const posY = (radius * Math.cos(thetaDelta) + halfHeight) * posIndex;
const posZ = radius * Math.sin(alphaDelta) * sinTheta;

const index = i + offset;
positions[index] = new Vector3(posX, posY, posZ);
normals[index] = new Vector3(posX, posY, posZ);
uvs[index] = new Vector2(u, v);
}

for (let i = 0; i < capRectangleCount; ++i) {
const x = i % radialSegments;
const y = (i * radialSegmentsReciprocal) | 0;

const a = y * radialCount + x + offset;
const b = a + 1;
const c = a + radialCount;
const d = c + 1;

indices[indicesOffset++] = b;
indices[indicesOffset++] = a;
indices[indicesOffset++] = d;
indices[indicesOffset++] = a;
indices[indicesOffset++] = c;
indices[indicesOffset++] = d;
}
}
}

0 comments on commit 0e14a9f

Please sign in to comment.