Skip to content

Instantly share code, notes, and snippets.

@kangchihlun
Created May 2, 2023 12:12
Show Gist options
  • Save kangchihlun/bf6fcbd66be5e51d117482001515a4e4 to your computer and use it in GitHub Desktop.
Save kangchihlun/bf6fcbd66be5e51d117482001515a4e4 to your computer and use it in GitHub Desktop.
Pacman Concept
<script type="x-shader/x-vertex" id="shader-passthrough-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
</script>
<script type="x-shader/x-fragment" id="shader-passthrough-fragment">
uniform sampler2D tDiffuse;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( tDiffuse, vec2( vUv.x, vUv.y ) );
}
</script>
<script type="x-shader/x-fragment" id="shader-volumetric-light-fragment">
varying vec2 vUv;
uniform sampler2D tDiffuse;
uniform vec2 lightPosition;
uniform float exposure;
uniform float decay;
uniform float density;
uniform float weight;
uniform int samples;
const int MAX_SAMPLES = 100;
void main()
{
vec2 texCoord = vUv;
vec2 deltaTextCoord = texCoord - lightPosition;
deltaTextCoord *= 1.0 / float(samples) * density;
vec4 color = texture2D(tDiffuse, texCoord);
float illuminationDecay = 1.0;
for(int i=0; i < MAX_SAMPLES; i++) {
if(i == samples) {
break;
}
texCoord -= deltaTextCoord;
vec4 sample = texture2D(tDiffuse, texCoord);
sample *= illuminationDecay * weight;
color += sample;
illuminationDecay *= decay;
}
gl_FragColor = color * exposure;
}
</script>
<script type="x-shader/x-fragment" id="shader-additive-fragment">
uniform sampler2D tDiffuse;
uniform sampler2D tAdd;
varying vec2 vUv;
void main() {
vec4 color = texture2D( tDiffuse, vUv );
vec4 add = texture2D( tAdd, vUv );
gl_FragColor = color + add;
}
</script>
<img id="map-test" src="data:image/gif;base64,R0lGODdhHAAfAPIAAAAAAAD/AAAA//8AACZFySZFySZFySZFySH5BAEAAAQALAAAAAAcAB8AAAOwOLrc/iMIAISkNahL7cyKwIhj2JDmADArq7QLrKZ0itYk5+0SL3gdzeBGupWGR2IteeQAhD3oTxp8GIsnB4YyY7q24FUrOp2+VGFMF8VNibcObBhJZ4GjaHh0nkXOsQ1gaxAkb2liGx9bFmeHXC1GC4V5bUcyLnUMOk6MEYpAIJlXS0qifaOSiVAZZT5Pql6RNkt0gHGzCxJ4nq+enWRCsqmZt8SBtE2KYK5pnRDP0AkAOw==" />

Pacman Concept

I wanted to see if I could do a minigame about pac-man with a little twist but somehow ended by doing this cube maze with sparking lights and colors. Then I realize It could be used as the game menu...

A Pen by Ivan Juarez N. on CodePen.

License.

/*
TODO:
- Cleanup code
- Generate different mazes for each face
- Try different color schemes
- Create UI Menus
- Optimize for mobile
*/
/*
Resources:
- Volumetric Light Scattering in three.js
https://medium.com/@andrew_b_berg/volumetric-light-scattering-in-three-js-6e1850680a41
- Postprocessing Unreal Bloom
https://threejs.org/examples/#webgl_postprocessing_unreal_bloom
- THREE Mesh Line
https://github.com/spite/THREE.MeshLine
- Javascript 2D Perlin & Simplex noise functions
https://github.com/josephg/noisejs
*/
const CUBE_SIZE = 10;
const MAP_WIDTH = 28;
const MAP_HEIGHT = 31;
// DIRECTIONS
const NONE = 0;
const UP = 1;
const RIGHT = 2;
const DOWN = 3;
const LEFT = 4;
// MAP ITEMS
const MAP_EMPTY = 1;
const MAP_WALL = 2;
const MAP_JUNCTION = 3;
const MAP_DIRECTION = 4;
const MAP_PARSE_COLORS = {
'0,0,0': MAP_EMPTY,
'255,0,0': MAP_WALL,
'0,255,0': MAP_JUNCTION,
'0,0,255': MAP_DIRECTION
};
const Utils = {
AddDot(scene, position, size = 5) {
const geo = new THREE.Geometry();
geo.vertices.push(position.clone());
const mat = new THREE.PointsMaterial( {
size,
sizeAttenuation: false,
color: 0xffffff
} );
const dot = new THREE.Points(geo, mat);
scene.add( dot );
}
}
class BoardMap {
constructor(mapId) {
this.width = 0;
this.height = 0;
this.tiles = [];
this.mapImageData = this.getImageData(mapId);
this.parseMap();
}
getImageData(id) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = document.querySelector(id);
const { width: w, height: h } = img;
canvas.width = w;
canvas.height = h;
ctx.drawImage(img, 0, 0);
this.width = w;
this.height = h;
return ctx.getImageData(0, 0, w, h).data;
}
getMapPixelRGB(x, y) {
const { mapImageData: data, width } = this;
const idx = (x + width * y) * 4;
return [
Math.round(data[idx + 0] / 255) * 255,
Math.round(data[idx + 1] / 255) * 255,
Math.round(data[idx + 2] / 255) * 255,
];
}
stepToDirection(x, y, direction) {
let xTo = x;
let yTo = y;
switch(direction) {
case UP: yTo -= 1; break;
case RIGHT: xTo += 1; break;
case DOWN: yTo += 1; break;
case LEFT: xTo -= 1; break;
}
return [xTo, yTo];
}
getTileAt(x, y, direction = NONE) {
let [xTo, yTo] = this.stepToDirection(x, y, direction);
if (x <= this.width && y <= this.height) {
let idx = yTo * this.width + xTo;
return this.tiles[idx];
}
}
getNearestNeighborFrom(x, y, direction, type) {
let next = this.getTileAt(x, y, direction);
let [xTo, yTo] = this.stepToDirection(x, y, direction);
if (next === type) {
return [xTo, yTo];
} else if (next) {
return this.getNearestNeighborFrom(xTo, yTo, direction, type);
}
}
getIndexFromCoords(x, y) {
return y * this.width + x;
}
getCoordsFromIndex(idx) {
const x = idx % this.width;
const y = Math.floor( idx / this.width );
return [x, y];
}
parseMap() {
for( let y = 0; y < this.height; y++ ) {
for( let x = 0; x < this.width; x++) {
const [r, g, b] = this.getMapPixelRGB(x, y);
this.tiles.push(MAP_PARSE_COLORS[`${r},${g},${b}`]);
}
}
}
}
class MapBoundariesMesh {
constructor(boardMap) {
this.boardMap = boardMap;
this.geometry = new THREE.Geometry();
this.generateGeometry();
}
generateGeometry() {
for( let x = 0; x < MAP_WIDTH; x++ ) {
for( let y = 0; y < MAP_HEIGHT; y++ ) {
let idx = y * MAP_WIDTH + x;
if (this.boardMap.tiles[idx] === MAP_WALL) {
this.putBlock(x, y);
}
}
}
}
putBlock(x, y) {
const boxWidth = CUBE_SIZE / MAP_WIDTH;
const boxHeight = CUBE_SIZE / MAP_HEIGHT;
const halfSize = CUBE_SIZE / 2;
const boxElevation = 0.25;
const geo = new THREE.BoxGeometry(boxWidth, boxElevation, boxHeight);
const tX = -halfSize + x * boxWidth + boxWidth / 2;
const tY = -halfSize + y * boxHeight + boxHeight / 2;
geo.translate(tX, boxElevation / 2, tY);
const mesh = new THREE.Mesh(geo);
this.geometry.merge(mesh.geometry, mesh.matrix);
}
}
class Particles {
constructor() {
this.clusters = [];
this.scales = [];
this.initParticles();
}
initParticles() {
this.texture = new THREE.TextureLoader().load('https://s3-us-west-2.amazonaws.com/s.cdpn.io/204379/particle.png');
for( let i = 0; i < 5; i++ ) {
const cluster = {
scale: i + 2,
speed: THREE.Math.randFloat(0.5, 1.8),
points: this.getCluster(100),
}
this.clusters.push(cluster);
}
}
getCluster(count) {
const geo = new THREE.Geometry();
const mat = new THREE.PointsMaterial({
color: 0xffff00,
size: THREE.Math.randFloat(0.1, 0.25),
map: this.texture,
sizeAttenuation: true,
transparent: true,
opacity: 0.9,
});
for( let i = 0; i < count; i++) {
let p = new THREE.Vector3();
p.x = THREE.Math.randFloatSpread( 2 );
p.y = THREE.Math.randFloatSpread( 2 );
p.z = THREE.Math.randFloatSpread( 2 );
geo.vertices.push(p);
}
return new THREE.Points(geo, mat);
}
update(delta) {
for( let i = 0; i < this.clusters.length; i++ ) {
const cluster = this.clusters[i];
if (cluster.scale > 12) {
cluster.scale = 2;
cluster.points.material.opacity = 1;
}
cluster.scale += 0.45 * delta * cluster.speed;
cluster.points.scale.set(cluster.scale, cluster.scale, cluster.scale);
//const color = this.startColor.lerp(this.endColor, cluster.scale / 12);
if (cluster.scale > 8) {
const opacity = THREE.Math.lerp(1, 0, 1 - ((12 - cluster.scale) / 4));
cluster.points.material.opacity = opacity;
}
}
}
}
class Trails {
constructor(map) {
this.group = new THREE.Object3D();
this.position = new THREE.Vector3();
this.map = map;
this.maxPositions = 25;
this.history = [];
this.junctionTiles = [];
this.init();
this.spawn();
}
init() {
this.geometry = new THREE.Geometry();
const mat = new MeshLineMaterial({color: new THREE.Color(0xffffff), side: THREE.DoubleSide });
this.line = new MeshLine();
this.mesh = new THREE.Mesh(this.line.geometry, mat);
this.group.add(this.mesh);
for( let i = 0; i < this.maxPositions; i++) {
this.geometry.vertices.push(new THREE.Vector3());
}
this.map.tiles.forEach( (t, idx) => {
if (t === MAP_JUNCTION) {
this.junctionTiles.push(idx);
}
});
this.light = new THREE.PointLight(0x00ff00, 1, 5);
this.group.add(this.light);
//this.debug();
}
spawn() {
const { position, line } = this;
const { vertices } = this.geometry;
const wayPoints = this.getWayPoints();
vertices.forEach( v => v.copy(wayPoints[0]) );
this.position.copy(wayPoints[0]);
this.light.position.copy(wayPoints[0]);
line.setGeometry(this.geometry, (p) => p * 0.5);
this.startPath(wayPoints);
}
getTileDirections(x, y) {
const { map } = this;
return [ UP, RIGHT, DOWN, LEFT ].filter( d => {
const tile = map.getTileAt(x, y, d);
return tile !== undefined && tile === MAP_DIRECTION;
} );
}
debug() {
this.junctionTiles.forEach( t => {
const [x, y] = this.map.getCoordsFromIndex(t);
Utils.AddDot(this.group, this.scaleTilePosition(new THREE.Vector3(x, y, 0)))
});
}
scaleTilePosition(position) {
const { map } = this;
const tileScaleX = CUBE_SIZE / (map.width);
const tileScaleY = CUBE_SIZE / (map.height);
position.set(
(position.x + tileScaleX * 1.5) * tileScaleX,
(position.y + tileScaleX * 1.5) * tileScaleY, 0 )
return position;
}
getWayPoints() {
const { map, junctionTiles: jTiles } = this;
const startTile = jTiles[ ~~(Math.random() * jTiles.length) ];
let [xCurrent, yCurrent] = map.getCoordsFromIndex(startTile);
const visitedTiles = [];
let insert = true;
while(insert) {
visitedTiles.push(map.getIndexFromCoords(xCurrent, yCurrent));
// find available directions from current coords
const directions = this.getTileDirections(xCurrent, yCurrent);
// get all neighbours for all posibile directions
const neighbours = directions
.map( d => map.getNearestNeighborFrom(xCurrent, yCurrent, d, MAP_JUNCTION) )
// exclude already visited ones
.filter( n => visitedTiles.indexOf( map.getIndexFromCoords(n[0], n[1]) ) === -1);
// pick one from available neighbours
const nPick = neighbours[~~(Math.random() * neighbours.length)];
if (nPick) {
[xCurrent, yCurrent] = nPick;
insert = true;
} else {
insert = false;
}
}
const tileScaleX = map.width / CUBE_SIZE * 0.1;
const tileScaleY = map.height / CUBE_SIZE * 0.1;
return visitedTiles.map( idx => {
let [x, y] = map.getCoordsFromIndex(idx);
return this.scaleTilePosition(new THREE.Vector3(x, y, 0));
});
}
updatePosition() {
const { position } = this;
this.light.position.copy(position);
this.line.advance(position);
}
startPath(waypoints) {
const { position } = this;
this.timeline = new TimelineMax({ onComplete: () => {
TweenMax.to(this.position, 1, {
onUpdate: this.updatePosition.bind(this),
onComplete: () => {
setTimeout(this.spawn.bind(this), Math.random() * 2500 + 500);
}
})
}});
waypoints.forEach( (pos, idx) => {
this.timeline.to(this.position, 0.25, {
x: pos.x,
y: pos.y,
onUpdate: this.updatePosition.bind(this),
ease: Linear.easeNone
});
if (idx === 0) {
this.timeline.to(this.light, 0.2, { power: 1.5 * 4 * Math.PI })
}
if (idx === waypoints.length - 1) {
this.timeline.to(this.light, 0.4, { power: 0.1 * 4 * Math.PI }, '-=0.45')
}
});
}
}
class App {
constructor() {
this.width = 0;
this.height = 0;
this.mouse = new THREE.Vector2(0, 0);
this.init();
this.initLights();
this.initMazeMesh();
this.initTrails();
this.initParticles();
this.initGodRays();
this.setupComposer();
this.setupProstprocessing();
this.addRenderTargetImage();
this.attachEvents();
this.updateSize();
this.onFrame(0);
//this.initHelpers();
//this.addGUI();
}
addGUI() {
this.gui = new dat.GUI();
const setCubeColor = (c) => { this.mazeMesh.material.color.setHex(c.replace('#', '0x')) };
const setOutterLightColor = (c) => { this.outterLight.color.setHex(c.replace('#', '0x')) };
const setLightSphereColor = (c) => { this.lightSphere.material.color.setHex(c.replace('#', '0x')) };
this.cubeColor = "#4583dc";
this.outterLightColor = "#c743ff";
this.lightSphereColor = '#ffd242';
this.gui.addColor(this, 'cubeColor').onChange(setCubeColor);
this.gui.addColor(this, 'outterLightColor').onChange(setOutterLightColor);
this.gui.addColor(this, 'lightSphereColor').onChange(setLightSphereColor);
}
init() {
const { innerWidth: w, innerHeight: h } = window;
const aspect = w / h;
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false });
this.renderer.setPixelRatio( window.devicePixelRatio );
this.renderer.setSize(w, h);
this.renderer.gammaInput = true;
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera( 45, w / h, 0.1, 1000 );
this.camera.position.set(14, 14, 14);
this.clock = new THREE.Clock();
document.body.appendChild(this.renderer.domElement);
}
initTrails() {
const { scene } = this;
const map = new BoardMap('#map-test');
const trails = [];
const t1 = new Trails(map);
t1.group.position.set(-CUBE_SIZE / 2, CUBE_SIZE / 2 + 0.2, -CUBE_SIZE / 2);
t1.group.rotation.x = Math.PI / 2;
scene.add(t1.group);
const t2 = new Trails(map);
t2.group.position.set(CUBE_SIZE / 2, -CUBE_SIZE / 2, -CUBE_SIZE / 2)
t2.group.rotation.x = Math.PI / 2;
t2.group.rotation.y = Math.PI / 2;
scene.add(t2.group);
const t3 = new Trails(map);
t3.group.position.set(-CUBE_SIZE / 2, -CUBE_SIZE / 2 - 0.1, CUBE_SIZE / 2)
scene.add(t3.group);
this.trails = trails;
}
initParticles() {
const { scene } = this;
this.particles = new Particles();
this.particles.clusters.forEach( ( cluster ) => {
scene.add(cluster.points);
});
}
initLights() {
const { scene } = this;
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.15 );
const innerLight = new THREE.PointLight(0xfffff);
const outterLight = new THREE.PointLight(0xc743ff, 3 , 25);
outterLight.position.set(14, 14, 14);
this.outterLight = outterLight;
//Utils.AddDot(scene, pointLight.position);
scene.add( innerLight );
scene.add( outterLight );
scene.add( ambientLight );
}
setupProstprocessing() {
const { composer } = this;
const { innerWidth: w, innerHeight: h } = window;
this.effectFXAA = new THREE.ShaderPass( THREE.FXAAShader );
this.effectFXAA.uniforms[ 'resolution' ].value.set(1/w, 1/h);
composer.addPass( this.effectFXAA );
this.bloomPass = new THREE.UnrealBloomPass( new THREE.Vector2(w, h), 1.5, 0.4, 0.85 );
this.bloomPass.renderToScreen = true;
composer.addPass( this.bloomPass);
}
initGodRays() {
const { scene, mazeMesh } = this;
const geoSphere = new THREE.BoxGeometry(CUBE_SIZE * 0.8, CUBE_SIZE * 0.8, CUBE_SIZE * 0.8);
const matSphere = new THREE.MeshBasicMaterial({ color: 0xffa602, transparent: true });
this.lightSphere = new THREE.Mesh(geoSphere, matSphere);
this.lightSphere.layers.set(1);
this.lightSphere.material.opacity = 1;
scene.add(this.lightSphere);
const matOcclusion = new THREE.MeshBasicMaterial({ color: 0x0 });
this.occlusionMesh = new THREE.Mesh(mazeMesh.geometry, matOcclusion);
this.occlusionMesh.position.z = 0;
this.occlusionMesh.layers.set(1);
scene.add(this.occlusionMesh);
}
getScriptContent(id) {
return document.querySelector(id).textContent;
}
setupComposer() {
const { renderer, camera, scene } = this;
const { innerWidth: w, innerHeight: h } = window;
const scale = 0.5;
this.occlusionRenderTarget = new THREE.WebGLRenderTarget( w * scale, h * scale);
this.occlusionComposer = new THREE.EffectComposer(renderer, this.occlusionRenderTarget);
this.occlusionComposer.addPass( new THREE.RenderPass(scene, camera));
let occPass = new THREE.ShaderPass({
uniforms: {
tDiffuse: { value:null },
lightPosition: { value: new THREE.Vector2(0.5, 0.5) },
exposure: { value: 0.21 },
decay: { value: 0.95 },
density: { value: 0.1 },
weight: { value: 0.7 },
samples: { value: 50 }
},
vertexShader: this.getScriptContent('#shader-passthrough-vertex'),
fragmentShader: this.getScriptContent('#shader-volumetric-light-fragment')
});
occPass.needsSwap = false;
this.occlusionPass = occPass;
this.occlusionComposer.addPass(occPass);
this.composer = new THREE.EffectComposer( renderer );
this.composer.addPass( new THREE.RenderPass( scene, camera ));
let addPass = new THREE.ShaderPass( {
uniforms: {
tDiffuse: { value:null },
tAdd: { value: null }
},
vertexShader: this.getScriptContent('#shader-passthrough-vertex'),
fragmentShader: this.getScriptContent('#shader-additive-fragment')
} );
addPass.uniforms.tAdd.value = this.occlusionRenderTarget.texture;
this.composer.addPass(addPass);
//addPass.renderToScreen = true;
}
addRenderTargetImage() {
const mat = new THREE.ShaderMaterial( {
uniforms: {
tDiffuse: { value: null },
vertexShader: this.getScriptContent('#shader-passthrough-vertex'),
fragmentShader: this.getScriptContent('#shader-passthrough-fragment')
},
} );
mat.uniforms.tDiffuse.value = this.occlusionRenderTarget.texture;
const mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry(2, 2), mat);
mesh.visible = false;
this.composer.passes[1].scene.add(mesh);
}
initMazeMesh() {
const { scene } = this;
const geo = new THREE.Geometry();
const up = this.getGamePlaneGeometry('#map-test');
up.position.y = CUBE_SIZE / 2;
up.updateMatrix();
geo.merge(up.geometry, up.matrix);
const right = this.getGamePlaneGeometry('#map-test');
right.position.x = CUBE_SIZE / 2;
right.rotation.z = Math.PI / 2;
right.updateMatrix();
geo.merge(right.geometry, right.matrix);
const front = this.getGamePlaneGeometry('#map-test');
front.rotation.x = Math.PI / 2;
front.position.z = CUBE_SIZE / 2 - 0.25;
front.updateMatrix();
geo.merge(front.geometry, front.matrix);
const left = this.getGamePlaneGeometry('#map-test');
left.rotation.z = Math.PI / 2;
left.position.x = -CUBE_SIZE / 2 + 0.25;
left.updateMatrix();
geo.merge(left.geometry, left.matrix);
const down = this.getGamePlaneGeometry('#map-test');
down.position.y = -CUBE_SIZE / 2;
down.updateMatrix();
geo.merge(down.geometry, down.matrix);
const back = this.getGamePlaneGeometry('#map-test');
back.rotation.x = Math.PI / 2;
back.position.z = -CUBE_SIZE / 2;
back.updateMatrix();
geo.merge(back.geometry, back.matrix);
const mat = new THREE.MeshPhongMaterial( {
color: 0x4583dc,
} );
this.mazeMesh = new THREE.Mesh(geo, mat);
this.mazeMesh.updateMatrix();
scene.add(this.mazeMesh);
}
getGamePlaneGeometry(mapId) {
const boardMap = new BoardMap(mapId);
const mapBoundariesMesh = new MapBoundariesMesh(boardMap);
return new THREE.Mesh(mapBoundariesMesh.geometry);
}
attachEvents() {
window.addEventListener("resize", this.updateSize.bind(this));
window.addEventListener("mousemove", this.onMouseMove.bind(this));
}
onMouseMove(event) {
this.mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
this.mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
initHelpers() {
const { scene, camera, renderer } = this;
const c = new THREE.OrbitControls(camera, renderer.domElement);
c.enableDamping = true;
c.dampingFactor = 0.25;
c.minDistance = 1;
c.maxDistance = 100;
this.orbitControls = c;
this.axesHelper = new THREE.AxesHelper(500);
//scene.add(this.axesHelper);
}
updateSize() {
const { renderer, camera, composer, occlusionComposer } = this;
const { innerWidth: w, innerHeight: h } = window;
renderer.setSize(w, h);
camera.aspect = w / h;
camera.updateProjectionMatrix();
composer.setSize(w, h);
occlusionComposer.setSize(w, h);
this.width = w;
this.height = h;
}
updateOcclusionIntensity(time) {
const { uniforms: u } = this.occlusionPass;
const n0 = (noise.perlin2(time * 0.0005, 0) + 1) * 0.5;
const n1 = (noise.perlin2(0, time * 0.0005) + 1) * 0.5;
u.exposure.value = THREE.Math.lerp(0.05, 0.21, n0);
u.decay.value = THREE.Math.lerp(0.95, 0.98, n1);
u.density.value = THREE.Math.lerp(0.2, 0.4, n0);
u.weight.value = THREE.Math.lerp(0.1, 0.7, n1);
}
updateLightPosition(time) {
const { lightSphere } = this;
const n0 = (noise.perlin2(time * 0.0005, 0) + 1) * 0.5;
lightSphere.position.y = THREE.Math.lerp(-1, 1, n0);
}
updateCameraTilt() {
const { camera, mouse } = this;
TweenMax.to(this.camera.position, 1.5, {
x: 14 + mouse.x * 2.5,
y: 14 + mouse.y * 2.5,
z: 14 + mouse.x * mouse.y
});
}
onFrame(time) {
const { renderer, scene, camera, clock } = this;
requestAnimationFrame(this.onFrame.bind(this));
//this.orbitControls.update();
camera.layers.set(1);
this.updateCameraTilt();
this.particles.update(clock.getDelta());
this.updateOcclusionIntensity(time);
this.updateLightPosition(time);
renderer.setClearColor(0x0, 0);
this.occlusionComposer.render();
camera.layers.set(0);
camera.lookAt( scene.position );
this.composer.render();
//renderer.render(scene, camera);
}
}
window.app = new App();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/204379/EffectComposer.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/204379/UnrealBloomPass.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/204379/perlin.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/204379/THREE.MeshLine.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
body
overflow: hidden
//background-color: white
background: radial-gradient(ellipse at center, #000000 0%, #100B0D 99%);
img
display: none
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment