@spearwolf/twopoint5d
Version:
a library to create 2.5d realtime graphics and pixelart with three.js
129 lines (111 loc) • 4.22 kB
JavaScript
import { DoubleSide, Texture } from 'three';
import { unpick } from '../../utils/unpick.js';
import { CustomChunksShaderMaterial } from '../CustomChunksShaderMaterial.js';
import ShaderLib from '../ShaderLib.js';
const vertexShader = `
attribute vec2 quadSize;
attribute vec3 instancePosition;
attribute float rotation;
attribute float animId;
attribute float animOffset;
uniform sampler2D animsMap;
uniform vec2 animsMapSize;
uniform float time;
varying vec2 vTexCoords;
vec2 texCoordsFromIndex(in vec2 mapSize, in int ndx) {
int column = int(mod(float(ndx), float(mapSize[0])));
int row = ndx / int(mapSize[0]);
return (vec2(column, row) + 0.5) / vec2(mapSize[0], mapSize[1]);
}
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(vertexPosition.xyz, 1.0);
// ---- texture coords from frame based animations meta data ---------------
vec4 animMetaData = texture2D(animsMap, texCoordsFromIndex(animsMapSize, int(animId)));
int frameIndex = int(floor(mod((time + animOffset) / animMetaData.y * animMetaData.x, animMetaData.x)));
vec4 texCoords = texture2D(animsMap, texCoordsFromIndex(animsMapSize, int(animMetaData.z) + frameIndex));
vTexCoords = texCoords.xy + (uv * texCoords.zw);
}
`;
const fragmentShader = `
uniform sampler2D colorMap;
varying vec2 vTexCoords;
void main() {
gl_FragColor = texture2D(colorMap, vTexCoords);
}
`;
export class AnimatedSpritesMaterial extends CustomChunksShaderMaterial {
constructor(options) {
super({
vertexShader,
fragmentShader,
uniforms: {
...options?.uniforms,
colorMap: {
value: options?.colorMap,
},
animsMap: {
value: options?.animsMap,
},
animsMapSize: {
value: [options?.animsMap?.image.width ?? 0, options?.animsMap?.image.height ?? 0],
},
time: {
value: options?.time ?? 0,
},
},
transparent: true,
side: DoubleSide,
...unpick(options ?? {}, 'uniforms', 'colorMap', 'animsMap', 'time', 'renderAsBillboards'),
});
this.name = options?.name ?? 'twopoint5d.AnimatedSpritesMaterial';
if (typeof options?.renderAsBillboards === 'boolean') {
this.renderAsBillboards = options.renderAsBillboards;
}
this.replaceVertexShaderChunks = [
'extra_pars_vertex',
'rotateZ_vertex',
'makeBillboard_fn_vertex',
'vertexPosition_makeBillboard_instanced_vertex',
'vertexPosition_instanced_vertex',
'after_vertexPosition_vertex',
'post_main_vertex',
];
this.replaceFragmentShaderChunks = ['extra_pars_fragment', 'discard_by_alpha_fragment', 'post_main_fragment'];
this.addStaticChunks(ShaderLib);
}
get colorMap() {
return this.uniforms['colorMap'].value;
}
set colorMap(colorMap) {
this.uniforms['colorMap'].value = colorMap;
}
get animsMap() {
return this.uniforms['animsMap'].value;
}
set animsMap(animsMap) {
this.uniforms['animsMap'].value = animsMap;
this.uniforms['animsMapSize'].value = animsMap ? [animsMap.image.width, animsMap.image.height] : [0, 0];
}
get renderAsBillboards() {
return this.defines?.['RENDER_AS_BILLBOARDS'] === 1;
}
set renderAsBillboards(renderAsBillboards) {
this.updateBoolDefine('RENDER_AS_BILLBOARDS', renderAsBillboards);
}
}
//# sourceMappingURL=AnimatedSpritesMaterial.js.map