@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
147 lines (109 loc) • 3.96 kB
JavaScript
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;
vec4 texel = texture2D(uDiffuse, vUv);
diffuseColor *= texel;
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;
}
}