fix water
This commit is contained in:
@@ -2,3 +2,4 @@ node_modules/
|
||||
yarn.lock
|
||||
dist/
|
||||
build/
|
||||
check-*.png
|
||||
|
||||
Generated
+4771
File diff suppressed because it is too large
Load Diff
+9
-14
@@ -1,19 +1,14 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"babel-loader": "^9.1.0",
|
||||
"css-loader": "^6.7.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"moment": "^2.29.4",
|
||||
"sass": "^1.57.1",
|
||||
"sass-loader": "^13.2.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"three": "^0.147.0",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
"css-loader": "^7.1.4",
|
||||
"html-webpack-plugin": "^5.6.7",
|
||||
"sass": "^1.101.0",
|
||||
"sass-loader": "^17.0.0",
|
||||
"style-loader": "^4.0.0",
|
||||
"three": "^0.185.1",
|
||||
"webpack": "^5.108.4",
|
||||
"webpack-cli": "^7.2.1",
|
||||
"webpack-dev-server": "^6.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "webpack serve --env mode=development",
|
||||
|
||||
+12
-12
@@ -18,19 +18,21 @@ camera.position.x = 10;
|
||||
camera.position.y = 4;
|
||||
|
||||
|
||||
const renderer = new THREE.WebGLRenderer();
|
||||
const renderer = new THREE.WebGLRenderer( { antialias: true } );
|
||||
renderer.setPixelRatio( Math.min( window.devicePixelRatio, 2 ) );
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
renderer.gammaFactor = 2.2;
|
||||
renderer.outputEncoding = THREE.sRGBEncoding;
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
renderer.toneMappingExposure = 1;
|
||||
renderer.physicallyCorrectLights
|
||||
document.body.appendChild( renderer.domElement );
|
||||
|
||||
window.addEventListener( 'resize', () => {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
} );
|
||||
|
||||
const controls = new OrbitControls( camera, renderer.domElement );
|
||||
controls.target.set( -4, 0, 0 );
|
||||
|
||||
@@ -321,14 +323,12 @@ let renderFlower = (size = 3, radius = 1) => {
|
||||
|
||||
renderFlower()
|
||||
|
||||
// const spotLight = new THREE.SpotLight( 0xffffff );
|
||||
const spotLight = new THREE.DirectionalLight( 0xeaa7a7, 1.5);
|
||||
// legacy lighting was removed in three r155: intensities need the old value times pi
|
||||
const spotLight = new THREE.DirectionalLight( 0xeaa7a7, 1.5 * Math.PI );
|
||||
spotLight.position.set( 10, 0, 0 );
|
||||
spotLight.castShadow = true;
|
||||
// spotLight.shadow.mapSize.width = 8182;
|
||||
// spotLight.shadow.mapSize.height = 8182;
|
||||
spotLight.shadow.mapSize.width = 4096;
|
||||
spotLight.shadow.mapSize.height = 4096;
|
||||
spotLight.shadow.mapSize.width = 2048;
|
||||
spotLight.shadow.mapSize.height = 2048;
|
||||
spotLight.shadow.camera.far = 21;
|
||||
spotLight.shadow.camera.left = -10;
|
||||
spotLight.shadow.camera.right = 10;
|
||||
|
||||
+278
-206
@@ -16,17 +16,24 @@ camera.position.z = 12;
|
||||
camera.position.x = 10;
|
||||
camera.position.y = 4;
|
||||
|
||||
const renderer = new THREE.WebGLRenderer();
|
||||
// debug switches to bisect driver issues: ?noaa disables MSAA, ?noshadow disables shadow maps
|
||||
const debugFlags = new URLSearchParams( window.location.search );
|
||||
|
||||
const renderer = new THREE.WebGLRenderer( { antialias: !debugFlags.has( 'noaa' ) } );
|
||||
renderer.setPixelRatio( Math.min( window.devicePixelRatio, 2 ) );
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.enabled = !debugFlags.has( 'noshadow' );
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
renderer.gammaFactor = 2.2;
|
||||
renderer.outputEncoding = THREE.sRGBEncoding;
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
renderer.toneMappingExposure = 1;
|
||||
renderer.physicallyCorrectLights
|
||||
document.body.appendChild( renderer.domElement );
|
||||
|
||||
window.addEventListener( 'resize', () => {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
} );
|
||||
|
||||
const controls = new OrbitControls( camera, renderer.domElement );
|
||||
controls.target.set( -4, 0, 0 );
|
||||
|
||||
@@ -170,12 +177,42 @@ function rotatePoint3D(px, py, pz, pitch, roll, yaw) {
|
||||
return [x, y, z]
|
||||
}
|
||||
|
||||
// WebGL draws lines at 1px regardless of linewidth, so the shape edges are built
|
||||
// from real cylinder tubes instead - same 0.03 thickness as the circle tori
|
||||
function makeEdgeTubes( geometry, color, tubeRadius = 0.03 ) {
|
||||
const edges = new THREE.EdgesGeometry( geometry );
|
||||
const positions = edges.attributes.position;
|
||||
const group = new THREE.Group();
|
||||
const material = new THREE.MeshBasicMaterial( { color } );
|
||||
const up = new THREE.Vector3( 0, 1, 0 );
|
||||
const start = new THREE.Vector3();
|
||||
const end = new THREE.Vector3();
|
||||
|
||||
for ( let i = 0; i < positions.count; i += 2 ) {
|
||||
start.fromBufferAttribute( positions, i );
|
||||
end.fromBufferAttribute( positions, i + 1 );
|
||||
const direction = new THREE.Vector3().subVectors( end, start );
|
||||
const length = direction.length();
|
||||
|
||||
const cylinder = new THREE.CylinderGeometry( tubeRadius, tubeRadius, length, 12 );
|
||||
cylinder.translate( 0, length / 2, 0 );
|
||||
|
||||
const tube = new THREE.Mesh( cylinder, material );
|
||||
tube.position.copy( start );
|
||||
tube.quaternion.setFromUnitVectors( up, direction.normalize() );
|
||||
tube.castShadow = true;
|
||||
group.add( tube );
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
const params = {
|
||||
xangle: 45,
|
||||
yangle: 0,
|
||||
zangle: 54.72972973,
|
||||
size: 5,
|
||||
radius: 1,
|
||||
tube: 0.03,
|
||||
};
|
||||
|
||||
// const params = {
|
||||
@@ -189,131 +226,160 @@ const params = {
|
||||
let sphere, circleCircum, cube, cubeLines;
|
||||
let spheres = [];
|
||||
let spheresLines = [];
|
||||
let gui;
|
||||
let solids = [];
|
||||
|
||||
let renderFlower = (size = 5, radius = 1) => {
|
||||
let renderFlower = (radius = 1) => {
|
||||
spheres = [];
|
||||
spheresLines = [];
|
||||
let x_count, y_count, z_count;
|
||||
|
||||
x_count = 1;
|
||||
for (let x of Array.from(Array(size), (_, i) => i * 0.612 * (radius * 2))) {
|
||||
y_count = 1;
|
||||
x = x - ((size - 1) * (0.612 * (radius * 2))) / 2
|
||||
// tear down the previous render's shapes and GUI so re-rendering never stacks duplicates
|
||||
if ( gui ) gui.destroy();
|
||||
for ( let obj of solids ) scene.remove( obj );
|
||||
solids = [];
|
||||
|
||||
// 3D fruit of life: a circle on the centre, on every cube corner and on
|
||||
// every cube edge midpoint (the inner ring of the 2D pattern)
|
||||
const d = 4 * 0.612 * radius;
|
||||
const points = [ [ 0, 0, 0 ] ];
|
||||
|
||||
for (let y of Array.from(Array(size), (_, i) => i * 0.612 * (radius * 2))) {
|
||||
z_count = 1;
|
||||
y = y - ((size - 1) * (0.612 * (radius * 2))) / 2
|
||||
|
||||
|
||||
for (let z of Array.from(Array(size), (_, i) => i * 0.612 * (radius * 2))) {
|
||||
z = z - ((size - 1) * (0.612 * (radius * 2))) / 2
|
||||
|
||||
|
||||
if (x_count % 2 == 0 || y_count % 2 == 0 || z_count % 2 == 0) {
|
||||
z_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (x_count % 5 == 0 && y_count % 3 == 0 ) {
|
||||
z_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (x_count % 5 == 0 && z_count % 3 == 0 ) {
|
||||
z_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (y_count % 5 == 0 && x_count % 3 == 0 ) {
|
||||
z_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (y_count % 5 == 0 && z_count % 3 == 0 ) {
|
||||
z_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (z_count % 5 == 0 && x_count % 3 == 0 ) {
|
||||
z_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (z_count % 5 == 0 && y_count % 3 == 0 ) {
|
||||
z_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
let xtemp, ytemp, ztemp;
|
||||
|
||||
[xtemp, ytemp, ztemp] = rotatePoint3D(x, y, z, params['yangle'], params['xangle'], params['zangle'])
|
||||
|
||||
let sphereGeometry = new THREE.SphereGeometry( radius, 64, 64 );
|
||||
let sphereMaterial = new THREE.MeshStandardMaterial( {
|
||||
color: 0x0063e4,
|
||||
metalness: 0.7,
|
||||
roughness: 0.3,
|
||||
opacity: 0.8,
|
||||
transparent: true
|
||||
} );
|
||||
sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
|
||||
sphere.position.x = xtemp;
|
||||
sphere.position.y = ytemp;
|
||||
sphere.position.z = ztemp;
|
||||
scene.add( sphere );
|
||||
|
||||
let circleGeometry = new THREE.TorusGeometry( radius, 0.03, 64, 64 );
|
||||
let circleMaterial = new THREE.MeshBasicMaterial( {
|
||||
color: 0x000000,
|
||||
opacity: 0.1,
|
||||
transparent: true
|
||||
} );
|
||||
circleCircum = new THREE.Mesh( circleGeometry, circleMaterial );
|
||||
circleCircum.castShadow = true;
|
||||
circleCircum.rotation.y = Math.PI / 2;
|
||||
circleCircum.position.x = xtemp;
|
||||
circleCircum.position.y = ytemp;
|
||||
circleCircum.position.z = ztemp;
|
||||
scene.add( circleCircum );
|
||||
|
||||
circleGeometry = new THREE.TorusGeometry( 0.01, 0.01, 64, 64 );
|
||||
circleMaterial = new THREE.MeshBasicMaterial( {
|
||||
color: 0x000000,
|
||||
opacity: 0.1,
|
||||
transparent: true
|
||||
} );
|
||||
circleCircum = new THREE.Mesh( circleGeometry, circleMaterial );
|
||||
circleCircum.castShadow = true;
|
||||
circleCircum.rotation.y = Math.PI / 2;
|
||||
circleCircum.position.x = xtemp;
|
||||
circleCircum.position.y = ytemp;
|
||||
circleCircum.position.z = ztemp;
|
||||
scene.add( circleCircum );
|
||||
|
||||
sphere.start_x = x;
|
||||
sphere.start_y = y;
|
||||
sphere.start_z = z;
|
||||
circleCircum.start_x = x;
|
||||
circleCircum.start_y = y;
|
||||
circleCircum.start_z = z;
|
||||
|
||||
spheres.push(sphere)
|
||||
spheresLines.push(circleCircum)
|
||||
|
||||
z_count++;
|
||||
for ( let sx of [ -1, 1 ] ) {
|
||||
for ( let sy of [ -1, 1 ] ) {
|
||||
for ( let sz of [ -1, 1 ] ) {
|
||||
points.push( [ sx * d, sy * d, sz * d ] );
|
||||
}
|
||||
y_count++;
|
||||
}
|
||||
x_count++;
|
||||
}
|
||||
|
||||
// only the edge midpoints whose coordinates share a sign: the other six sit on
|
||||
// the projection equator and would add circles between the two rings
|
||||
for ( let s of [ -1, 1 ] ) {
|
||||
points.push( [ s * d, s * d, 0 ] );
|
||||
points.push( [ s * d, 0, s * d ] );
|
||||
points.push( [ 0, s * d, s * d ] );
|
||||
}
|
||||
|
||||
// earth
|
||||
const boxGeometry = new THREE.BoxGeometry( 5 * radius, 5 * radius, 5 * radius );
|
||||
const addCircleAt = ( x, y, z, parent ) => {
|
||||
let xtemp, ytemp, ztemp;
|
||||
|
||||
[xtemp, ytemp, ztemp] = rotatePoint3D(x, y, z, params['yangle'], params['xangle'], params['zangle'])
|
||||
|
||||
let sphereGeometry = new THREE.SphereGeometry( radius, 64, 64 );
|
||||
let sphereMaterial = new THREE.MeshStandardMaterial( {
|
||||
color: 0x0063e4,
|
||||
metalness: 0.7,
|
||||
roughness: 0.3,
|
||||
opacity: 0.8,
|
||||
transparent: true
|
||||
} );
|
||||
sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
|
||||
sphere.position.x = xtemp;
|
||||
sphere.position.y = ytemp;
|
||||
sphere.position.z = ztemp;
|
||||
parent.add( sphere );
|
||||
|
||||
let circleGeometry = new THREE.TorusGeometry( radius, params['tube'], 64, 64 );
|
||||
let circleMaterial = new THREE.MeshBasicMaterial( {
|
||||
color: 0x000000,
|
||||
opacity: 0.1,
|
||||
transparent: true
|
||||
} );
|
||||
let ring = new THREE.Mesh( circleGeometry, circleMaterial );
|
||||
ring.castShadow = true;
|
||||
ring.rotation.y = Math.PI / 2;
|
||||
ring.position.x = xtemp;
|
||||
ring.position.y = ytemp;
|
||||
ring.position.z = ztemp;
|
||||
parent.add( ring );
|
||||
|
||||
circleGeometry = new THREE.TorusGeometry( 0.01, 0.01, 64, 64 );
|
||||
circleMaterial = new THREE.MeshBasicMaterial( {
|
||||
color: 0x000000,
|
||||
opacity: 0.1,
|
||||
transparent: true
|
||||
} );
|
||||
circleCircum = new THREE.Mesh( circleGeometry, circleMaterial );
|
||||
circleCircum.castShadow = true;
|
||||
circleCircum.rotation.y = Math.PI / 2;
|
||||
circleCircum.position.x = xtemp;
|
||||
circleCircum.position.y = ytemp;
|
||||
circleCircum.position.z = ztemp;
|
||||
parent.add( circleCircum );
|
||||
|
||||
sphere.start_x = x;
|
||||
sphere.start_y = y;
|
||||
sphere.start_z = z;
|
||||
ring.start_x = x;
|
||||
ring.start_y = y;
|
||||
ring.start_z = z;
|
||||
circleCircum.start_x = x;
|
||||
circleCircum.start_y = y;
|
||||
circleCircum.start_z = z;
|
||||
|
||||
spheres.push(sphere)
|
||||
spheresLines.push(ring)
|
||||
spheresLines.push(circleCircum)
|
||||
};
|
||||
|
||||
for ( let point of points ) {
|
||||
addCircleAt( ...point, scene );
|
||||
}
|
||||
|
||||
// the remaining cube circles: the six equatorial edge midpoints and the six
|
||||
// face centres, hidden behind the "allCubeCircles" toggle
|
||||
const extraCircles = new THREE.Group();
|
||||
extraCircles.visible = false;
|
||||
|
||||
for ( let s of [ -1, 1 ] ) {
|
||||
for ( let extraPoint of [
|
||||
[ s * d, -s * d, 0 ], [ s * d, 0, -s * d ], [ 0, s * d, -s * d ],
|
||||
[ s * d, 0, 0 ], [ 0, s * d, 0 ], [ 0, 0, s * d ],
|
||||
] ) {
|
||||
addCircleAt( ...extraPoint, extraCircles );
|
||||
}
|
||||
}
|
||||
|
||||
scene.add( extraCircles );
|
||||
|
||||
// Metatron's web: every circle centre connected to every other one
|
||||
let web = new THREE.Group();
|
||||
const webMaterial = new THREE.MeshBasicMaterial( { color: 0x000000, opacity: 0.5, transparent: true } );
|
||||
const webUp = new THREE.Vector3( 0, 1, 0 );
|
||||
|
||||
for ( let i = 0; i < points.length; i++ ) {
|
||||
for ( let j = i + 1; j < points.length; j++ ) {
|
||||
const [ ax, ay, az ] = rotatePoint3D( ...points[ i ], params[ 'yangle' ], params[ 'xangle' ], params[ 'zangle' ] );
|
||||
const [ bx, by, bz ] = rotatePoint3D( ...points[ j ], params[ 'yangle' ], params[ 'xangle' ], params[ 'zangle' ] );
|
||||
const a = new THREE.Vector3( ax, ay, az );
|
||||
const b = new THREE.Vector3( bx, by, bz );
|
||||
const direction = new THREE.Vector3().subVectors( b, a );
|
||||
const length = direction.length();
|
||||
|
||||
const webTube = params['tube'] * 0.4;
|
||||
const cylinder = new THREE.CylinderGeometry( webTube, webTube, length, 6 );
|
||||
cylinder.translate( 0, length / 2, 0 );
|
||||
|
||||
const strand = new THREE.Mesh( cylinder, webMaterial );
|
||||
strand.position.copy( a );
|
||||
strand.quaternion.setFromUnitVectors( webUp, direction.clone().normalize() );
|
||||
web.add( strand );
|
||||
}
|
||||
}
|
||||
|
||||
web.visible = false;
|
||||
scene.add( web );
|
||||
|
||||
// the exact rotation the circle grid uses, as a matrix - solids aligned with
|
||||
// this coincide with the dots instead of approximating them with tuned angles
|
||||
const gridRotation = new THREE.Matrix4().makeBasis(
|
||||
new THREE.Vector3( ...rotatePoint3D( 1, 0, 0, params['yangle'], params['xangle'], params['zangle'] ) ),
|
||||
new THREE.Vector3( ...rotatePoint3D( 0, 1, 0, params['yangle'], params['xangle'], params['zangle'] ) ),
|
||||
new THREE.Vector3( ...rotatePoint3D( 0, 0, 1, params['yangle'], params['xangle'], params['zangle'] ) )
|
||||
);
|
||||
|
||||
|
||||
// earth - width 2d puts every corner exactly on a corner dot
|
||||
const boxGeometry = new THREE.BoxGeometry( 2 * d, 2 * d, 2 * d );
|
||||
const boxMaterial = new THREE.MeshStandardMaterial( {
|
||||
color: 0x994f28,
|
||||
metalness: 0.7,
|
||||
@@ -323,22 +389,17 @@ let renderFlower = (size = 5, radius = 1) => {
|
||||
// wireframe: true,
|
||||
} );
|
||||
cube = new THREE.Mesh( boxGeometry, boxMaterial );
|
||||
cube.rotation.x = 30 * (Math.PI / 180)
|
||||
cube.rotation.y = 144.75 * (Math.PI / 180)
|
||||
cube.rotation.z = 45 * (Math.PI / 180)
|
||||
cube.setRotationFromMatrix( gridRotation );
|
||||
|
||||
let cubeEdges = new THREE.EdgesGeometry( boxGeometry );
|
||||
cubeLines = new THREE.LineSegments( cubeEdges, new THREE.LineBasicMaterial( { color: 0x1b0a02, linewidth: 50000 } ) );
|
||||
cubeLines.rotation.x = 30 * (Math.PI / 180)
|
||||
cubeLines.rotation.y = 144.8 * (Math.PI / 180)
|
||||
cubeLines.rotation.z = 45 * (Math.PI / 180)
|
||||
cubeLines = makeEdgeTubes( boxGeometry, 0x1b0a02, params['tube'] );
|
||||
cubeLines.setRotationFromMatrix( gridRotation );
|
||||
cubeLines.castShadow = true;
|
||||
|
||||
scene.add( cubeLines );
|
||||
scene.add( cube );
|
||||
|
||||
// fire
|
||||
const tetraGeometry = new THREE.TetrahedronGeometry( (5 - 2 / 3) * radius )
|
||||
// fire - radius sqrt(3)d puts every vertex exactly on a corner dot
|
||||
const tetraGeometry = new THREE.TetrahedronGeometry( Math.sqrt( 3 ) * d )
|
||||
const tetraMaterial = new THREE.MeshStandardMaterial( {
|
||||
color: 0xdb1212,
|
||||
metalness: 0.7,
|
||||
@@ -348,24 +409,32 @@ let renderFlower = (size = 5, radius = 1) => {
|
||||
} );
|
||||
let tetra = new THREE.Mesh( tetraGeometry, tetraMaterial );
|
||||
|
||||
let tetraEdges = new THREE.EdgesGeometry( tetraGeometry );
|
||||
let tetraLines = new THREE.LineSegments( tetraEdges, new THREE.LineBasicMaterial( { color: 0x140101, linewidth: 50000 } ) );
|
||||
let tetraLines = makeEdgeTubes( tetraGeometry, 0x140101, params['tube'] );
|
||||
|
||||
|
||||
|
||||
tetraLines.rotation.x = 90 * (Math.PI / 180)
|
||||
tetraLines.rotation.y = 35.26530612 * (Math.PI / 180)
|
||||
tetraLines.rotation.z = 45 * (Math.PI / 180)
|
||||
|
||||
tetra.rotation.x = 90 * (Math.PI / 180)
|
||||
tetra.rotation.y = 35.26530612 * (Math.PI / 180)
|
||||
tetra.rotation.z = 45 * (Math.PI / 180)
|
||||
tetraLines.setRotationFromMatrix( gridRotation );
|
||||
tetra.setRotationFromMatrix( gridRotation );
|
||||
tetraLines.castShadow = true;
|
||||
|
||||
scene.add( tetraLines );
|
||||
scene.add( tetra );
|
||||
|
||||
const octaGeometry = new THREE.OctahedronGeometry( 5 * radius )
|
||||
// second tetrahedron of the star tetrahedron (Merkaba): the same shape
|
||||
// rotated a quarter turn so it interlocks with the first
|
||||
const tetraGeometry2 = new THREE.TetrahedronGeometry( Math.sqrt( 3 ) * d );
|
||||
tetraGeometry2.rotateZ( Math.PI / 2 );
|
||||
let tetra2 = new THREE.Mesh( tetraGeometry2, tetraMaterial );
|
||||
let tetraLines2 = makeEdgeTubes( tetraGeometry2, 0x140101, params['tube'] );
|
||||
|
||||
tetra2.rotation.copy( tetra.rotation );
|
||||
tetraLines2.rotation.copy( tetraLines.rotation );
|
||||
|
||||
scene.add( tetraLines2 );
|
||||
scene.add( tetra2 );
|
||||
|
||||
// radius 2d puts the projected corners exactly on the outer circle centres
|
||||
const octaGeometry = new THREE.OctahedronGeometry( 2 * d )
|
||||
const octaMaterial = new THREE.MeshStandardMaterial( {
|
||||
color: 0x9dedf6,
|
||||
metalness: 0.7,
|
||||
@@ -375,22 +444,17 @@ let renderFlower = (size = 5, radius = 1) => {
|
||||
} );
|
||||
let octa = new THREE.Mesh( octaGeometry, octaMaterial );
|
||||
|
||||
let octaEdges = new THREE.EdgesGeometry( octaGeometry );
|
||||
let octaLines = new THREE.LineSegments( octaEdges, new THREE.LineBasicMaterial( { color: 0x0a2528, linewidth: 50000 } ) );
|
||||
let octaLines = makeEdgeTubes( octaGeometry, 0x0a2528, params['tube'] );
|
||||
|
||||
octaLines.rotation.x = 90 * (Math.PI / 180)
|
||||
octaLines.rotation.y = 35.26530612 * (Math.PI / 180)
|
||||
octaLines.rotation.z = 45 * (Math.PI / 180)
|
||||
|
||||
octa.rotation.x = 90 * (Math.PI / 180)
|
||||
octa.rotation.y = 35.26530612 * (Math.PI / 180)
|
||||
octa.rotation.z = 45 * (Math.PI / 180)
|
||||
octaLines.setRotationFromMatrix( gridRotation );
|
||||
octa.setRotationFromMatrix( gridRotation );
|
||||
octaLines.castShadow = true;
|
||||
|
||||
scene.add( octaLines );
|
||||
scene.add( octa );
|
||||
|
||||
const icosaGeometry = new THREE.IcosahedronGeometry( (3 + 1 / 3 + 0.028) * radius )
|
||||
// radius 1.663d puts the projected corners on the outer circle centres
|
||||
const icosaGeometry = new THREE.IcosahedronGeometry( 1.663 * d )
|
||||
const icosaMaterial = new THREE.MeshStandardMaterial( {
|
||||
color: 0x0063e4,
|
||||
metalness: 0.7,
|
||||
@@ -400,25 +464,26 @@ let renderFlower = (size = 5, radius = 1) => {
|
||||
} );
|
||||
let icosa = new THREE.Mesh( icosaGeometry, icosaMaterial );
|
||||
|
||||
let icosaEdges = new THREE.EdgesGeometry( icosaGeometry );
|
||||
let icosaLines = new THREE.LineSegments( icosaEdges, new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 50000 } ) );
|
||||
let icosaLines = makeEdgeTubes( icosaGeometry, 0x000000, params['tube'] );
|
||||
|
||||
icosaLines.rotation.x = 30 * (Math.PI / 180)
|
||||
icosaLines.rotation.y = 159.1 * (Math.PI / 180)
|
||||
icosaLines.rotation.z = 90 * (Math.PI / 180)
|
||||
// a grid-aligned icosahedron projects its corners 22.2 degrees off the dot
|
||||
// hexagon, so it gets an extra twist about the view diagonal to meet the dots
|
||||
const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
|
||||
const icosaTwist = Math.PI / 6 - Math.atan( ( PHI + 2 ) / ( Math.sqrt( 3 ) * PHI ) );
|
||||
const icosaRotation = new THREE.Matrix4().multiplyMatrices(
|
||||
gridRotation,
|
||||
new THREE.Matrix4().makeRotationAxis( new THREE.Vector3( 1, 1, 1 ).normalize(), icosaTwist )
|
||||
);
|
||||
|
||||
icosa.rotation.x = 30 * (Math.PI / 180)
|
||||
icosa.rotation.y = 159.1 * (Math.PI / 180)
|
||||
icosa.rotation.z = 90 * (Math.PI / 180)
|
||||
icosaLines.setRotationFromMatrix( icosaRotation );
|
||||
icosa.setRotationFromMatrix( icosaRotation );
|
||||
icosaLines.castShadow = true;
|
||||
|
||||
scene.add( icosaLines );
|
||||
scene.add( icosa );
|
||||
|
||||
icosa.visible = false;
|
||||
icosaLines.visible = false;
|
||||
|
||||
const dodecaGeometry = new THREE.DodecahedronGeometry( (2 + 1 / 3 + 0.005) * radius )
|
||||
// 2.29 * 1.003: tuned against the circle pattern
|
||||
const dodecaGeometry = new THREE.DodecahedronGeometry( 2.297 * radius )
|
||||
const dodecaMaterial = new THREE.MeshStandardMaterial( {
|
||||
color: 0x0063e4,
|
||||
metalness: 0.7,
|
||||
@@ -428,42 +493,42 @@ let renderFlower = (size = 5, radius = 1) => {
|
||||
} );
|
||||
let dodeca = new THREE.Mesh( dodecaGeometry, dodecaMaterial );
|
||||
|
||||
let dodecaEdges = new THREE.EdgesGeometry( dodecaGeometry );
|
||||
let dodecaLines = new THREE.LineSegments( dodecaEdges, new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 50000 } ) );
|
||||
let dodecaLines = makeEdgeTubes( dodecaGeometry, 0x000000, params['tube'] );
|
||||
|
||||
dodecaLines.rotation.x = 90 * (Math.PI / 180)
|
||||
dodecaLines.rotation.y = 111 * (Math.PI / 180)
|
||||
dodecaLines.rotation.z = 90 * (Math.PI / 180)
|
||||
|
||||
dodeca.rotation.x = 90 * (Math.PI / 180)
|
||||
dodeca.rotation.y = 111 * (Math.PI / 180)
|
||||
dodeca.rotation.z = 90 * (Math.PI / 180)
|
||||
// aether: a dodecahedron vertex sits on the cube diagonal, so the plain grid
|
||||
// rotation points a vertex straight at the light and shares the cube's frame,
|
||||
// with a tuned x-angle on top
|
||||
dodecaLines.setRotationFromMatrix( gridRotation );
|
||||
dodeca.setRotationFromMatrix( gridRotation );
|
||||
dodecaLines.rotation.x = 52.25 * (Math.PI / 180);
|
||||
dodeca.rotation.x = 52.25 * (Math.PI / 180);
|
||||
dodecaLines.castShadow = true;
|
||||
|
||||
scene.add( dodecaLines );
|
||||
scene.add( dodeca );
|
||||
|
||||
|
||||
// Big circle
|
||||
let circleGeometry = new THREE.TorusGeometry( 5 * radius, 0.02, 64, 64);
|
||||
let circleMaterial = new THREE.MeshBasicMaterial( {
|
||||
color: 0x000000,
|
||||
opacity: 0,
|
||||
transparent: true
|
||||
} );
|
||||
// Big circle: visible as a solid tube, same thickness as the shape edges
|
||||
let circleGeometry = new THREE.TorusGeometry( 5 * radius, params['tube'], 64, 64);
|
||||
let circleMaterial = new THREE.MeshBasicMaterial( { color: 0x000000 } );
|
||||
circleCircum = new THREE.Mesh( circleGeometry, circleMaterial );
|
||||
circleCircum.rotation.y = Math.PI / 2;
|
||||
circleCircum.castShadow = true;
|
||||
scene.add( circleCircum );
|
||||
|
||||
solids.push( cube, cubeLines, tetra, tetraLines, tetra2, tetraLines2, octa, octaLines, icosa, icosaLines, dodeca, dodecaLines, circleCircum, web, extraCircles );
|
||||
|
||||
const gui = new GUI();
|
||||
|
||||
gui = new GUI();
|
||||
|
||||
let guiDict = {};
|
||||
|
||||
let fire = gui.addFolder('Fire');
|
||||
guiDict['fire'] = {'folder': fire, 'object': tetra, 'objectLines': tetraLines};
|
||||
|
||||
let fire2 = gui.addFolder('Fire 2');
|
||||
guiDict['fire2'] = {'folder': fire2, 'object': tetra2, 'objectLines': tetraLines2};
|
||||
|
||||
let air = gui.addFolder('Air');
|
||||
guiDict['air'] = {'folder': air, 'object': octa, 'objectLines': octaLines};
|
||||
|
||||
@@ -479,6 +544,14 @@ let renderFlower = (size = 5, radius = 1) => {
|
||||
let circles = gui.addFolder('Circles')
|
||||
guiDict['circles'] = {'folder': circles};
|
||||
|
||||
circles.add( { web: false }, 'web' ).onChange( ( value ) => {
|
||||
web.visible = value;
|
||||
} );
|
||||
|
||||
circles.add( { allCubeCircles: false }, 'allCubeCircles' ).onChange( ( value ) => {
|
||||
extraCircles.visible = value;
|
||||
} );
|
||||
|
||||
let folderStandard = {
|
||||
show: true,
|
||||
fill: true,
|
||||
@@ -514,11 +587,7 @@ let renderFlower = (size = 5, radius = 1) => {
|
||||
if (fld === "circles") {
|
||||
continue
|
||||
}
|
||||
if (fld === "water") {
|
||||
folderStandard.show = false;
|
||||
} else {
|
||||
folderStandard.show = true;
|
||||
}
|
||||
folderStandard.show = true;
|
||||
|
||||
folderStandard.xAngle = guiDict[fld]['object'].rotation.x / (Math.PI / 180);
|
||||
folderStandard.yAngle = guiDict[fld]['object'].rotation.y / (Math.PI / 180);
|
||||
@@ -597,18 +666,6 @@ let renderFlower = (size = 5, radius = 1) => {
|
||||
[sphereLine.position.x, sphereLine.position.y, sphereLine.position.z] = rotatePoint3D(sphereLine.start_x, sphereLine.start_y, sphereLine.start_z, params['yangle'], params['xangle'], value)
|
||||
}
|
||||
});
|
||||
gui.add( params, 'size', 2, 5).step(1).onChange( (value) => {
|
||||
for (let sphere of spheres) {
|
||||
scene.remove(sphere)
|
||||
}
|
||||
for (let sphereLine of spheresLines) {
|
||||
scene.remove(sphereLine)
|
||||
}
|
||||
scene.remove(cube)
|
||||
scene.remove(cubeLines)
|
||||
scene.remove(circleCircum)
|
||||
renderFlower (value, params['radius'])
|
||||
});
|
||||
gui.add( params, 'radius', 0.5, 1.5).onChange( (value) => {
|
||||
for (let sphere of spheres) {
|
||||
scene.remove(sphere)
|
||||
@@ -616,25 +673,40 @@ let renderFlower = (size = 5, radius = 1) => {
|
||||
for (let sphereLine of spheresLines) {
|
||||
scene.remove(sphereLine)
|
||||
}
|
||||
scene.remove(cube)
|
||||
scene.remove(cubeLines)
|
||||
scene.remove(circleCircum)
|
||||
renderFlower (params['size'], value)
|
||||
renderFlower (value)
|
||||
});
|
||||
gui.add( params, 'tube', 0.01, 0.1 ).step( 0.005 ).onChange( () => {
|
||||
for (let sphere of spheres) {
|
||||
scene.remove(sphere)
|
||||
}
|
||||
for (let sphereLine of spheresLines) {
|
||||
scene.remove(sphereLine)
|
||||
}
|
||||
renderFlower (params['radius'])
|
||||
});
|
||||
|
||||
// ?only=<fire|fire2|air|earth|water|aether> hides the other solids, for
|
||||
// checking a single shape against the reference
|
||||
const only = debugFlags.get( 'only' );
|
||||
if ( only && guiDict[ only ] ) {
|
||||
for ( let fld of Object.keys( guiDict ) ) {
|
||||
if ( fld === only || ! guiDict[ fld ][ 'object' ] ) continue;
|
||||
guiDict[ fld ][ 'object' ].visible = false;
|
||||
guiDict[ fld ][ 'objectLines' ].visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
gui.close();
|
||||
}
|
||||
|
||||
renderFlower()
|
||||
|
||||
// const spotLight = new THREE.SpotLight( 0xffffff );
|
||||
const spotLight = new THREE.DirectionalLight( 0xeaa7a7, 1.5);
|
||||
// legacy lighting was removed in three r155: intensities need the old value times pi
|
||||
const spotLight = new THREE.DirectionalLight( 0xeaa7a7, 1.5 * Math.PI );
|
||||
spotLight.position.set( 10, 0, 0 );
|
||||
spotLight.castShadow = true;
|
||||
spotLight.shadow.mapSize.width = 8182;
|
||||
spotLight.shadow.mapSize.height = 8182;
|
||||
// spotLight.shadow.mapSize.width = 4096;
|
||||
// spotLight.shadow.mapSize.height = 4096;
|
||||
spotLight.shadow.mapSize.width = 2048;
|
||||
spotLight.shadow.mapSize.height = 2048;
|
||||
spotLight.shadow.camera.far = 21;
|
||||
spotLight.shadow.camera.left = -10;
|
||||
spotLight.shadow.camera.right = 10;
|
||||
|
||||
+12
-12
@@ -18,19 +18,21 @@ camera.position.x = 10;
|
||||
camera.position.y = 4;
|
||||
|
||||
|
||||
const renderer = new THREE.WebGLRenderer();
|
||||
const renderer = new THREE.WebGLRenderer( { antialias: true } );
|
||||
renderer.setPixelRatio( Math.min( window.devicePixelRatio, 2 ) );
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
renderer.gammaFactor = 2.2;
|
||||
renderer.outputEncoding = THREE.sRGBEncoding;
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
renderer.toneMappingExposure = 1;
|
||||
renderer.physicallyCorrectLights
|
||||
document.body.appendChild( renderer.domElement );
|
||||
|
||||
window.addEventListener( 'resize', () => {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
} );
|
||||
|
||||
const controls = new OrbitControls( camera, renderer.domElement );
|
||||
controls.target.set( -4, 0, 0 );
|
||||
|
||||
@@ -322,14 +324,12 @@ for (let x_angle of Array.from(Array(4), (_, i) => 360 / 4 * i)) {
|
||||
}
|
||||
}
|
||||
|
||||
// const spotLight = new THREE.SpotLight( 0xffffff );
|
||||
const spotLight = new THREE.DirectionalLight( 0xeaa7a7, 1.5);
|
||||
// legacy lighting was removed in three r155: intensities need the old value times pi
|
||||
const spotLight = new THREE.DirectionalLight( 0xeaa7a7, 1.5 * Math.PI );
|
||||
spotLight.position.set( 10, 0, 0 );
|
||||
spotLight.castShadow = true;
|
||||
// spotLight.shadow.mapSize.width = 8182;
|
||||
// spotLight.shadow.mapSize.height = 8182;
|
||||
spotLight.shadow.mapSize.width = 4096;
|
||||
spotLight.shadow.mapSize.height = 4096;
|
||||
spotLight.shadow.mapSize.width = 2048;
|
||||
spotLight.shadow.mapSize.height = 2048;
|
||||
spotLight.shadow.camera.far = 21;
|
||||
spotLight.shadow.camera.left = -10;
|
||||
spotLight.shadow.camera.right = 10;
|
||||
|
||||
+3
-16
@@ -31,24 +31,11 @@ module.exports = (env) => {
|
||||
"sass-loader",
|
||||
],
|
||||
},
|
||||
// {
|
||||
// test: /\.m?js$/,
|
||||
// exclude: /node_modules/,
|
||||
// use: {
|
||||
// loader: 'babel-loader',
|
||||
// options: {
|
||||
// presets: [
|
||||
// ['@babel/preset-env', { targets: { chrome: "58", ie: "11" }}]
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// For newer versions of Webpack it should be
|
||||
{
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'public/icons/[name].[ext]'
|
||||
type: 'asset/resource',
|
||||
generator: {
|
||||
filename: 'public/icons/[name][ext]'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user