Created
March 25, 2019 09:13
-
-
Save steffenvan/7e3987d6db5bd751738b0b251ab8f0a2 to your computer and use it in GitHub Desktop.
Revisions
-
steffenvan created this gist
Mar 25, 2019 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,10 @@ <script src="https://unpkg.com/[email protected]/build/three.min.js"></script> <script src="https://unpkg.com/[email protected]/examples/js/controls/OrbitControls.js"></script> <script src="https://unpkg.com/[email protected]/examples/js/controls/TransformControls.js"></script> <script src="https://unpkg.com/[email protected]/build/dat.gui.js"></script> <canvas id="tex" width="512" height="512"></canvas> <span id="info"> When "B" is under shadow, it is the same color as "A". Drag the purple square over the tiles to compare colors. </span> <div id="container"></div> 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,233 @@ var ctx = tex.getContext("2d"); const n = 512 / 5; // Generate a checker pattern texture. const checkerOpts = { perimeter: 38, flankingDiagonals: 30, centerDiagonal: 88 }; function drawCheckers() { const opts = checkerOpts; ctx.clearRect(0, 0, n * 5, n * 5); // background ctx.fillStyle = "hsl(0, 0%, 100%)"; ctx.fillRect(0, 0, n * 5, n * 5); // A ctx.fillStyle = `hsl(0, 0%, ${opts.perimeter}%)`; ctx.fillRect(0 * n, 1 * n, n, n); ctx.fillRect(1 * n, 0 * n, n, n); ctx.fillRect(3 * n, 4 * n, n, n); ctx.fillRect(4 * n, 3 * n, n, n); ctx.fillRect(4 * n, 1 * n, n, n); ctx.fillRect(3 * n, 0 * n, n, n); ctx.fillStyle = `hsl(0, 0%, ${opts.flankingDiagonals}%)`; ctx.fillRect(2 * n, 1 * n, n, n); ctx.fillRect(1 * n, 2 * n, n, n); ctx.fillRect(0 * n, 3 * n, n, n); ctx.fillRect(3 * n, 2 * n, n, n); ctx.fillRect(2 * n, 3 * n, n, n); ctx.fillRect(1 * n, 4 * n, n, n); // B ctx.fillStyle = `hsl(0, 0%, ${opts.centerDiagonal}%)`; ctx.fillRect(2 * n, 2 * n, n, n); ctx.fillRect(1 * n, 3 * n, n, n); ctx.fillStyle = "black"; ctx.font = "30pt sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText("A", 152, 50); ctx.fillText("B", 255, 255); } drawCheckers(); // Setup 3D renderer var renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(window.devicePixelRatio); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; container.appendChild(renderer.domElement); var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 ); camera.position.set(2, 2, 4); camera.lookAt(scene.position); function setSize() { renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); } setSize(); window.addEventListener("resize", setSize); // Lighting const ambient = new THREE.AmbientLight(0xffffff, 0.8); scene.add(ambient); const light = new THREE.DirectionalLight(0xffffff, 2.9); light.castShadow = true; light.shadow.mapSize.height = light.shadow.mapSize.width = 256; light.position.set(2, 1.1, -2); scene.add(light); // Create floor var geometry = new THREE.BoxGeometry(3, 0.2, 3); // Fix UV mapping on edges of floor geometry.faceVertexUvs[0][8][1].y = 1; geometry.faceVertexUvs[0][9][0].y = 2; geometry.faceVertexUvs[0][9][1].y = 2; geometry.faceVertexUvs[0][9][2].y = 2; geometry.faceVertexUvs[0][0][1].y = 1; geometry.faceVertexUvs[0][1][0].y = 2; geometry.faceVertexUvs[0][1][1].y = 2; geometry.faceVertexUvs[0][1][2].y = 2; geometry.faceVertexUvs[0][10][1].y = 1; geometry.faceVertexUvs[0][11][0].y = 2; geometry.faceVertexUvs[0][11][1].y = 2; geometry.faceVertexUvs[0][11][2].y = 2; geometry.faceVertexUvs[0][2][1].y = 1; geometry.faceVertexUvs[0][3][0].y = 2; geometry.faceVertexUvs[0][3][1].y = 2; geometry.faceVertexUvs[0][3][2].y = 2; var map = new THREE.CanvasTexture(tex); map.anisotropy = renderer.capabilities.getMaxAnisotropy(); var material = new THREE.MeshLambertMaterial({ color: 0xaaaaaa, map }); var floor = new THREE.Mesh(geometry, material); floor.receiveShadow = true; scene.add(floor); function updateCheckers() { drawCheckers(); map.needsUpdate = true; } // Green cylinder const cylRadius = 0.6; var geometry = new THREE.CylinderBufferGeometry(cylRadius, cylRadius, 1, 32); var material = new THREE.MeshStandardMaterial({ color: 0x55aa55, roughness: 1, metalness: 0.7 }); var cyl = new THREE.Mesh(geometry, material); cyl.castShadow = true; cyl.position.set(1.5 - cylRadius, 0.45, -1.5 + cylRadius); scene.add(cyl); // Create a movable swatch for comparing colors const swatchMat = new THREE.MeshBasicMaterial({ color: 0x777777 }); const swatchTrans = new THREE.Group(); const swatch = new THREE.Group(); swatch.position.set(-0.5, 0, 0.2); swatchTrans.add(swatch); swatch.add( new THREE.Mesh(new THREE.BoxBufferGeometry(0.25, 0.1, 2), swatchMat) ); swatch.children[0].position.x = -0.3; swatch.add( new THREE.Mesh(new THREE.BoxBufferGeometry(0.25, 0.1, 2), swatchMat) ); swatch.children[1].position.x = 0.3; swatch.add( new THREE.Mesh(new THREE.BoxBufferGeometry(0.8, 0.1, 0.9), swatchMat) ); swatch.add( new THREE.Mesh(new THREE.BoxBufferGeometry(0.8, 0.1, 0.2), swatchMat) ); swatch.children[3].position.z = 0.9; swatch.add( new THREE.Mesh(new THREE.BoxBufferGeometry(0.8, 0.1, 0.2), swatchMat) ); swatch.children[4].position.z = -0.9; swatchTrans.rotation.y = Math.sin(1 / 2); swatchTrans.position.set(-1.8, 0.1, -0.5); scene.add(swatchTrans); // Camera controls const orbit = new THREE.OrbitControls(camera, container); function addXZTransformControls(obj) { const transformControls = new THREE.TransformControls( camera, renderer.domElement ); // Hide unwanted transform gizmos. ['handles', 'pickers', 'planes'].forEach(gizmo => { for (const child of transformControls.children[0][gizmo].children) { if (child.name === "XZ") { continue; } child.visible = false; } }) transformControls.setSize(1); scene.add(transformControls); transformControls.attach(obj); orbit.addEventListener("change", () => transformControls.update()); } addXZTransformControls(swatchTrans); addXZTransformControls(cyl); // Render loop function animate(delta) { renderer.render(scene, camera); } renderer.setAnimationLoop(animate); // Control UI const gui = new dat.GUI(); gui.width = 300; gui.closed = window.innerWidth < 1024; gui .add(checkerOpts, "perimeter", 0, 100, 0.1) .name("Perimeter tiles") .onChange(updateCheckers); gui .add(checkerOpts, "flankingDiagonals", 0, 100, 0.1) .name("Flanking tiles") .onChange(updateCheckers); gui .add(checkerOpts, "centerDiagonal", 0, 100, 0.1) .name("Center tiles") .onChange(updateCheckers); gui .add(ambient, "intensity", 0, 1) .name("Ambient intensity") .onChange(updateCheckers); gui.add(light, "visible").name("Enable light"); gui.add(cyl, "visible").name("Show cylinder"); gui .add({ texture: false }, "texture") .name("Show texture") .onChange(show => (tex.style.display = show ? "block" : "none")); gui.add( { Reset: () => { gui.revert(gui); } }, "Reset" ); 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,39 @@ html, body { margin: 0; padding: 0; font-size: 0; display: flex; justify-content: center; } #tex { position: absolute; width: 128px; left: 0; display: none; } #info { position: absolute; color: white; font-size: 12pt; font-family: sans-serif; background: black; padding: 0.5em; bottom: 0; } .dg.main { font-size: 13px; } .dg .c input[type="checkbox"] { width: 18px; height: 18px; margin-top: 4px; } .illusion .dg.main .close-button { background: #333; height: 30px; display: flex; justify-content: center; align-items: center; } 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,7 @@ Three.js Checker Shadow Illusion -------------------------------- An interactive version of the infamous Checker Shadow Illusion built in three.js A [Pen](https://codepen.io/steffenvan/pen/WmmxmK) by [Steffen Van](https://codepen.io/steffenvan) on [CodePen](https://codepen.io). [License](https://codepen.io/steffenvan/pen/WmmxmK/license).