mirror of
https://github.com/WhitestormJS/whs.js.git
synced 2026-01-25 16:08:01 +00:00
486 lines
11 KiB
JavaScript
486 lines
11 KiB
JavaScript
// -----------------------------------------------------------------------------
|
|
// Configuration
|
|
// -----------------------------------------------------------------------------
|
|
const conf = {
|
|
shaders: {
|
|
bluriness: 2,
|
|
additiveCoef: 1.0,
|
|
bleachOpacity: 0.5,
|
|
vignetteDarkness: 1.0
|
|
},
|
|
world: {
|
|
stats: "fps",
|
|
autoresize: true,
|
|
|
|
gravity: {
|
|
x: 0,
|
|
y: 0,
|
|
z: 0
|
|
},
|
|
|
|
camera: {
|
|
far: 10000,
|
|
position: [0, 10, 30]
|
|
},
|
|
|
|
renderer: {
|
|
autoClear: false
|
|
}
|
|
},
|
|
glowSphere: {
|
|
geometry: {
|
|
radius: 10,
|
|
widthSegments: 16,
|
|
heightSegments: 16
|
|
},
|
|
|
|
mass: 10,
|
|
|
|
material: {
|
|
color: 0xff0000,
|
|
kind: 'basic'
|
|
},
|
|
|
|
pos: {
|
|
x: 0,
|
|
y: 20,
|
|
z: 0
|
|
}
|
|
},
|
|
sphere: {
|
|
geometry: {
|
|
radius: 5,
|
|
widthSegments: 16,
|
|
heightSegments: 16
|
|
},
|
|
|
|
mass: 10,
|
|
|
|
material: {
|
|
color: 0xcccccc,
|
|
kind: 'basic'
|
|
},
|
|
|
|
pos: {
|
|
x: 0,
|
|
y: 20,
|
|
z: 0
|
|
}
|
|
},
|
|
plane: {
|
|
geometry: {
|
|
width: 250,
|
|
height: 250
|
|
},
|
|
|
|
mass: 0,
|
|
|
|
material: {
|
|
color: 0xff0000,
|
|
kind: "basic"
|
|
},
|
|
|
|
pos: {
|
|
x: 0,
|
|
y: 0,
|
|
z: 0
|
|
},
|
|
|
|
rot: {
|
|
x: -Math.PI / 2
|
|
}
|
|
},
|
|
glowPostProcessor: {
|
|
|
|
},
|
|
postProcessor: {
|
|
|
|
}
|
|
};
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Glow related shaders
|
|
// -----------------------------------------------------------------------------
|
|
const BleachBypassShader = {
|
|
|
|
uniforms: {
|
|
|
|
"tDiffuse": { value: null },
|
|
"opacity": { value: 1.0 }
|
|
|
|
},
|
|
|
|
vertexShader: [
|
|
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
"vUv = uv;",
|
|
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
"}"
|
|
|
|
].join("\n"),
|
|
|
|
fragmentShader: [
|
|
|
|
"uniform float opacity;",
|
|
|
|
"uniform sampler2D tDiffuse;",
|
|
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
"vec4 base = texture2D( tDiffuse, vUv );",
|
|
|
|
"vec3 lumCoeff = vec3( 0.25, 0.65, 0.1 );",
|
|
"float lum = dot( lumCoeff, base.rgb );",
|
|
"vec3 blend = vec3( lum );",
|
|
|
|
"float L = min( 1.0, max( 0.0, 10.0 * ( lum - 0.45 ) ) );",
|
|
|
|
"vec3 result1 = 2.0 * base.rgb * blend;",
|
|
"vec3 result2 = 1.0 - 2.0 * ( 1.0 - blend ) * ( 1.0 - base.rgb );",
|
|
|
|
"vec3 newColor = mix( result1, result2, L );",
|
|
|
|
"float A2 = opacity * base.a;",
|
|
"vec3 mixRGB = A2 * newColor.rgb;",
|
|
"mixRGB += ( ( 1.0 - A2 ) * base.rgb );",
|
|
|
|
"gl_FragColor = vec4( mixRGB, base.a );",
|
|
|
|
"}"
|
|
|
|
].join("\n")
|
|
};
|
|
|
|
const VerticalBlurShader = {
|
|
uniforms: {
|
|
|
|
"tDiffuse": { value: null },
|
|
"v": { value: 1.0 / 512.0 }
|
|
|
|
},
|
|
vertexShader: [
|
|
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
"vUv = uv;",
|
|
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
"}"
|
|
|
|
].join("\n"),
|
|
fragmentShader: [
|
|
|
|
"uniform sampler2D tDiffuse;",
|
|
"uniform float v;",
|
|
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
"vec4 sum = vec4( 0.0 );",
|
|
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 4.0 * v ) ) * 0.051;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 3.0 * v ) ) * 0.0918;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 2.0 * v ) ) * 0.12245;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 1.0 * v ) ) * 0.1531;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 1.0 * v ) ) * 0.1531;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 2.0 * v ) ) * 0.12245;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 3.0 * v ) ) * 0.0918;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 4.0 * v ) ) * 0.051;",
|
|
"gl_FragColor = sum;",
|
|
"}"
|
|
].join("\n")
|
|
};
|
|
|
|
const HorizontalBlurShader = {
|
|
uniforms: {
|
|
|
|
"tDiffuse": { value: null },
|
|
"h": { value: 1.0 / 512.0 }
|
|
},
|
|
vertexShader: [
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
"vUv = uv;",
|
|
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
"}"
|
|
].join("\n"),
|
|
fragmentShader: [
|
|
|
|
"uniform sampler2D tDiffuse;",
|
|
"uniform float h;",
|
|
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
"vec4 sum = vec4( 0.0 );",
|
|
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x - 4.0 * h, vUv.y ) ) * 0.051;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x - 3.0 * h, vUv.y ) ) * 0.0918;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x - 2.0 * h, vUv.y ) ) * 0.12245;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x - 1.0 * h, vUv.y ) ) * 0.1531;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x + 1.0 * h, vUv.y ) ) * 0.1531;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x + 2.0 * h, vUv.y ) ) * 0.12245;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x + 3.0 * h, vUv.y ) ) * 0.0918;",
|
|
"sum += texture2D( tDiffuse, vec2( vUv.x + 4.0 * h, vUv.y ) ) * 0.051;",
|
|
|
|
"gl_FragColor = sum;",
|
|
|
|
"}"
|
|
].join("\n")
|
|
};
|
|
|
|
const VignetteShader = {
|
|
uniforms: {
|
|
"tDiffuse": { value: null },
|
|
"offset": { value: 1.0 },
|
|
"darkness": { value: 1.0 }
|
|
},
|
|
|
|
vertexShader: [
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
"vUv = uv;",
|
|
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
"}"
|
|
].join("\n"),
|
|
fragmentShader: [
|
|
"uniform float offset;",
|
|
"uniform float darkness;",
|
|
|
|
"uniform sampler2D tDiffuse;",
|
|
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
// Eskil's vignette
|
|
|
|
"vec4 texel = texture2D( tDiffuse, vUv );",
|
|
"vec2 uv = ( vUv - vec2( 0.5 ) ) * vec2( offset );",
|
|
"gl_FragColor = vec4( mix( texel.rgb, vec3( 1.0 - darkness ), dot( uv, uv ) ), texel.a );",
|
|
|
|
/*
|
|
// alternative version from glfx.js
|
|
// this one makes more "dusty" look (as opposed to "burned")
|
|
|
|
"vec4 color = texture2D( tDiffuse, vUv );",
|
|
"float dist = distance( vUv, vec2( 0.5 ) );",
|
|
"color.rgb *= smoothstep( 0.8, offset * 0.799, dist *( darkness + offset ) );",
|
|
"gl_FragColor = color;",
|
|
*/
|
|
"}"
|
|
].join("\n")
|
|
};
|
|
|
|
const AdditiveShader = {
|
|
|
|
uniforms: {
|
|
tDiffuse: {
|
|
type: "t",
|
|
value: null
|
|
},
|
|
tAdd: {
|
|
type: "t",
|
|
value: null
|
|
},
|
|
fCoeff: {
|
|
type: "f",
|
|
value: 1.5
|
|
}
|
|
},
|
|
|
|
vertexShader: [
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
"vUv = uv;",
|
|
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
|
|
|
|
"}"
|
|
].join("\n"),
|
|
|
|
fragmentShader: [
|
|
"uniform sampler2D tDiffuse;",
|
|
"uniform sampler2D tAdd;",
|
|
"uniform float fCoeff;",
|
|
|
|
"varying vec2 vUv;",
|
|
|
|
"void main() {",
|
|
|
|
"vec4 texel = texture2D( tDiffuse, vUv );",
|
|
"vec4 add = texture2D( tAdd, vUv );",
|
|
"gl_FragColor = texel + add * fCoeff;",
|
|
|
|
"}"
|
|
].join("\n")
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Glow Object wrapping geometries in both normal and glow worlds
|
|
// -----------------------------------------------------------------------------
|
|
class GlowObject {
|
|
constructor(options, glowOptions, geometryWorld, glowWorld) {
|
|
this._options = options;
|
|
this._glowOptions = glowOptions;
|
|
this._geometryWorld = geometryWorld;
|
|
this._glowWorld = glowWorld;
|
|
|
|
this._init();
|
|
}
|
|
|
|
_init() {
|
|
this.geometryObject = new WHS.Sphere(this._options);
|
|
this.geometryObject.addTo(this._geometryWorld);
|
|
|
|
this.glowObject = new WHS.Sphere(this._glowOptions);
|
|
this.glowObject.addTo(this._glowWorld);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Game class
|
|
// -----------------------------------------------------------------------------
|
|
class Game {
|
|
constructor(options) {
|
|
this.options = options;
|
|
|
|
this.world = new (PHYSICS.$world(WHS.World))(options.world);
|
|
this.glowWorld = new (PHYSICS.$world(WHS.World))({ init: { render: false } });
|
|
this.world.attachWorld(this.glowWorld);
|
|
|
|
this.createGlowPostProcessing();
|
|
this.createPostProcessing();
|
|
|
|
this.createGeometry();
|
|
}
|
|
|
|
createGlowPostProcessing() {
|
|
this.glowPostProcessor = new WHS.PostProcessor(this.options.glowPostProcessor, this.glowWorld);
|
|
|
|
// render geometry
|
|
this.glowPostProcessor.createRenderPass();
|
|
|
|
// blur passes that will stretch the glow-shapes geometry
|
|
this.glowPostProcessor.createPass(composer => {
|
|
let pass = new WHS.ShaderPass('hblur_1', HorizontalBlurShader);
|
|
pass.uniforms['h'].value = this.options.shaders.bluriness / window.innerWidth * 2;
|
|
composer.addPass(pass);
|
|
});
|
|
|
|
this.glowPostProcessor.createPass(composer => {
|
|
let pass = new WHS.ShaderPass('vblur_1', VerticalBlurShader);
|
|
pass.uniforms['v'].value = this.options.shaders.bluriness / window.innerHeight * 2;
|
|
composer.addPass(pass);
|
|
});
|
|
|
|
this.glowPostProcessor.createPass(composer => {
|
|
let pass = new WHS.ShaderPass('hblur_2', HorizontalBlurShader);
|
|
pass.uniforms['h'].value = this.options.shaders.bluriness / window.innerWidth * 2;
|
|
composer.addPass(pass);
|
|
});
|
|
|
|
this.glowPostProcessor.createPass(composer => {
|
|
let pass = new WHS.ShaderPass('vblur_2', VerticalBlurShader);
|
|
pass.renderToScreen = false;
|
|
pass.uniforms['v'].value = this.options.shaders.bluriness / window.innerHeight * 2;
|
|
composer.addPass(pass);
|
|
});
|
|
}
|
|
|
|
createPostProcessing() {
|
|
this.postProcessor = new WHS.PostProcessor(this.options.postProcessor, this.world);
|
|
|
|
// render geometry
|
|
this.postProcessor.createRenderPass();
|
|
|
|
// applying glow effect
|
|
this.postProcessor.createPass(composer => {
|
|
let pass = new WHS.ShaderPass('glow_additive', AdditiveShader);
|
|
pass.renderToScreen = true;
|
|
pass.needsSwap = true;
|
|
pass.uniforms['fCoeff'].value = this.options.shaders.additiveCoef;
|
|
pass.uniforms['tAdd'].value = this.glowPostProcessor.composer.renderTarget2.texture;
|
|
composer.addPass(pass);
|
|
});
|
|
|
|
// this.postProcessor.createPass(composer => {
|
|
// let pass = new WHS.TexturePass('rtt1', this.glowPostProcessor.composer.renderTarget1.texture);
|
|
// pass.renderToScreen = true;
|
|
// composer.addPass(pass);
|
|
// })
|
|
|
|
// bleach bypass
|
|
// this.postProcessor.createPass(composer => {
|
|
// let pass = new WHS.ShaderPass('bleach_bypass', BleachBypassShader);
|
|
// pass.renderToScreen = false;
|
|
// pass.uniforms['opacity'].value = this.options.shaders.bleachOpacity;
|
|
// composer.addPass(pass);
|
|
// });
|
|
|
|
// vignetting
|
|
// this.postProcessor.createPass(composer => {
|
|
// let pass = new WHS.ShaderPass('vignette', VignetteShader);
|
|
// pass.renderToScreen = true;
|
|
// pass.uniforms['darkness'].value = this.options.shaders.vignetteDarkness;
|
|
// composer.addPass(pass);
|
|
// });
|
|
}
|
|
|
|
createGeometry() {
|
|
this.plane = new WHS.Plane(this.options.plane);
|
|
this.plane.addTo(this.world);
|
|
|
|
// create random glow objects here
|
|
this.glowSpheres = [];
|
|
this.glowSpheres.push(new GlowObject(this.options.sphere, this.options.glowSphere, this.world, this.glowWorld));
|
|
}
|
|
|
|
start() {
|
|
this.world.setControls(WHS.orbitControls());
|
|
this.world.start();
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Application bootstrap
|
|
// -----------------------------------------------------------------------------
|
|
var app = null;
|
|
|
|
function bootstrap() {
|
|
app.start()
|
|
}
|
|
|
|
function configure() {
|
|
return new Promise((resolve) => {
|
|
// some async config fetch could be done from here
|
|
// ...
|
|
|
|
// Create a Game instance with its conf
|
|
app = new Game(conf);
|
|
resolve(true);
|
|
});
|
|
}
|
|
|
|
configure().then(() => bootstrap());
|