Skip to content

Commit

Permalink
mark
Browse files Browse the repository at this point in the history
  • Loading branch information
jerzakm committed Mar 6, 2024
1 parent 17053a0 commit 62bfefd
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
<script>
<script lang="ts">
import { onMount } from 'svelte';
import { start } from './main';
import { initDemonBench } from './mainDemons';
import { page } from '$app/stores';
import { initBunBench } from './mainBunnies';
import { fly } from 'svelte/transition';
const url = $page.url;
const param = url.searchParams.get('count');
const count = parseInt(param);
const mode = url.searchParams.get('mode');
onMount(() => {
start(count);
if (mode === 'bunnies') {
initBunBench(count);
} else {
initDemonBench(count);
}
});
const countOptions = [500, 2000, 10000, 50000, 100000, 200000, 400000, 600000, 800000, 1000000];
Expand All @@ -27,13 +34,28 @@
Displaying <b>{count}</b> bunnies.
</span>
<ul>
<span>Go to:</span>
<span style="width: 140px;">Bunnies (static):</span>
{#each countOptions as c}
<li>
<a data-sveltekit-reload href={`/instanced-sprite-bunny-mark?count=${c}`}>{c}</a>
<a data-sveltekit-reload href={`/instanced-sprite-bunny-mark?count=${c}&mode=bunnies`}
>{c}</a
>
</li>
{/each}
</ul>
<ul>
<span style="width: 140px;">Demons (animated):</span>
{#each countOptions as c}
<li>
<a data-sveltekit-reload href={`/instanced-sprite-bunny-mark?count=${c}&mode=demons`}>{c}</a
>
</li>
{/each}
</ul>
{#if mode === 'demons'}
Each demon has a random animation (idle, death, fly, attack) that changes each time it hits the
screen boundary, a separate animation progression and changes flipX based on the direction.
{/if}
</div>

<canvas id="three-canvas" />
Expand Down
156 changes: 156 additions & 0 deletions apps/playground/src/routes/instanced-sprite-bunny-mark/demon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { InstancedSpriteMesh, createSpritesheet } from '@threejs-kit/instanced-sprite-mesh';
import {
DoubleSide,
Matrix4,
MeshBasicMaterial,
type Scene,
type Vector3Tuple,
type WebGLRenderer
} from 'three';

export const initDemons = async (renderer: WebGLRenderer, scene: Scene, count: number) => {
const { texture, spritesheet } = await createSpritesheet()
.add(
'/textures/sprites/cacodaemon.png',
{
type: 'rowColumn',
width: 8,
height: 4
},
[
{ name: 'fly', frameRange: [0, 5] },
{ name: 'attack', frameRange: [8, 13] },
{ name: 'idle', frameRange: [16, 19] },
{ name: 'death', frameRange: [24, 31] }
]
)
.build();

const baseMaterial = new MeshBasicMaterial({
transparent: true,
alphaTest: 0.01,
// needs to be double side for shading
side: DoubleSide,
map: texture
});

const sprite = new InstancedSpriteMesh(baseMaterial, count, renderer);

sprite.fps = 9;
sprite.playmode.setAll('FORWARD');
sprite.loop.setAll(true);

sprite.hueShift.setGlobal({
h: 0,
s: 1.1,
v: 1.9
});

sprite.spritesheet = spritesheet;
scene.add(sprite);

sprite.castShadow = true;

// UPDATING AND MOVING SPRITES
let dirtyInstanceMatrix = false;

const tempMatrix = new Matrix4();
function updatePosition(id: number, [x, y, z]: Vector3Tuple) {
tempMatrix.makeScale(100, 100, 100);
tempMatrix.setPosition(x, bounds.top - y, z);
sprite.setMatrixAt(id, tempMatrix);
dirtyInstanceMatrix = true;
}

const gravity = 0.75;

const positionX: number[] = new Array(count).fill(0);
const positionY: number[] = new Array(count).fill(0);

const speedX: number[] = new Array(count).fill(0);
const speedY: number[] = new Array(count).fill(0);

const setRandomAnimationAt = (id: number) => {
const animations = ['fly', 'attack', 'idle', 'death'];
sprite.animation.setAt(id, animations[Math.floor(Math.random() * animations.length)]);
};

function setupRandomAgents() {
for (let i = 0; i < count; i++) {
positionX[i] = 0;
positionY[i] = 0;

speedX[i] = Math.random() * 10;
speedY[i] = Math.random() * 10 - 5;
setRandomAnimationAt(i);
// sprite.animation.setAt(i, bunnies[Math.floor(Math.random() * bunnies.length)]);
}

const updateAgents = (delta: number) => {
for (let i = 0; i < count; i++) {
delta = 1;
// timer
// apply gravity

// apply velocity
positionX[i] += speedX[i] * delta * 0.5;
positionY[i] += speedY[i] * delta * 0.1;

// roll new behaviour if bunny gets out of bounds

if (positionX[i] > bounds.right) {
speedX[i] *= -1;
positionX[i] = bounds.right;
setRandomAnimationAt(i);
sprite.flipX.setAt(i, true);
} else if (positionX[i] < bounds.left) {
speedX[i] *= -1;
positionX[i] = bounds.left;
setRandomAnimationAt(i);
sprite.flipX.setAt(i, false);
}

if (positionY[i] > bounds.top) {
speedY[i] *= -0.85;
positionY[i] = bounds.top;
setRandomAnimationAt(i);
if (Math.random() > 0.5) {
speedY[i] -= Math.random() * 6;
}
} else if (positionY[i] < bounds.bottom) {
setRandomAnimationAt(i);
speedY[i] *= -1;
positionY[i] = bounds.top;
}
}

for (let i = 0; i < count; i++) {
updatePosition(i, [positionX[i], positionY[i], 0]);
}
};

return { updateAgents };
}

const { updateAgents } = setupRandomAgents();

const bounds = {
left: 0,
right: window.innerWidth,
bottom: 0,
top: window.innerHeight
};

const update = (delta: number) => {
updateAgents(delta);

sprite.update();

if (dirtyInstanceMatrix) {
sprite.instanceMatrix.needsUpdate = true;
dirtyInstanceMatrix = false;
}
};

return { update, sprite };
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { initBunnies } from './bunny';

export const clock = new Clock(true);

export const start = async (count = 100000) => {
export const initBunBench = async (count = 100000) => {
// GENERAL SCENE SETUP
const screenWidth = window.innerWidth;
const screenHeight = window.innerHeight;
Expand Down Expand Up @@ -58,8 +58,14 @@ export const start = async (count = 100000) => {
window.addEventListener('resize', onWindowResize);

function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.left = 0;
camera.right = window.innerWidth;
camera.top = window.innerHeight;
camera.bottom = 0;
// camera.position.set(screenWidth / 2, screenHeight / 2, 10);
// camera.lookAt(screenWidth / 2, screenHeight / 2, 0);
camera.updateProjectionMatrix();

renderer.setSize(window.innerWidth, window.innerHeight);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Stats from 'three/examples/jsm/libs/stats.module.js';

import {
AmbientLight,
Clock,
OrthographicCamera,
SRGBColorSpace,
Scene,
WebGLRenderer
} from 'three';
import { initDemons } from './demon';

export const clock = new Clock(true);

export const initDemonBench = async (count = 100000) => {
// GENERAL SCENE SETUP
const screenWidth = window.innerWidth;
const screenHeight = window.innerHeight;
const pixelRatio = window.devicePixelRatio || 1;

const camera = new OrthographicCamera(0, screenWidth, screenHeight, 0, 1, 1000);
camera.position.set(0, 0, 10);
camera.lookAt(0, 0, 0);
camera.zoom = 1;
camera.updateProjectionMatrix();
const scene = new Scene();

const canvas = document.getElementById('three-canvas');
if (!canvas) return;
const renderer = new WebGLRenderer({
canvas
});

renderer.outputColorSpace = SRGBColorSpace;

renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(pixelRatio);

const stats = new Stats();
document.body.appendChild(stats.dom);

const demons = await initDemons(renderer, scene, count);

sceneSetup();
animate();

function sceneSetup() {
const ambient = new AmbientLight('#ddddff', 1.19);
scene.add(ambient);
}

window.addEventListener('resize', onWindowResize);

function onWindowResize() {
camera.left = 0;
camera.right = window.innerWidth;
camera.top = window.innerHeight;
camera.bottom = 0;
// camera.position.set(screenWidth / 2, screenHeight / 2, 10);
// camera.lookAt(screenWidth / 2, screenHeight / 2, 0);
camera.updateProjectionMatrix();

renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
requestAnimationFrame(animate);
stats.begin();
// timer.update();
// const delta = timer.getDelta();
const delta = clock.getDelta();

demons.update(delta);
renderer.render(scene, camera);

stats.end();
}
};

0 comments on commit 62bfefd

Please sign in to comment.