Skip to content

Commit

Permalink
feat: add particle shape wireframe
Browse files Browse the repository at this point in the history
  • Loading branch information
JujieX committed Jan 16, 2024
1 parent 8990978 commit 514e258
Show file tree
Hide file tree
Showing 2 changed files with 341 additions and 2 deletions.
157 changes: 155 additions & 2 deletions packages/auxiliary-lines/src/WireframeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ import {
SpotLight,
Transform,
Vector3,
DependentMode
DependentMode,
ParticleRenderer,
BoxShape,
CircleShape,
ConeShape,
HemisphereShape,
SphereShape
} from "@galacean/engine";
import { PlainColorMaterial } from "@galacean/engine-toolkit-custom-material";
import { WireframePrimitive } from "./WireframePrimitive";
Expand Down Expand Up @@ -111,7 +117,7 @@ export class WireframeManager extends Script {
*/
addEntityWireframe(entity: Entity, includeChildren = true): void {
if (includeChildren) {
const components = new Array<Camera | SpotLight | DirectLight | PointLight | Collider>();
const components = new Array<Camera | SpotLight | DirectLight | PointLight | Collider | ParticleRenderer>();
entity.getComponentsIncludeChildren(Camera, components);
for (let i = 0, n = components.length; i < n; i++) {
this.addCameraWireframe(<Camera>components[i]);
Expand Down Expand Up @@ -140,6 +146,12 @@ export class WireframeManager extends Script {
for (let i = componentsOffset, n = components.length; i < n; i++) {
this.addCollideWireframe(<Collider>components[i]);
}
componentsOffset = components.length;

entity.getComponentsIncludeChildren(ParticleRenderer, components);
for (let i = componentsOffset, n = components.length; i < n; i++) {
this.addParticleRendererEmissionShapeWireframe(<ParticleRenderer>components[i]);
}
} else {
const camera = entity.getComponent(Camera);
camera && this.addCameraWireframe(camera);
Expand All @@ -151,6 +163,8 @@ export class WireframeManager extends Script {
pointLight && this.addPointLightWireframe(pointLight);
const collider = entity.getComponent(Collider);
collider && this.addCollideWireframe(collider);
const particle = entity.getComponent(ParticleRenderer);
particle && this.addParticleRendererEmissionShapeWireframe(particle);
}
}

Expand Down Expand Up @@ -427,6 +441,145 @@ export class WireframeManager extends Script {
this._wireframeElements.push(new WireframeElement(transform, positionsOffset));
}

addParticleRendererEmissionShapeWireframe(particleRenderer: ParticleRenderer): void {
if (particleRenderer.generator.emission.enabled) {
const shape = particleRenderer.generator.emission.shape;
const transform = particleRenderer.entity.transform;
switch (shape.shapeType) {
case 0:
this.addBoxParticleShapeWireframe(shape as BoxShape, transform);
break;
case 1:
this.addCircleParticleShapeWireframe(shape as CircleShape, transform);
break;
case 2:
this.addConeParticleShapeWireframe(shape as ConeShape, transform);
break;
case 3:
this.addHemisphereParticleShapeWireframe(shape as HemisphereShape, transform);
break;
case 4:
this.addSphereParticleShapeWireframe(shape as SphereShape, transform);
break;
default:
break;
}
}
}

addBoxParticleShapeWireframe(shape: BoxShape, transform: Transform): void {
const worldScale = transform.lossyWorldScale;
const { size } = shape;

const positionsOffset = this._localPositions.length;

const cuboidIndicesCount = WireframePrimitive.cuboidIndexCount;
this._growthIndexMemory(cuboidIndicesCount);
this._growthPosition(WireframePrimitive.cuboidPositionCount);
const { _indices: indices, _localPositions: localPositions } = this;
WireframePrimitive.createCuboidWireframe(
worldScale.x * size.x,
worldScale.y * size.y,
worldScale.z * size.z,
localPositions,
positionsOffset,
indices,
this._indicesCount
);

this._indicesCount += cuboidIndicesCount;
this._wireframeElements.push(new WireframeElement(transform, positionsOffset));
}

addCircleParticleShapeWireframe(shape: CircleShape, transform: Transform): void {
const worldScale = transform.lossyWorldScale;
const { radius } = shape;

const positionsOffset = this._localPositions.length;

const circleIndicesCount = WireframePrimitive.circleIndexCount;
this._growthIndexMemory(circleIndicesCount);
this._growthPosition(WireframePrimitive.circlePositionCount);
const { _indices: indices, _localPositions: localPositions } = this;
WireframePrimitive.createCircleWireframe(
Math.max(worldScale.x, worldScale.y, worldScale.z) * radius,
0,
new Vector3(),
localPositions,
positionsOffset,
indices,
this._indicesCount
);
this._indicesCount += circleIndicesCount;
this._wireframeElements.push(new WireframeElement(transform, positionsOffset));
}

addConeParticleShapeWireframe(shape: ConeShape, transform: Transform): void {
const worldScale = transform.lossyWorldScale;
const { radius, length, angle } = shape;

const positionsOffset = this._localPositions.length;

const frustumIndicesCount = WireframePrimitive.frustumIndexCount;
this._growthIndexMemory(frustumIndicesCount);
this._growthPosition(WireframePrimitive.frustumPositionCount);
const { _indices: indices, _localPositions: localPositions } = this;
WireframePrimitive.createFrustumWireframe(
Math.max(worldScale.x, worldScale.y, worldScale.z) * radius,
length,
angle,
localPositions,
positionsOffset,
indices,
this._indicesCount
);
this._indicesCount += frustumIndicesCount;
this._wireframeElements.push(new WireframeElement(transform, positionsOffset));
}

addHemisphereParticleShapeWireframe(shape: HemisphereShape, transform: Transform): void {
const worldScale = transform.lossyWorldScale;
const { radius } = shape;

const positionsOffset = this._localPositions.length;

const hemisphereIndicesCount = WireframePrimitive.hemisphereIndexCount;
this._growthIndexMemory(hemisphereIndicesCount);
this._growthPosition(WireframePrimitive.hemispherePositionCount);
const { _indices: indices, _localPositions: localPositions } = this;
WireframePrimitive.createHemisphereWireframe(
Math.max(worldScale.x, worldScale.y, worldScale.z) * radius,
2,
localPositions,
positionsOffset,
indices,
this._indicesCount
);
this._indicesCount += hemisphereIndicesCount;
this._wireframeElements.push(new WireframeElement(transform, positionsOffset));
}

addSphereParticleShapeWireframe(shape: SphereShape, transform: Transform): void {
const worldScale = transform.lossyWorldScale;
const { radius } = shape;

const positionsOffset = this._localPositions.length;

const sphereIndicesCount = WireframePrimitive.sphereIndexCount;
this._growthIndexMemory(sphereIndicesCount);
this._growthPosition(WireframePrimitive.spherePositionCount);
const { _indices: indices, _localPositions: localPositions } = this;
WireframePrimitive.createSphereWireframe(
Math.max(worldScale.x, worldScale.y, worldScale.z) * radius,
localPositions,
positionsOffset,
indices,
this._indicesCount
);
this._indicesCount += sphereIndicesCount;
this._wireframeElements.push(new WireframeElement(transform, positionsOffset));
}

override onAwake(): void {
const engine = this.engine;
const mesh = new ModelMesh(engine);
Expand Down
186 changes: 186 additions & 0 deletions packages/auxiliary-lines/src/WireframePrimitive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,34 @@ export class WireframePrimitive {
return WireframePrimitive.circleVertexCount;
}

/**
* Get frustum wire frame index count.
*/
static get frustumIndexCount(): number {
return WireframePrimitive.circleIndexCount * 2 + 10;
}

/**
* Get frustum wire frame position count.
*/
static get frustumPositionCount(): number {
return WireframePrimitive.circleVertexCount * 2 + 10;
}

/**
* Get hemisphere wire frame index count.
*/
static get hemisphereIndexCount(): number {
return WireframePrimitive.circleVertexCount * 2 + WireframePrimitive.circleIndexCount;
}

/**
* Get hemisphere wire frame position count.
*/
static get hemispherePositionCount(): number {
return WireframePrimitive.circleVertexCount + 2 + WireframePrimitive.circlePositionCount;
}

/**
* Store cuboid wireframe mesh data.
* The origin located in center of cuboid.
Expand Down Expand Up @@ -555,4 +583,162 @@ export class WireframePrimitive {
}
}
}

/**
* Store frustum wireframe mesh data.
* The origin located in the center of cap.
* @param radius - The radius of cap
* @param height - The height of cone
* @param angle - The angle of cone
* @param positions - position array
* @param positionOffset - The min of index list
* @param indices - index array
* @param indicesOffset - index array offset
*/
static createFrustumWireframe(
radius: number,
height: number,
angle: number,
positions: Vector3[],
positionOffset: number,
indices: Uint16Array | Uint32Array,
indicesOffset: number
): void {
WireframePrimitive._shift.set(0, 0, 0);

// Z
WireframePrimitive.createCircleWireframe(
radius,
2,
WireframePrimitive._shift,
positions,
positionOffset,
indices,
indicesOffset
);

WireframePrimitive._shift.set(0, 0, -height);
const radian = MathUtil.degreeToRadian(angle);
const dirSinA = Math.sin(radian);
const bottomRadius = radius + dirSinA * height;

WireframePrimitive.createCircleWireframe(
bottomRadius,
2,
WireframePrimitive._shift,
positions,
positionOffset + WireframePrimitive.circleVertexCount,
indices,
indicesOffset + WireframePrimitive.circleIndexCount
);

const indexBegin = positionOffset + 2 * WireframePrimitive.circleVertexCount;
let offset = indexBegin;

positions[offset++].set(0, 0, 0);
positions[offset++].set(0, 0, -height);
positions[offset++].set(radius, 0, 0);
positions[offset++].set(bottomRadius, 0, -height);
positions[offset++].set(-radius, 0, 0);
positions[offset++].set(-bottomRadius, 0, -height);
positions[offset++].set(0, radius, 0);
positions[offset++].set(0, bottomRadius, -height);
positions[offset++].set(0, -radius, 0);
positions[offset++].set(0, -bottomRadius, -height);

indicesOffset += 2 * WireframePrimitive.circleIndexCount;
indices[indicesOffset++] = indexBegin;
indices[indicesOffset++] = indexBegin + 1;
indices[indicesOffset++] = indexBegin + 2;
indices[indicesOffset++] = indexBegin + 3;
indices[indicesOffset++] = indexBegin + 4;
indices[indicesOffset++] = indexBegin + 5;
indices[indicesOffset++] = indexBegin + 6;
indices[indicesOffset++] = indexBegin + 7;
indices[indicesOffset++] = indexBegin + 8;
indices[indicesOffset++] = indexBegin + 9;
}

/**
* Store hemisphere wireframe mesh data.
* @param radius - The radius of hemisphere
* @param axis - The default direction
* @param positions - position array
* @param positionOffset - The min of index list
* @param indices - index array
* @param indicesOffset - index array offset
*/
static createHemisphereWireframe(
radius: number,
axis: number,
positions: Vector3[],
positionOffset: number,
indices: Uint16Array | Uint32Array,
indicesOffset: number
): void {
const vertexCount = WireframePrimitive.circleVertexCount / 2;
const twoPi = Math.PI;
const countReciprocal = 1.0 / vertexCount;

let offset = positionOffset;
for (let i = 0; i < vertexCount + 1; i++) {
const v = i * countReciprocal;
const thetaDelta = v * twoPi;

switch (axis) {
case 0:
positions[offset++].set(radius * Math.sin(thetaDelta), 0, radius * Math.cos(thetaDelta));
break;
case 1:
positions[offset++].set(0, radius * Math.sin(thetaDelta), radius * Math.cos(thetaDelta));
break;
case 2:
positions[offset++].set(-radius * Math.cos(thetaDelta), 0, -radius * Math.sin(thetaDelta));
break;
}

const globalIndex = i + positionOffset;

if (i < vertexCount) {
indices[indicesOffset + 2 * i] = globalIndex;
indices[indicesOffset + 2 * i + 1] = globalIndex + 1;
}
}

indicesOffset += WireframePrimitive.circleVertexCount;
for (let i = 0; i < vertexCount + 1; i++) {
const v = i * countReciprocal;
const thetaDelta = v * twoPi;

switch (axis) {
case 0:
positions[offset++].set(radius * Math.sin(thetaDelta), radius * Math.cos(thetaDelta), 0);
break;
case 1:
positions[offset++].set(radius * Math.cos(thetaDelta), radius * Math.sin(thetaDelta), 0);
break;
case 2:
positions[offset++].set(0, -radius * Math.cos(thetaDelta), -radius * Math.sin(thetaDelta));
break;
}

const globalIndex = i + positionOffset + vertexCount + 1;

if (i < vertexCount) {
indices[indicesOffset + 2 * i] = globalIndex;
indices[indicesOffset + 2 * i + 1] = globalIndex + 1;
}
}

WireframePrimitive._shift.set(0, 0, 0);
WireframePrimitive.createCircleWireframe(
radius,
axis,
WireframePrimitive._shift,
positions,
positionOffset + WireframePrimitive.circleVertexCount + 2,
indices,
indicesOffset + WireframePrimitive.circleVertexCount
);
}
}

0 comments on commit 514e258

Please sign in to comment.