globe/src/atmosphere.ts

97 lines
2.5 KiB
TypeScript

import {
BackSide,
DirectionalLight,
Mesh,
Object3D,
ShaderMaterial,
SphereGeometry,
Vector3,
} from 'three';
import { plainText as vertexShader } from './shaders/atmosphere.vert';
import { plainText as fragmentShader } from './shaders/atmosphere.frag';
export class Atmosphere extends Object3D {
public Rayleigh = 0.0025;
public Mie = 0.0005;
public Exposure = 15.0;
public Scale = 1;
public ScaleDepth = 0.25;
public G = -0.95;
public Wavelength = new Vector3(0.65, 0.57, 0.475);
public geom?: SphereGeometry;
public mesh?: Mesh;
public shader = new ShaderMaterial({
vertexShader,
fragmentShader,
side: BackSide,
transparent: true,
});
constructor(public innerRadius: number, public outerRadius: number) {
super();
this.Scale = 1 / (this.outerRadius - this.innerRadius);
this.setUniforms(this.shader);
this.initialize();
}
set planetRadius(radius: number) {
const thickness = this.thickness;
this.innerRadius = radius;
this.outerRadius = radius + thickness;
this.refreshScale();
}
get planetRadius() {
return this.innerRadius;
}
set thickness(thickness: number) {
this.outerRadius = thickness + this.innerRadius;
this.refreshScale();
}
get thickness() {
return this.outerRadius - this.innerRadius;
}
setUniforms(shader: ShaderMaterial) {
shader.uniforms.invWavelength = {
value: [
1 / Math.pow(this.Wavelength.x, 4),
1 / Math.pow(this.Wavelength.y, 4),
1 / Math.pow(this.Wavelength.z, 4),
],
};
shader.uniforms.outerRadius = { value: this.outerRadius };
shader.uniforms.innerRadius = { value: this.innerRadius };
shader.uniforms.Kr = { value: this.Rayleigh };
shader.uniforms.Km = { value: this.Mie };
shader.uniforms.ESun = { value: this.Exposure };
shader.uniforms.scale = { value: this.Scale };
shader.uniforms.scaleDepth = { value: this.ScaleDepth };
shader.uniforms.g = { value: this.G };
}
setLight(light: DirectionalLight) {
this.shader.uniforms.lightDirection = {
value: light.position.clone().normalize(),
};
}
initialize() {
if (this.geom) {
this.geom.dispose();
this.mesh && this.remove(this.mesh);
}
this.geom = new SphereGeometry(this.outerRadius, 128, 128);
this.mesh = new Mesh(this.geom, this.shader);
this.add(this.mesh);
}
private refreshScale() {
this.Scale = 1 / (this.outerRadius - this.innerRadius);
this.setUniforms(this.shader);
this.initialize();
}
}