-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
30 changed files
with
1,790 additions
and
1,020 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
|
||
const { read } = require('addon-tools-raub'); | ||
const glfw = require('glfw-raub'); | ||
|
||
const { init, addThreeHelpers } = require('../../index'); | ||
const { generatePalette } = require('./utils/palette'); | ||
const { debugShaders } = require('./utils/debug-shaders'); | ||
const { createPostMaterial } = require('./utils/create-post-material'); | ||
const { createColorQuads } = require('./utils/create-color-quads'); | ||
const { createRenderTarget } = require('./utils/create-render-target'); | ||
const { populateScene } = require('./utils/populate-scene'); | ||
|
||
const hueModes = [ | ||
'monochromatic', 'analagous', 'complementary', 'triadic', 'tetradic', | ||
]; | ||
|
||
const { Window } = glfw; | ||
|
||
(async () => { | ||
const THREE = await import('three'); | ||
const { OrbitControls } = await import('three/examples/jsm/controls/OrbitControls.js'); | ||
|
||
const fragmentShader = await read(`${__dirname}/post.glsl`); | ||
|
||
const { | ||
doc, requestAnimationFrame, gl, | ||
} = init({ isGles3: true, width: 1280, height: 720 }); | ||
addThreeHelpers(THREE, gl); | ||
|
||
doc.setPointerCapture = () => { | ||
doc.setInputMode(glfw.CURSOR, glfw.CURSOR_DISABLED); | ||
}; | ||
doc.releasePointerCapture = () => { | ||
doc.setInputMode(glfw.CURSOR, glfw.CURSOR_NORMAL); | ||
}; | ||
doc.on('mousedown', (e) => { doc.emit('pointerdown', e); }); | ||
doc.on('mouseup', (e) => { doc.emit('pointerup', e); }); | ||
doc.on('mousemove', (e) => { doc.emit('pointermove', e); }); | ||
|
||
const cameraOrtho = new THREE.OrthographicCamera( | ||
-doc.w / 2, doc.w / 2, doc.h / 2, -doc.h / 2, - 10, 10, | ||
); | ||
cameraOrtho.position.z = 5; | ||
|
||
const cameraPerspective = new THREE.PerspectiveCamera(50, doc.w / doc.h, 1, 1000); | ||
const controls = new OrbitControls(cameraPerspective, doc); | ||
|
||
cameraPerspective.position.z = 9; | ||
controls.update(); | ||
|
||
const scene = new THREE.Scene(); | ||
let mesh; | ||
populateScene(scene, (m) => { mesh = m; }); | ||
|
||
const scenePost = new THREE.Scene(); | ||
|
||
let isSwap = false; | ||
let modeGrayscale = 0; | ||
let modeHue = 0; | ||
let numColors = 9; | ||
|
||
const rawPalette0 = generatePalette(hueModes[modeHue], numColors); | ||
let palette = rawPalette0.map((c) => (new THREE.Color(...c))); | ||
|
||
let materialPost = createPostMaterial(THREE, numColors, isSwap, modeGrayscale, palette, fragmentShader); | ||
|
||
let rt = createRenderTarget(THREE, materialPost, doc.w, doc.h); | ||
|
||
let quadPost = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), materialPost); | ||
scenePost.add(quadPost); | ||
|
||
const quadHelp = new THREE.Mesh( | ||
new THREE.PlaneGeometry(256, 256), | ||
new THREE.MeshBasicMaterial({ | ||
side: THREE.CullFaceFront, | ||
depthTest: false, | ||
depthWrite: false, | ||
transparent: true, | ||
map: new THREE.TextureLoader().load( __dirname + '/textures/help.png' ), | ||
}), | ||
); | ||
quadHelp.position.set(doc.w / 2 - 128, -doc.h / 2 + 128, 1); | ||
scenePost.add(quadHelp); | ||
|
||
let colorQuads = createColorQuads(THREE, scenePost, palette, isSwap); | ||
|
||
const setPalette = (newValue) => { | ||
palette = newValue; | ||
materialPost.uniforms.colors.value = palette; | ||
if (palette.length !== colorQuads.length) { | ||
if (colorQuads) { | ||
colorQuads.forEach((q) => scenePost.remove(q)); | ||
} | ||
colorQuads = createColorQuads(THREE, scenePost, palette, isSwap); | ||
} else { | ||
palette.forEach((color, i) => { | ||
colorQuads[i].material.uniforms.color.value = color; | ||
}); | ||
} | ||
}; | ||
|
||
const setModeGrayscale = (newValue) => { | ||
if (isSwap && !newValue) { | ||
newValue = 1; | ||
} | ||
modeGrayscale = newValue; | ||
materialPost.uniforms.modeGrayscale.value = modeGrayscale; | ||
}; | ||
|
||
const setIsSwap = (newValue) => { | ||
if (isSwap && !modeGrayscale) { | ||
setModeGrayscale(1); | ||
} | ||
isSwap = newValue; | ||
materialPost.uniforms.isSwap.value = isSwap; | ||
palette.forEach((color, i) => { | ||
colorQuads[i].visible = isSwap; | ||
}); | ||
}; | ||
|
||
const randomizePalette = () => { | ||
const rawPalette = generatePalette(hueModes[modeHue], numColors); | ||
const colorPalette = rawPalette.map((c) => (new THREE.Color(...c))); | ||
setPalette(colorPalette); | ||
}; | ||
|
||
const setModeHue = (newValue) => { | ||
modeHue = newValue; | ||
randomizePalette(); | ||
}; | ||
|
||
const setNumColors = (newValue) => { | ||
if (numColors === newValue) { | ||
return; | ||
} | ||
numColors = newValue; | ||
|
||
const rawPalette = generatePalette(hueModes[modeHue], numColors); | ||
const colorPalette = rawPalette.map((c) => (new THREE.Color(...c))); | ||
materialPost = createPostMaterial( | ||
THREE, numColors, isSwap, modeGrayscale, colorPalette, fragmentShader, | ||
); | ||
materialPost.uniforms.t.value = rt.texture; | ||
|
||
scenePost.remove(quadPost); | ||
quadPost = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), materialPost); | ||
scenePost.add(quadPost); | ||
|
||
randomizePalette(); | ||
}; | ||
|
||
doc.on('keydown', (e) => { | ||
if (e.keyCode === glfw.KEY_P) { | ||
randomizePalette(); | ||
return; | ||
} | ||
if (e.keyCode === glfw.KEY_M) { | ||
setModeHue((modeHue + 1) % hueModes.length); | ||
return; | ||
} | ||
if (e.keyCode === glfw.KEY_S) { | ||
setIsSwap(!isSwap); | ||
return; | ||
} | ||
if (e.keyCode === glfw.KEY_G) { | ||
setModeGrayscale((modeGrayscale + 1) % 4); | ||
return; | ||
} | ||
if (e.keyCode === Window.extraCodes[glfw.KEY_EQUAL]) { | ||
setNumColors(Math.min(16, numColors + 1)); | ||
return; | ||
} | ||
if (e.keyCode === Window.extraCodes[glfw.KEY_MINUS]) { | ||
setNumColors(Math.max(2, numColors - 1)); | ||
return; | ||
} | ||
if (e.keyCode === glfw.KEY_H || e.keyCode === Window.extraCodes[glfw.KEY_F1]) { | ||
quadHelp.visible = !quadHelp.visible; | ||
return; | ||
} | ||
// console.log('kk', e.keyCode, glfw.KEY_EQUAL, Window.extraCodes[glfw.KEY_EQUAL]); | ||
}); | ||
|
||
const renderer = new THREE.WebGLRenderer({ antialias: true }); | ||
renderer.setPixelRatio(doc.devicePixelRatio); | ||
renderer.setSize(doc.w, doc.h); | ||
debugShaders(renderer); | ||
|
||
doc.on('resize', () => { | ||
cameraPerspective.aspect = doc.w / doc.h; | ||
cameraPerspective.updateProjectionMatrix(); | ||
controls.update(); | ||
|
||
cameraOrtho.left = -doc.w / 2; | ||
cameraOrtho.right = doc.w / 2; | ||
cameraOrtho.top = doc.h / 2; | ||
cameraOrtho.bottom = -doc.h / 2; | ||
cameraOrtho.updateProjectionMatrix(); | ||
|
||
quadHelp.position.set(doc.w / 2 - 128, -doc.h / 2 + 128, 1); | ||
|
||
renderer.setSize(doc.w, doc.h); | ||
if (rt) { | ||
rt.dispose(); | ||
rt = null; | ||
} | ||
rt = createRenderTarget(THREE, materialPost, doc.w, doc.h); | ||
}); | ||
|
||
const render = () => { | ||
const rtOld = renderer.getRenderTarget(); | ||
renderer.setRenderTarget(rt); | ||
renderer.render(scene, cameraPerspective); | ||
renderer.setRenderTarget(rtOld); | ||
|
||
renderer.render(scenePost, cameraOrtho); | ||
}; | ||
|
||
const animate = () => { | ||
requestAnimationFrame(animate); | ||
|
||
controls.update(); | ||
|
||
if (mesh) { | ||
mesh.rotation.y = Date.now() * 0.00005; | ||
} | ||
|
||
render(); | ||
}; | ||
|
||
animate(); | ||
})(); |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
in vec2 tc; | ||
out vec4 fragColor; | ||
|
||
#ifndef NUM_COLORS | ||
#define NUM_COLORS 8 | ||
#endif | ||
|
||
#define IDX_LAST (NUM_COLORS - 1) | ||
|
||
uniform bool isSwap; | ||
uniform int modeGrayscale; | ||
uniform sampler2D t; | ||
uniform vec3 colors[NUM_COLORS]; | ||
|
||
|
||
int getIndex(float value) { | ||
return clamp(int(value * float(IDX_LAST) + 0.5), 0, IDX_LAST); | ||
} | ||
|
||
|
||
vec3 paletteSwap(float gray, vec3 colors[NUM_COLORS]) { | ||
int index = getIndex(gray); | ||
return colors[index]; | ||
} | ||
|
||
float toGrayscale(vec3 rgb) { | ||
if (modeGrayscale == 1) { | ||
return 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b; // Luminosity | ||
} | ||
if (modeGrayscale == 2) { | ||
return 0.5 * (max(rgb.r, max(rgb.g, rgb.b)) + min(rgb.r, min(rgb.g, rgb.b))); // Lightness | ||
} | ||
return (rgb.r + rgb.g + rgb.b) * 0.3333333; // Average | ||
} | ||
|
||
void main() { | ||
vec4 rgba = texture(t, tc); | ||
float gray = toGrayscale(rgba.rgb); | ||
vec3 finalColor = rgba.rgb; | ||
if (modeGrayscale > 0) { | ||
finalColor = vec3(gray); | ||
} | ||
fragColor = vec4(mix(finalColor, paletteSwap(gray, colors), bvec3(isSwap)), rgba.a); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Oops, something went wrong.