body {
overflow: hidden;
margin: 0;
}
#info {
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display: block;
color: white;
font-family: 'Courier New', monospace;
s
}
#lil-gui {
left: 10px;
top: 70px;
}
<div id="info">3d pi estimator <br> dots in sphere: 0 • dots outside sphere: • pi estimate: </div>
<script type="module">
import * as THREE from 'https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b6c2dec4d3d3f6c086988785809886">[email protected]</a>';
import { OrbitControls } from 'https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e99d819b8c8ca99fd9c7d8dadfc7d9">[email protected]</a>/examples/jsm/controls/OrbitControls.js';
import { GUI } from "https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="72061a00171732425c4341445c42">[email protected]</a>/examples/jsm/libs/lil-gui.module.min.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
const controls = new OrbitControls( camera, renderer.domElement );
controls.autoRotate = true;
camera.position.z = 30;
camera.position.y = 15;
controls.update();
const geometry_cube = new THREE.BoxGeometry( 20, 20, 20 );
const edges_cube = new THREE.EdgesGeometry( geometry_cube );
const cube = new THREE.LineSegments( edges_cube, new THREE.LineBasicMaterial( { color: 0xffffff } ) );
scene.add( cube );
const geometry_sphere = new THREE.SphereGeometry( 10, 32, 16 );
const material_sphere = new THREE.MeshBasicMaterial( { color: 0xffffff } );
const sphere = new THREE.Mesh( geometry_sphere, material_sphere );
sphere.material.transparent = true;
sphere.material.opacity = 0.5;
scene.add( sphere );
let num_points = 30000;
let in_sphere = 0;
let out_sphere = 0;
let geometry_point = new THREE.SphereGeometry( 0.1, 3, 2 );
let colorController = {
color1: "#ffffff",
color2: "#42c5f5"
};
let uniforms = {
color1: {value: new THREE.Color(colorController.color1)},
color2: {value: new THREE.Color(colorController.color2)}
};
let material_point = new THREE.MeshBasicMaterial( {
color: 0xffffff,
onBeforeCompile: shader => {
shader.uniforms.color1 = uniforms.color1;
shader.uniforms.color2 = uniforms.color2;
shader.vertexShader = `
attribute float colorIdx;
varying float vColorIdx;
${shader.vertexShader}
`.replace(
`#include <begin_vertex>`,
`#include <begin_vertex>
vColorIdx = colorIdx;
`
);
//console.log(shader.vertexShader);
shader.fragmentShader = `
uniform vec3 color1;
uniform vec3 color2;
varying float vColorIdx;
${shader.fragmentShader}
`.replace(
`vec4 diffuseColor = vec4( diffuse, opacity );`,
`
vec3 finalColor = mix(color1, color2, vColorIdx);
finalColor *= diffuse;
vec4 diffuseColor = vec4( finalColor, opacity );
`
);
//console.log(shader.fragmentShader);
}
} );
let point = new THREE.InstancedMesh( geometry_point, material_point, num_points );
let dummy = new THREE.Object3D();
let colorIdx = [];
for (let i = 0; i < num_points; i++) {
dummy.position.random().subScalar(0.5).multiplyScalar(20);
dummy.updateMatrix();
point.setMatrixAt(i, dummy.matrix);
if (dummy.position.length() <= 10) {
colorIdx.push(1);
in_sphere++;
}
else {
colorIdx.push(0);
out_sphere++;
}
}
geometry_point.setAttribute("colorIdx", new THREE.InstancedBufferAttribute(new Float32Array(colorIdx), 1));
scene.add(point);
let gui = new GUI({autoplace:false});
gui.domElement.id = "lil-gui"
gui.addColor(colorController, "color1").onChange(val => {uniforms.color1.value.set(val)});
gui.addColor(colorController, "color2").onChange(val => {uniforms.color2.value.set(val)});
document.getElementById("info").innerHTML = "3d pi estimator <br>" + "dots in sphere: " + in_sphere + " • dots outside sphere: " + out_sphere + " • pi estimate: " + ((6 * in_sphere) / (in_sphere + out_sphere));
function animate() {
requestAnimationFrame( animate );
controls.update(); // Required because of auto-rotation
renderer.render( scene, camera );
};
animate();
</script>