97 lines
2.5 KiB
TypeScript
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();
|
|
}
|
|
}
|