{
const canvas = document.querySelector("canvas.webgl");
const parameters = {};
parameters.width = width;
parameters.height = 1000;
parameters.count = 200000;
parameters.size = 0.005;
parameters.radius = 5;
parameters.branches = 3;
parameters.spin = 1;
parameters.randomness = 0.2;
parameters.randomnessPower = 3;
parameters.insideColor = "#ff6030";
parameters.outsideColor = "#1b3984";
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({
canvas: canvas
});
renderer.setSize(parameters.width, parameters.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
let geometry = null;
let material = null;
let points = null;
const generateGalaxy = () => {
if (points !== null) {
geometry.dispose();
material.dispose();
scene.remove(points);
}
geometry = new THREE.BufferGeometry();
const positions = new Float32Array(parameters.count * 3);
const randomness = new Float32Array(parameters.count * 3);
const colors = new Float32Array(parameters.count * 3);
const scales = new Float32Array(parameters.count * 1);
const insideColor = new THREE.Color(parameters.insideColor);
const outsideColor = new THREE.Color(parameters.outsideColor);
for (let i = 0; i < parameters.count; i++) {
const i3 = i * 3;
// Position
const radius = Math.random() * parameters.radius;
const branchAngle =
((i % parameters.branches) / parameters.branches) * Math.PI * 2;
const gRandom = () => {
return (
Math.pow(Math.random(), parameters.randomnessPower) *
(Math.random() < 0.5 ? 1 : -1) *
parameters.randomness *
radius
);
};
const randomX = gRandom();
const randomY = gRandom();
const randomZ = gRandom();
positions[i3] = Math.cos(branchAngle) * radius;
positions[i3 + 1] = 0;
positions[i3 + 2] = Math.sin(branchAngle) * radius;
randomness[i3] = randomX;
randomness[i3 + 1] = randomY;
randomness[i3 + 2] = randomZ;
// Color
const mixedColor = insideColor.clone();
mixedColor.lerp(outsideColor, radius / parameters.radius);
colors[i3] = mixedColor.r;
colors[i3 + 1] = mixedColor.g;
colors[i3 + 2] = mixedColor.b;
// Scale
scales[i] = Math.random();
}
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
geometry.setAttribute(
"aRandomness",
new THREE.BufferAttribute(randomness, 3)
);
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
geometry.setAttribute("aScale", new THREE.BufferAttribute(scales, 1));
material = new THREE.ShaderMaterial({
depthWrite: false,
blending: THREE.AdditiveBlending,
vertexColors: true,
uniforms: {
uTime: { value: 0 },
uSize: { value: 30 * renderer.getPixelRatio() }
},
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
points = new THREE.Points(geometry, material);
scene.add(points);
};
// Base camera
const camera = new THREE.PerspectiveCamera(
75,
parameters.width / parameters.height,
0.1,
100
);
camera.position.x = 3;
camera.position.y = 3;
camera.position.z = 3;
scene.add(camera);
// Controls
const controls = new THREE.OrbitControls(camera, canvas);
controls.enableDamping = true;
controls.autoRotate = true;
/**
* Generate the first galaxy
*/
generateGalaxy();
/**
* Animate
*/
const clock = new THREE.Clock();
const tick = () => {
const elapsedTime = clock.getElapsedTime();
// Update material
material.uniforms.uTime.value = elapsedTime;
// Update controls
controls.update();
// Render
renderer.render(scene, camera);
// Call tick again on the next frame
window.requestAnimationFrame(tick);
};
tick();
return html``;
}