Skip to content

Commit

Permalink
Rework entity placement, increases entity manager update performance
Browse files Browse the repository at this point in the history
  • Loading branch information
nickyvanurk committed Sep 27, 2024
1 parent 4ea3ca5 commit c989d76
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 169 deletions.
1 change: 1 addition & 0 deletions engine/core/TaroEntity.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ var TaroEntity = TaroObject.extend({
}

self.billboard(!!body['isBillboard']);
self.globalSpace(!!body['globalSpace']);

if (!body.rotate) body.rotate = { x: 0, y: 0, z: 0 };
body.rotate.x ||= 0;
Expand Down
14 changes: 14 additions & 0 deletions engine/core/TaroObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,20 @@ var TaroObject = TaroEventingClass.extend({
return this._billboard;
},

globalSpace: function (val) {
if (val !== undefined) {
this._globalSpace = val;

if (taro.isClient) {
this.emit('globalSpace', [val]);
}

return this;
}

return this._globalSpace;
},

// NOTE(nick): Supports "Rotate (3D)" editor setting under entity body,
// probably wanna rework this when the engine support 3D better/properly.
rotate3d: function (x, y, z) {
Expand Down
2 changes: 1 addition & 1 deletion ts/src/renderer/three/AnimatedSprite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ namespace Renderer {
setTextureSheet(spriteSheet: TextureSheet) {
this.spriteSheet = spriteSheet;

super.setTexture(spriteSheet.texture, spriteSheet.key);
super.setTexture(spriteSheet.key);

this.tileH = 1 / (spriteSheet.width / spriteSheet.tileWidth);
this.tileV = 1 / (spriteSheet.height / spriteSheet.tileHeight);
Expand Down
5 changes: 2 additions & 3 deletions ts/src/renderer/three/EntityEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ namespace Renderer {

updatePreview(): void {
this.previewGroup.clear();
const renderer = Renderer.Three.instance();
if (this.activeEntity.length === 0) {
if (this.previewGroup) {
this.previewGroup.visible = false;
Expand Down Expand Up @@ -246,7 +245,7 @@ namespace Renderer {
const texture = new TextureSheet(key, tex, frameWidth, frameHeight);

newPreview = new Renderer.Three.AnimatedSprite(texture) as Renderer.Three.AnimatedSprite;
newPreview.setBillboard(entity.isBillboard, renderer.camera);
newPreview.setBillboard(entity.isBillboard);
newPreview.scale.set(Utils.pixelToWorld(width), 1, Utils.pixelToWorld(height));
newPreview.setOpacity(0.5);

Expand Down Expand Up @@ -306,7 +305,7 @@ namespace Renderer {
}
this.previewGroup.children.forEach((child) => {
if (child instanceof Renderer.Three.AnimatedSprite) {
child.setBillboard(child.billboard, renderer.camera);
child.setBillboard(child.billboard);
}
});
}
Expand Down
57 changes: 31 additions & 26 deletions ts/src/renderer/three/EntityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ namespace Renderer {
private animatedSprites: AnimatedSprite[] = [];
private unownedItems = new Map<string, Item>();

private tempVec3 = new THREE.Vector3();
private tempQuat = new THREE.Quaternion();

create(taroEntity: TaroEntityPhysics, type: 'unit' | 'item' | 'projectile' | 'region') {
let entity;

Expand Down Expand Up @@ -89,34 +92,36 @@ namespace Renderer {
instancedSprite.count = 0;
}

const tempVec3 = new THREE.Vector3();
const tempQuat = new THREE.Quaternion();

for (const entity of this.animatedSprites) {
entity.update(dt);

if (!entity.visible) continue;

const isGameObject = entity instanceof Unit || entity instanceof Projectile || entity instanceof Item;

if (isGameObject && entity.body instanceof Sprite) {
const instancedSprite = Three.instance().instancedSprites.get(entity.body.key);
if (instancedSprite) {
const pos = entity.body.sprite.getWorldPosition(tempVec3);
const q = entity.body.sprite.getWorldQuaternion(tempQuat);

const index = instancedSprite.count;
instancedSprite.setPositionAt(index, pos);
instancedSprite.setScaleAt(index, { x: entity.body.sprite.scale.x, y: entity.body.sprite.scale.z });
instancedSprite.setQuaternionAt(index, q);
instancedSprite.setUVRepeatAt(index, { x: entity.body.tileH, y: entity.body.tileV });
instancedSprite.setUVOffsetAt(index, { x: entity.body.offsetX, y: entity.body.offsetY });
instancedSprite.setOpacityAt(index, entity.body.opacity);
instancedSprite.setCastShadowAt(index, entity.castShadow);
instancedSprite.count++;
const updateEntities = (entities) => {
for (const entity of entities) {
entity.update(dt);

if (!entity.visible) continue;

if (entity.body instanceof Sprite) {
const instancedSprite = Three.instance().instancedSprites.get(entity.body.key);

if (instancedSprite) {
const pos = this.tempVec3.copy(Three.getEntitiesLayer().position).add(entity.position);
const q = this.tempQuat.copy(entity.quaternion).multiply(entity.body.quaternion);

const index = instancedSprite.count;
instancedSprite.setPositionAt(index, pos);
instancedSprite.setScaleAt(index, { x: entity.body.sprite.scale.x, y: entity.body.sprite.scale.z });
instancedSprite.setQuaternionAt(index, q);
instancedSprite.setUVRepeatAt(index, { x: entity.body.tileH, y: entity.body.tileV });
instancedSprite.setUVOffsetAt(index, { x: entity.body.offsetX, y: entity.body.offsetY });
instancedSprite.setOpacityAt(index, entity.body.opacity);
instancedSprite.setCastShadowAt(index, entity.castShadow);
instancedSprite.count++;
}
}
}
}
};

updateEntities(this.units);
updateEntities(this.items);
updateEntities(this.projectiles);
}

scaleGui(scale: number) {
Expand Down
3 changes: 1 addition & 2 deletions ts/src/renderer/three/InitEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace Renderer {
entity: InitEntity;
};
(body.sprite as THREE.Mesh & { entity: InitEntity }).entity = this;
body.setBillboard(this.isBillboard, renderer.camera);
body.setBillboard(this.isBillboard);
}
body.entity = this;
this.rotation.order = 'YXZ';
Expand Down Expand Up @@ -231,7 +231,6 @@ namespace Renderer {
Utils.pixelToWorld(this.defaultHeight * action.scale.y)
);
} else {

this.setSize(action.scale.x, action.scale.z, action.scale.y);
}
}
Expand Down
35 changes: 28 additions & 7 deletions ts/src/renderer/three/InstancedSprite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,34 @@ namespace Renderer {
const opacity = new Float32Array(count).fill(1);
const castShadow = new Float32Array(count).fill(0);

this.geometry.setAttribute('instanceOffset', new THREE.InstancedBufferAttribute(offsets, 3));
this.geometry.setAttribute('instanceScale', new THREE.InstancedBufferAttribute(scales, 2));
this.geometry.setAttribute('instanceQuaternion', new THREE.InstancedBufferAttribute(quaternions, 4));
this.geometry.setAttribute('instanceUvRepeat', new THREE.InstancedBufferAttribute(uvRepeat, 2));
this.geometry.setAttribute('instanceUvOffset', new THREE.InstancedBufferAttribute(uvOffset, 2));
this.geometry.setAttribute('instanceOpacity', new THREE.InstancedBufferAttribute(opacity, 1));
this.geometry.setAttribute('instanceCastShadow', new THREE.InstancedBufferAttribute(castShadow, 1));
this.geometry.setAttribute(
'instanceOffset',
new THREE.InstancedBufferAttribute(offsets, 3).setUsage(THREE.DynamicDrawUsage)
);
this.geometry.setAttribute(
'instanceScale',
new THREE.InstancedBufferAttribute(scales, 2).setUsage(THREE.DynamicDrawUsage)
);
this.geometry.setAttribute(
'instanceQuaternion',
new THREE.InstancedBufferAttribute(quaternions, 4).setUsage(THREE.DynamicDrawUsage)
);
this.geometry.setAttribute(
'instanceUvRepeat',
new THREE.InstancedBufferAttribute(uvRepeat, 2).setUsage(THREE.DynamicDrawUsage)
);
this.geometry.setAttribute(
'instanceUvOffset',
new THREE.InstancedBufferAttribute(uvOffset, 2).setUsage(THREE.DynamicDrawUsage)
);
this.geometry.setAttribute(
'instanceOpacity',
new THREE.InstancedBufferAttribute(opacity, 1).setUsage(THREE.DynamicDrawUsage)
);
this.geometry.setAttribute(
'instanceCastShadow',
new THREE.InstancedBufferAttribute(castShadow, 1).setUsage(THREE.DynamicDrawUsage)
);

this.material = new THREE.MeshStandardMaterial({
map: texture,
Expand Down
10 changes: 5 additions & 5 deletions ts/src/renderer/three/Renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,11 @@ namespace Renderer {
if (dt <= 0) dt = 1 / 60;
else if (dt >= 0.25) dt = 0.25;

now = performance.now();
this.camera.update(dt);
curr = performance.now() - now;
times.cameraUpdate += curr;

now = performance.now();
this.entityManager.update(dt);
curr = performance.now() - now;
Expand All @@ -1267,11 +1272,6 @@ namespace Renderer {
curr = performance.now() - now;
times.particleSystemUpdate += curr;

now = performance.now();
this.camera.update(dt);
curr = performance.now() - now;
times.cameraUpdate += curr;

now = performance.now();
this.voxelEditor.update();
curr = performance.now() - now;
Expand Down
27 changes: 14 additions & 13 deletions ts/src/renderer/three/Sprite.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
namespace Renderer {
export namespace Three {
export class Sprite extends Node {
root = new THREE.Object3D();
sprite = new THREE.Object3D();
billboard = false;
scaleUnflipped = new THREE.Vector2(1, 1);
opacity = 1;

depthOffset = 0;
yOffset = 0;

private depth = 1;
private flipX = 1;
private flipY = 1;
Expand All @@ -17,15 +19,11 @@ namespace Renderer {
public key: string
) {
super();

this.root.add(this.sprite);
this.add(this.root);
}

setBillboard(billboard: boolean, camera: Camera) {
setBillboard(billboard: boolean) {
this.billboard = billboard;
if (this.billboard) {
this.faceCamera(camera);
this.correctZOffsetBasedOnCameraAngle();
} else {
this.resetRotation();
Expand All @@ -50,7 +48,7 @@ namespace Renderer {
this.calcRenderOrder();
}

setTexture(tex: THREE.Texture, key: string) {
setTexture(key: string) {
this.key = key;
}

Expand All @@ -69,20 +67,23 @@ namespace Renderer {
}

update(_dt: number) {
const parent = this.parent as Unit | Item;
const isOwnedItem = parent && parent instanceof Item && parent.ownerUnit;

if (isOwnedItem) return;

if (this.billboard) {
this.faceCamera(Three.instance().camera);
this.correctZOffsetBasedOnCameraAngle();
}

const parent = this.parent as Unit | Item;
const isOwnedItem = parent && parent instanceof Item && parent.ownerUnit;
if (isOwnedItem && parent.ownerUnit.body) {
this.position.y = parent.ownerUnit.body.position.y;
if (isOwnedItem) {
this.yOffset = parent.ownerUnit.position.y;
}
}

private calcRenderOrder() {
this.sprite.position.y = Utils.getDepthZOffset(this.depth);
this.depthOffset = Utils.getDepthZOffset(this.depth);
}

private faceCamera(camera: Camera) {
Expand All @@ -103,7 +104,7 @@ namespace Renderer {
(parent && !(parent instanceof Item)) || (parent && parent instanceof Item && !parent.ownerUnit);

if (isNotItemOrUnownedItem) {
this.position.y = Utils.getDepthZOffset(this.depth) + offset;
this.yOffset = Utils.getDepthZOffset(this.depth) + offset;
}
}

Expand Down
5 changes: 5 additions & 0 deletions ts/src/renderer/three/entities/Entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ namespace Renderer {
export class Entity extends Node {
castShadow = false;

protected rotationOffset = new THREE.Vector3();

private layer = 3;
private zOffset = 0;

Expand All @@ -15,6 +17,9 @@ namespace Renderer {
taroEntity.on('layer', (layer) => this.setLayer(layer));
taroEntity.on('z-offset', (offset) => this.setZOffset(Utils.pixelToWorld(offset)));
taroEntity.on('destroy', () => this.destroy());
taroEntity.on('rotate', (x: number, y: number, z: number) => {
this.rotationOffset.set(-Utils.deg2rad(x), -Utils.deg2rad(z), -Utils.deg2rad(y));
});
}

onDestroy(): void {
Expand Down
Loading

0 comments on commit c989d76

Please sign in to comment.