perf(web): share card texture via shader UV transform
Move the card sprite repeat/offset out of per-card texture clones and into a uniform injected into the material shader. Cards now share the deck sheet (one GPU upload), the shader, and the geometry, with only per-card material uniforms differing, so navigating a deck no longer re-uploads the sheet on every step.
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
/**
|
||||
* Per-card UV transform injected into a `MeshStandardMaterial` shader.
|
||||
*
|
||||
* Cards share one texture (the deck's sprite sheet, cached by drei) and one
|
||||
* geometry, but each card samples a different sprite cell. Rather than cloning
|
||||
* the texture per card (which re-uploads the sheet on every GPU bind), the
|
||||
* repeat/offset is pushed into the material as a uniform. The shader source is
|
||||
* identical across cards, so three.js still compiles a single shared program.
|
||||
*
|
||||
* We inject our own uniform instead of setting `texture.repeat`/`offset`
|
||||
* because three r185 derives the map UVs from a `mapTransform` matrix that is
|
||||
* refreshed from `map.matrix` every frame, overwriting any per-material
|
||||
* transform we set on the shared texture.
|
||||
*/
|
||||
const VERTEX_INJECT = /* glsl */ `
|
||||
#include <uv_vertex>
|
||||
vMapUv = uv * uMapRepeat + uMapOffset;
|
||||
`;
|
||||
|
||||
/**
|
||||
* Apply a repeat/offset to a card material's map sampling. Call once per
|
||||
* material (the transform is baked into the shader). `repeat`/`offset` are
|
||||
* copied, so the caller may reuse the vectors.
|
||||
*/
|
||||
export function applyMapTransform(
|
||||
material: THREE.MeshStandardMaterial,
|
||||
repeat: THREE.Vector2,
|
||||
offset: THREE.Vector2,
|
||||
): void {
|
||||
// Clone eagerly so later mutation of the caller's vectors can't leak into
|
||||
// the uniform once the material is compiled.
|
||||
const r = repeat.clone();
|
||||
const o = offset.clone();
|
||||
material.onBeforeCompile = (shader) => {
|
||||
shader.uniforms.uMapRepeat = { value: r };
|
||||
shader.uniforms.uMapOffset = { value: o };
|
||||
shader.vertexShader = shader.vertexShader.replace(
|
||||
'#include <uv_vertex>',
|
||||
VERTEX_INJECT,
|
||||
);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user