From 8b7817badc9cc7ca26f1f7f97474ed82a2dbdb5f Mon Sep 17 00:00:00 2001 From: Marcin Jerzak Date: Sat, 2 Dec 2023 19:43:13 +0100 Subject: [PATCH 1/3] playground --- .../routes/instanced-sprite/AnimatedInstancedSprite.svelte | 5 ++++- .../src/routes/instanced-sprite/PlayerUpdater.svelte | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/playground/src/routes/instanced-sprite/AnimatedInstancedSprite.svelte b/apps/playground/src/routes/instanced-sprite/AnimatedInstancedSprite.svelte index b470796..ba2f498 100644 --- a/apps/playground/src/routes/instanced-sprite/AnimatedInstancedSprite.svelte +++ b/apps/playground/src/routes/instanced-sprite/AnimatedInstancedSprite.svelte @@ -65,7 +65,10 @@ const mesh: InstancedSpriteMesh = new InstancedSpriteMesh( baseMaterial, - count + count, + { + triGeometry: true + } ); const textureStore = texture diff --git a/apps/playground/src/routes/instanced-sprite/PlayerUpdater.svelte b/apps/playground/src/routes/instanced-sprite/PlayerUpdater.svelte index a000b30..7f8eb28 100644 --- a/apps/playground/src/routes/instanced-sprite/PlayerUpdater.svelte +++ b/apps/playground/src/routes/instanced-sprite/PlayerUpdater.svelte @@ -122,7 +122,7 @@ for (let i = 0; i < count; i++) { // $camera.position.set(0 + (posX[0] || 0), 7, 15 + (posZ[0] || 0)) - updatePosition(i, [posX[i] || 0, 0.5, posZ[i] || 0]); + updatePosition(i, [posX[i] || 0, 1, posZ[i] || 0]); } }); From 43ef09543b9e53cff55d01dcad049d184cf87742 Mon Sep 17 00:00:00 2001 From: Marcin Jerzak Date: Sat, 2 Dec 2023 19:43:43 +0100 Subject: [PATCH 2/3] Option to use triangle instead of plane for sprites --- .../instancedSprite/02-reference-sheet.mdx | 18 +++++--- .../src/InstancedSpriteMesh.ts | 32 +++++++++++--- .../instanced-sprite-mesh/src/material.ts | 44 +++++++++++++++---- .../instanced-sprite-mesh/src/triangle.ts | 29 ++++++++++++ 4 files changed, 102 insertions(+), 21 deletions(-) create mode 100644 packages/instanced-sprite-mesh/src/triangle.ts diff --git a/apps/docs/src/content/docs/instancedSprite/02-reference-sheet.mdx b/apps/docs/src/content/docs/instancedSprite/02-reference-sheet.mdx index e789eb3..edcb16d 100644 --- a/apps/docs/src/content/docs/instancedSprite/02-reference-sheet.mdx +++ b/apps/docs/src/content/docs/instancedSprite/02-reference-sheet.mdx @@ -8,18 +8,24 @@ which in turn extends [THREE.InstancedMesh](https://threejs.org/docs/?q=instance ## Constructor ```ts +type InstancedSpriteOptions = { + spritesheet?: SpritesheetFormat; + triGeometry?: boolean; +}; + new InstancedSpriteMesh ( baseMaterial: T extends Material, count: number, - spritesheet?: SpritesheetFormat, - options?: InstancedSpriteOptions + options: InstancedSpriteOptions = {} ) ``` -**baseMaterial** - Threejs material (recommended THREE.MeshBasicMaterial or THREE.MeshStandardMaterial) - more on this here -> (TODO) -**count** - number of instances -**spritesheet** - spritesheet metadata -**options** - (none atm, placeholder) +- **baseMaterial** - Threejs material (recommended THREE.MeshBasicMaterial or THREE.MeshStandardMaterial) - more on this here -> (TODO) +- **count** - number of instances +- **options** - (none atm, placeholder) + - **spritesheet** - spritesheet metadata + - **triGeometry** - use triangles instead of PlaneGeometry for sprites + ## Properties and Methods diff --git a/packages/instanced-sprite-mesh/src/InstancedSpriteMesh.ts b/packages/instanced-sprite-mesh/src/InstancedSpriteMesh.ts index 5ce2f7a..7112bfe 100644 --- a/packages/instanced-sprite-mesh/src/InstancedSpriteMesh.ts +++ b/packages/instanced-sprite-mesh/src/InstancedSpriteMesh.ts @@ -1,13 +1,21 @@ -import { Material, PlaneGeometry, ShaderMaterial, Vector4 } from "three"; +import { + BufferGeometry, + Material, + PlaneGeometry, + ShaderMaterial, + Vector4, +} from "three"; import { InstancedUniformsMesh } from "three-instanced-uniforms-mesh"; import { SpritesheetFormat, constructSpriteMaterial, makeDataTexture, } from "./material"; +import { createSpriteTriangle } from "./triangle"; type InstancedSpriteOptions = { - // geometry?: BufferGeometry + spritesheet?: SpritesheetFormat; + triGeometry?: boolean; }; export class InstancedSpriteMesh< @@ -23,16 +31,26 @@ export class InstancedSpriteMesh< constructor( baseMaterial: T, count: number, - spritesheet?: SpritesheetFormat, - options?: InstancedSpriteOptions + options: InstancedSpriteOptions = {} ) { - const geometry = new PlaneGeometry(1, 1); - const spriteMaterial = constructSpriteMaterial(baseMaterial); + let geometry: BufferGeometry | PlaneGeometry; + + if (options?.triGeometry) { + console.log("tri geo"); + geometry = createSpriteTriangle(); + } else { + geometry = new PlaneGeometry(1, 1) as any; + } + + const spriteMaterial = constructSpriteMaterial( + baseMaterial, + options?.triGeometry + ); super(geometry, spriteMaterial as any, count); this._animationMap = new Map(); this._spriteMaterial = spriteMaterial as any; - if (spritesheet) this.updateSpritesheet(spritesheet); + if (options.spritesheet) this.updateSpritesheet(options.spritesheet); } private updateSpritesheet(spritesheet: SpritesheetFormat) { diff --git a/packages/instanced-sprite-mesh/src/material.ts b/packages/instanced-sprite-mesh/src/material.ts index 5eb7698..34058e7 100644 --- a/packages/instanced-sprite-mesh/src/material.ts +++ b/packages/instanced-sprite-mesh/src/material.ts @@ -32,11 +32,20 @@ const replaceUVs = (text: string, replacement: string) => { }; // TODO TYPE GENERICS -export const constructSpriteMaterial = (baseMaterial: Material): Material => { +export const constructSpriteMaterial = ( + baseMaterial: Material, + triGeometry: boolean | undefined +): Material => { + const defines: Record = { + USE_UV: "", + }; + + if (triGeometry) { + defines["TRI_GEOMETRY"] = ""; + } + const customMaterial = createDerivedMaterial(baseMaterial, { - defines: { - USE_UV: "", - }, + defines, uniforms: { /** active animation */ animationId: { value: 0 }, @@ -131,11 +140,13 @@ export const constructSpriteMaterial = (baseMaterial: Material): Material => { float hStep = 1.f / dataSize.y; float hHalfStep = 1.f / dataSize.y * 0.5f; return texture2D(spritesheetData, vec2(col * wStep + wHalfStep, row * hStep + hHalfStep)); - } + } `; // calculate sprite UV const spriteUv = /*glsl*/ ` + + float animLength = readData(animationId, 1.f).r; float totalTime = animLength / fps; @@ -156,16 +167,33 @@ export const constructSpriteMaterial = (baseMaterial: Material): Material => { vec2 fSize = frameMeta.zw; vec2 fOffset = vec2(frameMeta.xy); - vec2 transformedPlaneUv = vUv; + vec2 transformedPlaneUv = vUv + vec2(0.,0.); if(flipX == 1.){ transformedPlaneUv.x = 1. - transformedPlaneUv.x; } if(flipY == 1.){ transformedPlaneUv.y = 1. - transformedPlaneUv.y; - } + } - vec2 spriteUv = fSize * transformedPlaneUv + fOffset; + vec2 spriteUv = fSize * transformedPlaneUv + fOffset ; + + #ifdef TRI_GEOMETRY + // Shift UVs if mesh uses triangle geometry + // TODO optimize ugly math + if(vUv.y>0.5 || vUv.x<0.25 || vUv.x>0.75){ + discard; + } + + vec2 zoomCenter = vec2(fSize.x * 0.5,0.); + float zoomFactor = 2.; + vec2 shiftedUV = spriteUv - zoomCenter; + shiftedUV *= zoomFactor; + shiftedUV += zoomCenter; + spriteUv = shiftedUV; + #endif + + `; fragmentShader = fragmentShader.replace( diff --git a/packages/instanced-sprite-mesh/src/triangle.ts b/packages/instanced-sprite-mesh/src/triangle.ts new file mode 100644 index 0000000..df7cb63 --- /dev/null +++ b/packages/instanced-sprite-mesh/src/triangle.ts @@ -0,0 +1,29 @@ +import { BufferGeometry, BufferAttribute } from "three"; + +export const createSpriteTriangle = () => { + const geometry = new BufferGeometry(); + + const vertices = new Float32Array([ + // top + 0.0, 1.0, 0.0, + // bot-left + -1.0, -1.0, 0.0, + // bot-right + 1.0, -1.0, 0.0, + ]); + geometry.setAttribute("position", new BufferAttribute(vertices, 3)); + + const uvs = new Float32Array([ + // top + 0.5, 1, + // bot-left + 0, 0.0, + // bot-right + 1, 0.0, + ]); + + geometry.setAttribute("uv", new BufferAttribute(uvs, 2)); + geometry.computeVertexNormals(); + + return geometry; +}; From 55c1caabd13e54d43dffe13318aea131f3021ea1 Mon Sep 17 00:00:00 2001 From: Marcin Jerzak Date: Sat, 2 Dec 2023 19:48:38 +0100 Subject: [PATCH 3/3] changeset --- .changeset/blue-eyes-remain.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/blue-eyes-remain.md diff --git a/.changeset/blue-eyes-remain.md b/.changeset/blue-eyes-remain.md new file mode 100644 index 0000000..9f289f9 --- /dev/null +++ b/.changeset/blue-eyes-remain.md @@ -0,0 +1,5 @@ +--- +"@threejs-kit/instanced-sprite-mesh": minor +--- + +Option to use a triangle instead of a plane for the sprite geometry