FDNavigate back to the homepage

Harnessing the Elements - Sun, Noise, and Bloom in Layered Mesh Design

Rick
September 11th, 2024 · 1 min read

I have always wanted to create a sun like mesh and this is a small showcase of it.

The design is spheres scaled inside each other.

Avoiding artifacts which doublesided spheres have.

And creating a sun like object in 3D space.

Giph of sun

Here is the code:

1import { ImprovedNoise } from 'three/examples/jsm/math/ImprovedNoise';
2import React, { useState, useEffect, useMemo } from 'react';
3import { Canvas, useFrame } from '@react-three/fiber';
4import { OrbitControls } from '@react-three/drei';
5import * as THREE from 'three';
6import { EffectComposer, Bloom } from '@react-three/postprocessing';
7import { KernelSize } from 'postprocessing'
8
9const generate3DNoiseTexture = (width, height, depth) => {
10 const size = width * height * depth;
11 const data = new Float32Array(size);
12 const noise = new ImprovedNoise();
13 const scale = 10;
14
15 for (let z = 0; z < depth; z++) {
16 for (let y = 0; y < height; y++) {
17 for (let x = 0; x < width; x++) {
18 const nx = x / width;
19 const ny = y / height;
20 const nz = z / depth;
21 data[x + width * (y + height * z)] = (noise.noise(nx * scale, ny * scale, nz * scale) + 1) * 0.5;
22 }
23 }
24 }
25
26 const texture = new THREE.Data3DTexture(data, width, height, depth);
27 texture.minFilter = THREE.NearestMipMapLinearFilter;
28 texture.magFilter = THREE.NearestMipMapLinearFilter;
29 texture.format = THREE.RedFormat;
30 texture.type = THREE.FloatType;
31 texture.needsUpdate = true;
32 texture.wrapR = texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
33
34 return texture;
35};
36
37const NoiseMaterial = ({ noiseTexture, front, alpha }) => {
38 const [time, setTime] = useState(0);
39 useFrame(({ clock }) => setTime(clock.getElapsedTime()));
40
41 const vertexShader = `
42 varying vec3 vPosition;
43 void main() {
44 vPosition = position;
45 vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
46 gl_Position = projectionMatrix * mvPosition;
47 }
48 `;
49
50 const fragmentShader = `
51 varying vec3 vPosition;
52 uniform sampler3D noiseTexture;
53 uniform float alpha;
54 uniform float time;
55
56 void main() {
57 vec3 vPos = vPosition;
58 vPos.xyz += time * 0.3;
59 vPos.xyz = (vPos.xyz + time * 0.3 + 1.0) * (0.5 + time * 0.8);
60 vPos = vec3(vPos);
61 vec3 noise = texture(noiseTexture, vPos ).rgb;
62 float stepper = step(alpha / 0.3, noise.r);
63 gl_FragColor = vec4(0.0, 0.0, mix(stepper * 6.0 * 2.0 - alpha, 0.0, alpha), mix(0.0, stepper, noise.r / 0.7));
64 }
65 `;
66
67 return (
68 <shaderMaterial
69 attach="material"
70 transparent={true}
71 alphaToCoverage
72 sizeAttenuation={false}
73 depthTest={true}
74 depthWrite={true}
75 side={front ? THREE.FrontSide : THREE.BackSide}
76 args={[{
77 vertexShader,
78 fragmentShader,
79 uniforms: {
80 noiseTexture: { value: noiseTexture },
81 alpha: { value: alpha },
82 time: { value: time }
83 } }]}
84 uniforms-noiseTexture-value={noiseTexture}
85 uniforms-alpha-value={alpha / 10 - 0.1}
86 uniforms-time-value={time * 1.0 / alpha / 50.0}
87 />
88 );
89};
90
91const LayeredSpheres = ({ radius, noiseTexture, layers }) => {
92 const layerOffset = 0.01;
93
94 return (
95 <>
96 {[...Array(layers)].map((_, i) => {
97 const currentRadius = radius - i / layers * layerOffset;
98 if (currentRadius <= 0) return null; // Prevent spheres with non-positive radius
99
100 return (
101 <React.Fragment key={i}>
102 <mesh>
103 <sphereGeometry args={[currentRadius, 64, 64]} />
104 <NoiseMaterial noiseTexture={noiseTexture} front={false} alpha={i} /> {/* Outer Sphere */}
105 </mesh>
106 <mesh>
107 <sphereGeometry args={[currentRadius - layerOffset / 2, 64, 64]} />
108 <NoiseMaterial noiseTexture={noiseTexture} front={true} alpha={i} /> {/* Inner Sphere */}
109 </mesh>
110 </React.Fragment>
111 );
112 })}
113 </>
114 );
115};
116
117const LightingAndControls = () => (
118 <>
119 <ambientLight />
120 <pointLight position={[10, 10, 10]} />
121 <OrbitControls />
122 </>
123);
124
125const BloomEffect = () => (
126 <EffectComposer multisampling={8}>
127 <Bloom kernelSize={1} luminanceThreshold={0} luminanceSmoothing={0.9} intensity={0.6} />
128 <Bloom kernelSize={KernelSize.HUGE} luminanceThreshold={0} luminanceSmoothing={0} intensity={.05} />
129 </EffectComposer>
130);
131
132const StarField = ({ count = 5000, radius = 100 }) => {
133 const starsGeometry = useMemo(() => {
134 const positions = new Float32Array(count * 3);
135 for (let i = 0; i < count; i++) {
136 const theta = THREE.MathUtils.randFloatSpread(360);
137 const phi = THREE.MathUtils.randFloatSpread(360);
138
139 const distance = THREE.MathUtils.randFloatSpread(radius);
140
141 const x = distance * Math.cos(theta) * Math.sin(phi);
142 const y = distance * Math.sin(theta) * Math.sin(phi);
143 const z = distance * Math.cos(phi);
144
145 positions.set([x, y, z], i * 3);
146 }
147
148 const geometry = new THREE.BufferGeometry();
149 geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
150
151 return geometry;
152 }, [count, radius]);
153
154 return (
155 <points geometry={starsGeometry}>
156 <pointsMaterial size={0.001} color="white" />
157 </points>
158 );
159};
160
161const AppCanvas = ({ children }) => (
162 <Canvas style={{ height: '100vh', width: '100vw' }}>
163 <color attach="background" args={['black']} />
164 {children}
165 </Canvas>
166);
167
168const App = () => {
169 const [noiseTexture, setNoiseTexture] = useState(null);
170
171 useEffect(() => {
172 setNoiseTexture(generate3DNoiseTexture(256, 256, 256));
173 }, []);
174
175 if (!noiseTexture) return null;
176
177 return (
178 <AppCanvas>
179 <LayeredSpheres radius={1} noiseTexture={noiseTexture} layers={60} />
180 <LightingAndControls />
181 <BloomEffect />
182 <StarField />
183 <mesh>
184 <sphereGeometry args={[0.99, 64, 64]} />
185 <meshBasicMaterial color={'#FAF9F6'} emissionIntensity={1.0}/>
186 </mesh>
187 </AppCanvas>
188 );
189};
190
191export default App;

More articles from theFrontDev

Dynamic FlowMap Curve Modifier for Procedural River Generation

The dynamic FlowMap Curve Modifier is an innovative research and development tool for creating fluid, adaptive river terrains. It combines curve modification with integrated flow mapping to generate evolving watercourses, offering new possibilities for procedural landscape generation in 3D environments and interactive applications.

September 10th, 2024 · 1 min read

Centroids - Precursor to Normal Calculation in Point Clouds

This project involves dividing a bounding box into equal sections to compute and visualize 3D centroids of points within each section. It serves as a precursor to calculating local normals for point clouds. The visualization includes section boundaries, centroid spheres, and normal vectors to aid in understanding point distributions and orientations.

September 7th, 2024 · 1 min read
© 2021–2024 theFrontDev
Link to $https://twitter.com/TheFrontDevLink to $https://github.com/Richard-ThompsonLink to $https://www.linkedin.com/in/richard-thompson-248ba3111/