Created
September 28, 2018 17:20
-
-
Save valex/d5acf0da3b9c0d56149b9eb99e5bd003 to your computer and use it in GitHub Desktop.
Creating custom shaders
This file contains hidden or 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
THREE.CustomGrayScaleShader = { | |
uniforms: { | |
"tDiffuse": {type: "t", value: null}, | |
"rPower": {type: "f", value: 0.2126}, | |
"gPower": {type: "f", value: 0.7152}, | |
"bPower": {type: "f", value: 0.0722} | |
}, | |
// 0.2126 R + 0.7152 G + 0.0722 B | |
// vertexshader is always the same for postprocessing steps | |
vertexShader: [ | |
"varying vec2 vUv;", | |
"void main() {", | |
"vUv = uv;", | |
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", | |
"}" | |
].join("\n"), | |
fragmentShader: [ | |
// pass in our custom uniforms | |
"uniform float rPower;", | |
"uniform float gPower;", | |
"uniform float bPower;", | |
// pass in the image/texture we'll be modifying | |
"uniform sampler2D tDiffuse;", | |
// used to determine the correct texel we're working on | |
"varying vec2 vUv;", | |
// executed, in parallel, for each pixel | |
"void main() {", | |
// get the pixel from the texture we're working with (called a texel) | |
"vec4 texel = texture2D( tDiffuse, vUv );", | |
// calculate the new color | |
"float gray = texel.r*rPower + texel.g*gPower + texel.b*bPower;", | |
// return this new color | |
"gl_FragColor = vec4( vec3(gray), texel.w );", | |
"}" | |
].join("\n") | |
}; | |
THREE.CustomBitShader = { | |
uniforms: { | |
"tDiffuse": {type: "t", value: null}, | |
"bitSize": {type: "i", value: 4} | |
}, | |
vertexShader: [ | |
"varying vec2 vUv;", | |
"void main() {", | |
"vUv = uv;", | |
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", | |
"}" | |
].join("\n"), | |
fragmentShader: [ | |
"uniform int bitSize;", | |
"uniform sampler2D tDiffuse;", | |
"varying vec2 vUv;", | |
"void main() {", | |
"vec4 texel = texture2D( tDiffuse, vUv );", | |
"float n = pow(float(bitSize),2.0);", | |
"float newR = floor(texel.r*n)/n;", | |
"float newG = floor(texel.g*n)/n;", | |
"float newB = floor(texel.b*n)/n;", | |
"gl_FragColor = vec4( vec3(newR,newG,newB), 1.0);", | |
"}" | |
].join("\n") | |
}; |
This file contains hidden or 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
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Example 11.07 - custom shaderpass</title> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.min.js"></script> | |
<script type="text/javascript" src="../libs96/OrbitControls.js"></script> | |
<script type="text/javascript" src="../utils/SceneUtils.js"></script> | |
<!-- https://github.com/mrdoob/three.js/tree/master/examples/js/postprocessing --> | |
<script type="text/javascript" src="../libs/postprocessing/EffectComposer.js"></script> | |
<script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script> | |
<script type="text/javascript" src="../libs/postprocessing/MaskPass.js"></script> | |
<script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script> | |
<script type="text/javascript" src="../libs/postprocessing/RenderPass.js"></script> | |
<!-- https://github.com/mrdoob/three.js/tree/master/examples/js/shaders --> | |
<script type="text/javascript" src="../libs/shaders/CopyShader.js"></script> | |
<script type="text/javascript" src="custom-shader.js"></script> | |
<style> | |
body { | |
/* set margin to 0 and overflow to hidden, to go fullscreen */ | |
margin: 0; | |
overflow: hidden; | |
} | |
</style> | |
</head> | |
<body> | |
<!--- Just create a very simple fragment shader that converts a color image to a grayscale image.--> | |
<!--- Using the following formula from wikipedia: Y' = 0.2126 R + 0.7152 G + 0.0722 B--> | |
<!--- Maybe convert a 32 bit image to an 8 bit image.--> | |
<!--- Is now a scale from 0 to 1.--> | |
<!--- Or just multiple with 256 and round and divide by 256.--> | |
<div id="Stats-output"> | |
</div> | |
<!-- Div which will hold the Output --> | |
<div id="WebGL-output"> | |
</div> | |
<!-- Javascript code that runs our Three.js examples --> | |
<script type="text/javascript"> | |
// once everything is loaded, we run our Three.js stuff. | |
function init() { | |
var stats = initStats(); | |
// create a scene, that will hold all our elements such as objects, cameras and lights. | |
var scene = new THREE.Scene(); | |
// create a camera, which defines where we're looking at. | |
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); | |
// create a render and set the size | |
var webGLRenderer = new THREE.WebGLRenderer(); | |
webGLRenderer.setClearColor(new THREE.Color(0x000000)); | |
webGLRenderer.setSize(window.innerWidth, window.innerHeight); | |
webGLRenderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap | |
var sphere = createMesh(new THREE.SphereGeometry(10, 40, 40)); | |
// add the sphere to the scene | |
scene.add(sphere); | |
// position and point the camera to the center of the scene | |
camera.position.x = -10; | |
camera.position.y = 15; | |
camera.position.z = 25; | |
camera.lookAt(new THREE.Vector3(0, 0, 0)); | |
var orbitControls = new THREE.OrbitControls(camera); | |
orbitControls.autoRotate = false; | |
var clock = new THREE.Clock(); | |
var ambi = new THREE.AmbientLight(0x181818); | |
scene.add(ambi); | |
var spotLight = new THREE.DirectionalLight(0xffffff); | |
spotLight.position.set(550, 100, 550); | |
spotLight.intensity = 0.6; | |
scene.add(spotLight); | |
// add the output of the renderer to the html element | |
document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement); | |
var renderPass = new THREE.RenderPass(scene, camera); | |
var effectCopy = new THREE.ShaderPass(THREE.CopyShader); | |
effectCopy.renderToScreen = true; | |
var shaderPass = new THREE.ShaderPass(THREE.CustomGrayScaleShader); | |
shaderPass.enabled = false; | |
var bitPass = new THREE.ShaderPass(THREE.CustomBitShader); | |
bitPass.enabled = false; | |
var composer = new THREE.EffectComposer(webGLRenderer); | |
composer.addPass(renderPass); | |
composer.addPass(shaderPass); | |
composer.addPass(bitPass); | |
composer.addPass(effectCopy); | |
// setup the control gui | |
var controls = new function () { | |
this.grayScale = false; | |
this.rPower = 0.2126; | |
this.gPower = 0.7152; | |
this.bPower = 0.0722; | |
this.bitShader = false; | |
this.bitSize = 8; | |
this.updateEffectFilm = function () { | |
shaderPass.enabled = controls.grayScale; | |
shaderPass.uniforms.rPower.value = controls.rPower; | |
shaderPass.uniforms.gPower.value = controls.gPower; | |
shaderPass.uniforms.bPower.value = controls.bPower; | |
}; | |
this.updateBit = function () { | |
bitPass.enabled = controls.bitShader; | |
bitPass.uniforms.bitSize.value = controls.bitSize; | |
} | |
}; | |
var gui = new dat.GUI(); | |
var grayMenu = gui.addFolder('gray scale'); | |
grayMenu.add(controls, 'grayScale').onChange(controls.updateEffectFilm); | |
grayMenu.add(controls, 'rPower', 0, 1).onChange(controls.updateEffectFilm); | |
grayMenu.add(controls, 'gPower', 0, 1).onChange(controls.updateEffectFilm); | |
grayMenu.add(controls, 'bPower', 0, 1).onChange(controls.updateEffectFilm); | |
var bitMenu = gui.addFolder('bit'); | |
bitMenu.add(controls, 'bitShader').onChange(controls.updateBit); | |
bitMenu.add(controls, 'bitSize', 2, 24).step(1).onChange(controls.updateBit); | |
// call the render function | |
var step = 0; | |
render(); | |
function createMesh(geom) { | |
var planetTexture = new THREE.TextureLoader().load("../assets96/textures/planets/Earth.png"); | |
var specularTexture = new THREE.TextureLoader().load("../assets96/textures/planets/EarthSpec.png"); | |
var normalTexture = new THREE.TextureLoader().load("../assets96/textures/planets/EarthNormal.png"); | |
var planetMaterial = new THREE.MeshPhongMaterial(); | |
planetMaterial.specularMap = specularTexture; | |
planetMaterial.specular = new THREE.Color(0x4444aa); | |
planetMaterial.normalMap = normalTexture; | |
planetMaterial.map = planetTexture; | |
// planetMaterial.shininess = 150; | |
// create a multimaterial | |
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [planetMaterial]); | |
return mesh; | |
} | |
function render() { | |
stats.update(); | |
//sphere.rotation.y=step+=0.01; | |
var delta = clock.getDelta(); | |
orbitControls.update(delta); | |
sphere.rotation.y += 0.002; | |
// render using requestAnimationFrame | |
requestAnimationFrame(render); | |
// webGLRenderer.render(scene, camera); | |
composer.render(delta); | |
} | |
function initStats() { | |
var stats = new Stats(); | |
stats.setMode(0); // 0: fps, 1: ms | |
// Align top-left | |
stats.domElement.style.position = 'absolute'; | |
stats.domElement.style.left = '0px'; | |
stats.domElement.style.top = '0px'; | |
document.getElementById("Stats-output").appendChild(stats.domElement); | |
return stats; | |
} | |
} | |
window.onload = init; | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment