UNPKG

3d-tiles-renderer

Version:

https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification

160 lines (114 loc) 3.71 kB
import { PointsMaterial, Vector2, Vector4 } from 'three'; import { MVTGlyphAtlasTexture } from './MVTGlyphAtlasTexture.js'; const _viewport = /* @__PURE__ */ new Vector4(); /** * A `PointsMaterial` that draws each point sprite as a glyph from an `MVTGlyphAtlasTexture` with fading. * @private * @extends PointsMaterial */ export class MVTGlyphMaterial extends PointsMaterial { /** * The glyph atlas sampled by this material. * @type {MVTGlyphAtlasTexture} */ get glyphAtlas() { return this._glyphAtlas; } set glyphAtlas( v ) { this._glyphAtlas = v; if ( v !== null ) { v.getSlotSize( this._glyphCellSize ); } if ( this._uniforms ) { this._uniforms.glyphAtlas.value = v; } } /** * A single atlas slot's size in UV units. * @type {Vector2} */ get glyphCellSize() { return this._glyphCellSize; } /** * @param {Object} [parameters] - `PointsMaterial` parameters, plus the overrides below. * @param {number} [parameters.size=25] - Point size in pixels. * @param {boolean} [parameters.sizeAttenuation=false] - Whether point size shrinks with distance. */ constructor( parameters = {} ) { const { size = 25, sizeAttenuation = false, ...rest } = parameters; super( { size, sizeAttenuation, ...rest } ); this.transparent = true; this.depthTest = false; this.depthWrite = false; this.resolution = new Vector2(); // owns the glyph atlas ( unless one is provided ); the cell size is kept in sync with it // and pushed to the uniforms after compile this._glyphCellSize = new Vector2(); this._glyphAtlas = new MVTGlyphAtlasTexture(); this._uniforms = null; this.onBeforeCompile = ( shader ) => { shader.uniforms.glyphAtlas = { value: this._glyphAtlas }; shader.uniforms.glyphCellSize = { value: this._glyphCellSize }; this._uniforms = shader.uniforms; shader.vertexShader = shader.vertexShader.replace( '#include <color_pars_vertex>', /* glsl */` #include <color_pars_vertex> attribute vec2 glyphUV; attribute float alpha; attribute float angle; varying vec2 vGlyphUV; varying float vAlpha; varying float vAngle; ` ); shader.vertexShader = shader.vertexShader.replace( '#include <color_vertex>', /* glsl */` #include <color_vertex> vGlyphUV = glyphUV; vAlpha = alpha; vAngle = angle; ` ); shader.fragmentShader = /* glsl */` uniform sampler2D glyphAtlas; uniform vec2 glyphCellSize; uniform float opacity; varying vec2 vGlyphUV; varying float vAlpha; varying float vAngle; void main() { vec4 diffuseColor = vec4( 0.0 ); if ( vGlyphUV.x >= 0.0 ) { // rotate the point-sprite lookup around its center so the glyph follows // the path direction; clamp keeps the rotated corners inside the slot vec2 pc = gl_PointCoord - 0.5; float c = cos( vAngle ); float s = sin( vAngle ); pc = vec2( c * pc.x + s * pc.y, - s * pc.x + c * pc.y ) + 0.5; pc = clamp( pc, 0.0, 1.0 ); vec4 glyph = texture2D( glyphAtlas, vGlyphUV + pc * glyphCellSize * vec2( 1.0, - 1.0 ) ); diffuseColor = glyph; } diffuseColor.a *= vAlpha * opacity; gl_FragColor = diffuseColor; #include <tonemapping_fragment> #include <colorspace_fragment> #include <premultiplied_alpha_fragment> } `; }; } onBeforeRender( renderer ) { this._glyphAtlas.getSlotSize( this._glyphCellSize ); // viewport size in pixels, refreshed each frame in onBeforeRender for screen-space raycasting renderer.getViewport( _viewport ); this.resolution.set( _viewport.z, _viewport.w ); } }