Atmosphere constructor
Atmosphere({
- AtmosphereParameters? atmosphereParams,
- Texture? cloudTexture,
- int renderOrder = 2,
Implementation
factory Atmosphere({AtmosphereParameters? atmosphereParams, Texture? cloudTexture, int renderOrder = 2}){
atmosphereParams ??= AtmosphereParameters();
final material = ShaderMaterial.fromMap({
'uniforms': {
'time': { 'value': 0.0 },
'pointTexture': { 'value': cloudTexture },
'radius': { 'value': atmosphereParams.radius },
'thickness': { 'value': atmosphereParams.thickness },
...atmosphereParams.uniforms
},
'vertexShader': atosphereVertexShader,
'fragmentShader': atmosphereFragmentShader.replaceAll(
'void main() {',
'''${noiseFunctions}
void main() {'''
),
'depthWrite': false,
'transparent': true,
'blending': AdditiveBlending,
});
material.polygonOffset = true;
material.polygonOffsetFactor = -1.0;
material.polygonOffsetUnits = -4.0;
final int count = atmosphereParams.particles;
final Float32List combinedData = Float32List(count * 6);
final random = math.Random();
for(int i = 0; i < count; i++) {
double r = random.nextDouble() * atmosphereParams.thickness + atmosphereParams.radius;
// Pick a random point within a cube of size [-1, 1]
// This approach works better than parameterizing the spherical coordinates
// since it doesn't have the issue of particles being bunched at the poles
final p = Vector3(
2 * random.nextDouble() - 1,
2 * random.nextDouble() - 1,
2 * random.nextDouble() - 1
);
// Project onto the surface of a sphere
p.normalize();
p.scale(r);
final minSize = atmosphereParams.minParticleSize;
final maxSize = atmosphereParams.maxParticleSize;
final size = random.nextDouble() * (maxSize - minSize) + minSize;
combinedData.setAll(i * 4, [p.x, p.y, p.z, size]);
}
final geometry = BufferGeometry();
final interleavedBuffer = InterleavedBuffer(combinedData, 4);
geometry.setAttributeFromString('position', InterleavedBufferAttribute(interleavedBuffer, 3, 0));
geometry.setAttributeFromString('size', InterleavedBufferAttribute(interleavedBuffer, 1, 3));
geometry.computeBoundingSphere();
geometry.computeBoundingBox();
return Atmosphere._(geometry, material, atmosphereParams, renderOrder);
}