You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

654 lines
14 KiB

2 years ago
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - multiple elements with text</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
* {
box-sizing: border-box;
-moz-box-sizing: border-box;
}
body {
background-color: #fff;
color: #444;
margin: auto;
padding: .5in;
max-width: 7in;
text-align: justify;
}
a {
color: #08f;
}
#info {
left: 0px;
}
.view {
width: 5in;
height: 5in;
margin: auto;
}
#c {
position: fixed;
left: 0px; top: 0px;
width: 100%;
height: 100%;
background-color: #fff;
z-index: -1;
}
.math {
text-align: center;
}
.math-frac {
display: inline-block;
vertical-align: middle;
}
.math-num {
display: block;
}
.math-denom {
display: block;
border-top: 1px solid;
}
.math-sqrt {
display: inline-block;
transform: scale(1, 1.3);
}
.math-sqrt-stem {
display: inline-block;
border-top: 1px solid;
margin-top: 5px;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - multiple elements with text - webgl</div>
<!-- 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",
"three/addons/": "./jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const scenes = [];
const clock = new THREE.Clock();
let views, t, canvas, renderer;
window.onload = init;
function init() {
const balls = 20;
const size = .25;
const colors = [
'rgb(0,127,255)', 'rgb(255,0,0)', 'rgb(0,255,0)', 'rgb(0,255,255)',
'rgb(255,0,255)', 'rgb(255,0,127)', 'rgb(255,255,0)', 'rgb(0,255,127)'
];
canvas = document.getElementById( 'c' );
renderer = new THREE.WebGLRenderer( { canvas: canvas, antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
views = document.querySelectorAll( '.view' );
for ( let n = 0; n < views.length; n ++ ) {
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xffffff );
const geometry0 = new THREE.BufferGeometry();
const geometry1 = new THREE.BufferGeometry();
const vertices = [];
if ( views[ n ].lattice ) {
const range = balls / 2;
for ( let i = - range; i <= range; i ++ ) {
for ( let j = - range; j <= range; j ++ ) {
for ( let k = - range; k <= range; k ++ ) {
vertices.push( i, j, k );
}
}
}
} else {
for ( let m = 0; m < Math.pow( balls, 3 ); m ++ ) {
const i = balls * Math.random() - balls / 2;
const j = balls * Math.random() - balls / 2;
const k = balls * Math.random() - balls / 2;
vertices.push( i, j, k );
}
}
geometry0.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
geometry1.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices.slice(), 3 ) );
const index = Math.floor( colors.length * Math.random() );
const canvas2 = document.createElement( 'canvas' );
canvas2.width = 128;
canvas2.height = 128;
const context = canvas2.getContext( '2d' );
context.arc( 64, 64, 64, 0, 2 * Math.PI );
context.fillStyle = colors[ index ];
context.fill();
const texture = new THREE.CanvasTexture( canvas2 );
const material = new THREE.PointsMaterial( { size: size, map: texture, transparent: true, alphaTest: 0.1 } );
scene.add( new THREE.Points( geometry0, material ) );
scene.userData.view = views[ n ];
scene.userData.geometry1 = geometry1;
const camera = new THREE.PerspectiveCamera( 75, 1, 0.1, 100 );
camera.position.set( 0, 0, 1.2 * balls );
scene.userData.camera = camera;
const controls = new OrbitControls( camera, views[ n ] );
scene.userData.controls = controls;
scenes.push( scene );
}
t = 0;
animate();
}
function updateSize() {
const width = canvas.clientWidth;
const height = canvas.clientHeight;
if ( canvas.width !== width || canvas.height != height ) {
renderer.setSize( width, height, false );
}
}
function animate() {
render();
requestAnimationFrame( animate );
}
function render() {
updateSize();
renderer.setClearColor( 0xffffff );
renderer.setScissorTest( false );
renderer.clear();
renderer.setClearColor( 0x000000 );
renderer.setScissorTest( true );
scenes.forEach( function ( scene ) {
const rect = scene.userData.view.getBoundingClientRect();
// check if it's offscreen. If so skip it
if ( rect.bottom < 0 || rect.top > renderer.domElement.clientHeight ||
rect.right < 0 || rect.left > renderer.domElement.clientWidth ) {
return; // it's off screen
}
// set the viewport
const width = rect.right - rect.left;
const height = rect.bottom - rect.top;
const left = rect.left;
const bottom = renderer.domElement.clientHeight - rect.bottom;
renderer.setViewport( left, bottom, width, height );
renderer.setScissor( left, bottom, width, height );
renderer.render( scene, scene.userData.camera );
const points = scene.children[ 0 ];
const position = points.geometry.attributes.position;
const point = new THREE.Vector3();
const offset = new THREE.Vector3();
for ( let i = 0; i < position.count; i ++ ) {
point.fromBufferAttribute( scene.userData.geometry1.attributes.position, i );
scene.userData.view.displacement( point.x, point.y, point.z, t / 5, offset );
position.setXYZ( i, point.x + offset.x, point.y + offset.y, point.z + offset.z );
}
position.needsUpdate = true;
} );
t += clock.getDelta() * 60;
}
</script>
<p>Sound waves whose geometry is determined by a single dimension, plane waves, obey the wave equation</p>
<!-- css math formatting inspired by http://mathquill.com/mathquill/mathquill.css -->
<div class="math">
<span class="math-frac">
<span class="math-num">
&part;<sup>2</sup><i>u</i>
</span>
<span class="math-denom">
&part;<i>r</i><sup>2</sup>
</span>
</span>
&minus;
<span class="math-frac">
<span class="math-num">
1<sup></sup> <!-- sup for vertical alignment -->
</span>
<span class="math-denom">
<i>c</i><sup>2</sup>
</span>
</span>
<span class="math-frac">
<span class="math-num">
&part;<sup>2</sup><i>u</i>
</span>
<span class="math-denom">
&part;<i>t</i><sup>2</sup>
</span>
</span>
=&nbsp;0
</div>
<p>where <i>c</i> designates the speed of sound in the medium. The monochromatic solution for plane waves will be taken to be</p>
<div class="math">
<i>u</i>(<i>r</i>,<i>t</i>)&thinsp;=&nbsp;sin(<i>k</i><i>r</i>&thinsp;&plusmn;&thinsp;&omega;<i>t</i>)
</div>
<p>where &omega; is the frequency and <i>k</i>=&omega;/<i>c</i> is the wave number. The sign chosen in the argument determines the direction of movement of the waves.</p>
<p>Here is a plane wave moving on a three-dimensional lattice of atoms:</p>
<div class="view">
<script>
/* eslint-disable prefer-const*/
let parent = document.scripts[ document.scripts.length - 1 ].parentNode;
parent.displacement = function ( x, y, z, t, target ) {
return target.set( Math.sin( x - t ), 0, 0 );
};
parent.lattice = true;
</script>
</div>
<p>Here is a plane wave moving through a three-dimensional random distribution of molecules:</p>
<div class="view">
<script>
parent = document.scripts[ document.scripts.length - 1 ].parentNode;
parent.displacement = function ( x, y, z, t, target ) {
return target.set( Math.sin( x - t ), 0, 0 );
};
parent.lattice = false;
</script>
</div>
<p>Sound waves whose geometry is determined by two dimensions, cylindrical waves, obey the wave equation</p>
<div class="math">
<span class="math-frac">
<span class="math-num">
&part;<sup>2</sup><i>u</i>
</span>
<span class="math-denom">
&part;<i>r</i><sup>2</sup>
</span>
</span>
&plus;
<span class="math-frac">
<span class="math-num">
1
</span>
<span class="math-denom">
<i>r</i>
</span>
</span>
<span class="math-frac">
<span class="math-num">
&part;<i>u</i>
</span>
<span class="math-denom">
&part;<i>r</i>
</span>
</span>
&minus;
<span class="math-frac">
<span class="math-num">
1<sup></sup> <!-- sup for vertical alignment -->
</span>
<span class="math-denom">
<i>c</i><sup>2</sup>
</span>
</span>
<span class="math-frac">
<span class="math-num">
&part;<sup>2</sup><i>u</i>
</span>
<span class="math-denom">
&part;<i>t</i><sup>2</sup>
</span>
</span>
=&nbsp;0
</div>
<p>The monochromatic solution for cylindrical sound waves will be taken to be</p>
<div class="math">
<i>u</i>(<i>r</i>,<i>t</i>)&thinsp;=
<span class="math-frac">
<span class="math-num">
sin(<i>k</i><i>r</i>&thinsp;&plusmn;&thinsp;&omega;<i>t</i>)
</span>
<span class="math-denom">
<span class="math-sqrt">&radic;</span><span class="math-sqrt-stem"><i>r</i></span>
</span>
</span>
</div>
<p>Here is a cylindrical wave moving on a three-dimensional lattice of atoms:</p>
<div class="view">
<script>
parent = document.scripts[ document.scripts.length - 1 ].parentNode;
parent.displacement = function ( x, y, z, t, target ) {
if ( x * x + y * y < 0.01 ) {
return target.set( 0, 0, 0 );
} else {
const rho = Math.sqrt( x * x + y * y );
const phi = Math.atan2( y, x );
return target.set( 1.5 * Math.cos( phi ) * Math.sin( rho - t ) / Math.sqrt( rho ), 1.5 * Math.sin( phi ) * Math.sin( rho - t ) / Math.sqrt( rho ), 0 );
}
};
parent.lattice = true;
</script>
</div>
<p>Here is a cylindrical wave moving through a three-dimensional random distribution of molecules:</p>
<div class="view">
<script>
parent = document.scripts[ document.scripts.length - 1 ].parentNode;
parent.displacement = function ( x, y, z, t, target ) {
if ( x * x + y * y < 0.01 ) {
return target.set( 0, 0, 0 );
} else {
const rho = Math.sqrt( x * x + y * y );
const phi = Math.atan2( y, x );
return target.set( 1.5 * Math.cos( phi ) * Math.sin( rho - t ) / Math.sqrt( rho ), 1.5 * Math.sin( phi ) * Math.sin( rho - t ) / Math.sqrt( rho ), 0 );
}
};
parent.lattice = false;
</script>
</div>
<p>Sound waves whose geometry is determined by three dimensions, spherical waves, obey the wave equation</p>
<div class="math">
<span class="math-frac">
<span class="math-num">
&part;<sup>2</sup><i>u</i>
</span>
<span class="math-denom">
&part;<i>r</i><sup>2</sup>
</span>
</span>
&plus;
<span class="math-frac">
<span class="math-num">
2
</span>
<span class="math-denom">
<i>r</i>
</span>
</span>
<span class="math-frac">
<span class="math-num">
&part;<i>u</i>
</span>
<span class="math-denom">
&part;<i>r</i>
</span>
</span>
&minus;
<span class="math-frac">
<span class="math-num">
1<sup></sup> <!-- sup for vertical alignment -->
</span>
<span class="math-denom">
<i>c</i><sup>2</sup>
</span>
</span>
<span class="math-frac">
<span class="math-num">
&part;<sup>2</sup><i>u</i>
</span>
<span class="math-denom">
&part;<i>t</i><sup>2</sup>
</span>
</span>
=&nbsp;0
</div>
<p>The monochromatic solution for spherical sound waves will be taken to be</p>
<div class="math">
<i>u</i>(<i>r</i>,<i>t</i>)&thinsp;=
<span class="math-frac">
<span class="math-num">
sin(<i>k</i><i>r</i>&thinsp;&plusmn;&thinsp;&omega;<i>t</i>)
</span>
<span class="math-denom">
<i>r</i>
</span>
</span>
</div>
<p>Here is a spherical wave moving on a three-dimensional lattice of atoms:</p>
<div class="view">
<script>
parent = document.scripts[ document.scripts.length - 1 ].parentNode;
parent.displacement = function ( x, y, z, t, target ) {
if ( x * x + y * y + z * z < 0.01 ) {
return target.set( 0, 0, 0 );
} else {
const r = Math.sqrt( x * x + y * y + z * z );
const theta = Math.acos( z / r );
const phi = Math.atan2( y, x );
return target.set( 3 * Math.cos( phi ) * Math.sin( theta ) * Math.sin( r - t ) / r, 3 * Math.sin( phi ) * Math.sin( theta ) * Math.sin( r - t ) / r, 3 * Math.cos( theta ) * Math.sin( r - t ) / r );
}
};
parent.lattice = true;
</script>
</div>
<p>Here is a spherical wave moving through a three-dimensional random distribution of molecules:</p>
<div class="view">
<script>
parent = document.scripts[ document.scripts.length - 1 ].parentNode;
parent.displacement = function ( x, y, z, t, target ) {
if ( x * x + y * y + z * z < 0.01 ) {
return target.set( 0, 0, 0 );
} else {
const r = Math.sqrt( x * x + y * y + z * z );
const theta = Math.acos( z / r );
const phi = Math.atan2( y, x );
return target.set( 3 * Math.cos( phi ) * Math.sin( theta ) * Math.sin( r - t ) / r, 3 * Math.sin( phi ) * Math.sin( theta ) * Math.sin( r - t ) / r, 3 * Math.cos( theta ) * Math.sin( r - t ) / r );
}
};
parent.lattice = false;
</script>
</div>
<p>The mathematical description of sound waves can be carried to higher dimensions, but one needs to wait for Four.js and its higher-dimensional successors to attempt visualizations.</p>
</body>
</html>