<!-- Licensed under a BSD license. See license.html for license --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> <title>Three.js - Canvas Textured Cube</title> <style> html, body { height: 100%; margin: 0; } #c { width: 100%; height: 100%; display: block; } </style> </head> <body> <canvas id="c"></canvas> </body> <!-- Import maps polyfill --> <!-- Remove this when import maps will be widely supported --> <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script> <script type="importmap"> { "imports": { "three": "../../build/three.module.js" } } </script> <script type="module"> import * as THREE from 'three'; function main() { const canvas = document.querySelector('#c'); const renderer = new THREE.WebGLRenderer({canvas}); const fov = 75; const aspect = 2; // the canvas default const near = 0.1; const far = 5; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); camera.position.z = 2; const scene = new THREE.Scene(); const boxWidth = 1; const boxHeight = 1; const boxDepth = 1; const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth); const cubes = []; // just an array we can use to rotate the cubes const ctx = document.createElement('canvas').getContext('2d'); ctx.canvas.width = 256; ctx.canvas.height = 256; ctx.fillStyle = '#FFF'; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); const texture = new THREE.CanvasTexture(ctx.canvas); const material = new THREE.MeshBasicMaterial({ map: texture, }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); cubes.push(cube); // add to our list of cubes to rotate function resizeRendererToDisplaySize(renderer) { const canvas = renderer.domElement; const width = canvas.clientWidth; const height = canvas.clientHeight; const needResize = canvas.width !== width || canvas.height !== height; if (needResize) { renderer.setSize(width, height, false); } return needResize; } function rand(min, max) { if (max === undefined) { max = min; min = 0; } return Math.random() * (max - min) + min; } function randVelocity() { return rand(2, 4) * (rand(2) < 1 ? -1 : 1); } const maxLines = 60; const points = [ { position: [rand(256), rand(256)], direction: [randVelocity(), randVelocity()]}, { position: [rand(256), rand(256)], direction: [randVelocity(), randVelocity()]}, ]; const lineHistory = []; let lineCursor = 0; function drawCurrentLine() { const line = lineHistory[lineCursor]; ctx.beginPath(); ctx.moveTo(...line[0]); ctx.lineTo(...line[1]); ctx.stroke(); } function drawLines(time) { points.forEach((point) => { point.position.forEach((position, ndx) => { const newPosition = position + point.direction[ndx]; if (newPosition > 255) { point.direction[ndx] = rand(-2, -4); } else if (newPosition < 0) { point.direction[ndx] = rand( 2, 4); } point.position[ndx] = newPosition; }); }); if (lineHistory.length === maxLines) { ctx.lineWidth = 3; ctx.strokeStyle = '#FFF'; drawCurrentLine(); } lineHistory[lineCursor] = points.map(point => point.position.slice()); ctx.lineWidth = 1; ctx.strokeStyle = hsl(time, 1, .5); drawCurrentLine(); lineCursor = (lineCursor + 1) % maxLines; } function hsl(h, s, l) { return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`; } function render(time) { time *= 0.001; if (resizeRendererToDisplaySize(renderer)) { const canvas = renderer.domElement; camera.aspect = canvas.clientWidth / canvas.clientHeight; camera.updateProjectionMatrix(); } drawLines(time * 0.1); texture.needsUpdate = true; cubes.forEach((cube, ndx) => { const speed = .2 + ndx * .1; const rot = time * speed; cube.rotation.x = rot; cube.rotation.y = rot; }); renderer.render(scene, camera); requestAnimationFrame(render); } requestAnimationFrame(render); } main(); </script> </html>