UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

147 lines (109 loc) 3.96 kB
import { DoubleSide, NormalBlending, ShaderMaterial, Vector2 } from "three"; const vertexShader = ` varying vec2 vUv; varying vec4 vColor; attribute float thickness; attribute vec3 previous, next; attribute float off; attribute vec3 color; attribute float uv_offset; attribute float age; attribute float alpha; uniform vec2 resolution; uniform float maxAge; uniform float time; float pi = 3.141592653589793; vec4 transform(vec3 coord){ return projectionMatrix * modelViewMatrix * vec4(coord, 1.0); } vec2 project(vec4 device){ vec3 device_normal = device.xyz / device.w; vec2 clip_pos = (device_normal*0.5+0.5).xy; return clip_pos * resolution; } vec4 unproject(vec2 screen, float z, float w){ vec2 clip_pos = screen / resolution; vec2 device_normal = clip_pos*2.0-1.0; return vec4( device_normal * w, z, w); } float estimateScale(vec3 position, vec2 sPosition){ vec4 view_pos = modelViewMatrix * vec4( position, 1.0 ); float halfWidth = thickness*0.5; vec4 scale_pos = view_pos - vec4( normalize(view_pos.xy) * halfWidth, 0.0, 0.0); vec2 screen_scale_pos = project(projectionMatrix * scale_pos); return distance( sPosition, screen_scale_pos ); } void main(){ vec2 sLast = project(transform(previous.xyz)); vec2 sNext = project(transform(next.xyz)); vec4 dCurrent = transform(position.xyz); vec2 sCurrent = project(dCurrent); vec2 normal1 = normalize(sLast - sCurrent); vec2 normal2 = normalize(sCurrent - sNext); // vector between two segments vec2 normal = (normal1 + normal2) * 0.5; float offset_signed = off*2.0 - 1.0; vUv = vec2(uv_offset, off); float relativeAge = clamp(age / maxAge, 0.0, 1.0); vColor = vec4( color / 255.0, alpha ); vec2 dir = vec2(normal.y, -normal.x) * offset_signed; float angular_compensation = max( normal.x * normal.x + normal.y * normal.y, 0.25 ); float visual_size = resolution.y * projectionMatrix[1][1] * thickness*0.5 / dCurrent.w; float scale = visual_size / angular_compensation; vec2 pos = sCurrent + dir * scale; gl_Position = unproject(pos, dCurrent.z, dCurrent.w); } `; const fragmentShader = ` varying vec2 vUv; varying vec4 vColor; uniform sampler2D uDiffuse; void main(){ vec4 diffuseColor = vColor; #ifdef USE_TEXTURE vec4 texel = texture2D(uDiffuse, vUv); diffuseColor *= texel; #endif gl_FragColor = diffuseColor; } `; export class RibbonMaterialX extends ShaderMaterial { constructor(params) { super({ fragmentShader, vertexShader, uniforms: { resolution: { value: new Vector2(600, 600) }, uDiffuse: { type: 't', value: null } }, defines: { USE_TEXTURE: false }, blending: NormalBlending, transparent: true, depthWrite: false, depthTest: true, side: DoubleSide }); this.setValues(params); } /** * * @param {Vector2} v2 */ set resolution(v2) { this.uniforms.resolution.value.set(v2.x, v2.y); } /** * * @return {Vector2} */ get resolution() { return this.uniforms.resolution.value; } }