Compare commits
2 Commits
ea33336736
...
93290a6c06
Author | SHA1 | Date | |
---|---|---|---|
93290a6c06 | |||
d08cdd4177 |
26
package-lock.json
generated
26
package-lock.json
generated
@ -11,7 +11,9 @@
|
||||
"three": "^0.147.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dat.gui": "^0.7.9",
|
||||
"@types/three": "^0.146.0",
|
||||
"dat.gui": "^0.7.9",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.2.3",
|
||||
"vite-plugin-plain-text": "^1.2.1"
|
||||
@ -281,6 +283,12 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/dat.gui": {
|
||||
"version": "0.7.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/dat.gui/-/dat.gui-0.7.9.tgz",
|
||||
"integrity": "sha512-UiqZasQIask5cUwWOO6BgOjP1dNj9ChYtmeAb4WTKs5IJ7ha3ATRTeXY7/TzlmEZznh40lS6Ov5BdNA+tU+fWQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/three": {
|
||||
"version": "0.146.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.146.0.tgz",
|
||||
@ -296,6 +304,12 @@
|
||||
"integrity": "sha512-IUMDPSXnYIbEO2IereEFcgcqfDREOgmbGqtrMpVPpACTU6pltYLwHgVkrnYv0XhWEcjio9sYEfIEzgn3c7nDqA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/dat.gui": {
|
||||
"version": "0.7.9",
|
||||
"resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.9.tgz",
|
||||
"integrity": "sha512-sCNc1OHobc+Erc1HqiswYgHdVNpSJUlk/Hz8vzOCsER7rl+oF/4+v8GXFUyCgtXpoCX6+bnmg07DedLvBLwYKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz",
|
||||
@ -1002,6 +1016,12 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@types/dat.gui": {
|
||||
"version": "0.7.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/dat.gui/-/dat.gui-0.7.9.tgz",
|
||||
"integrity": "sha512-UiqZasQIask5cUwWOO6BgOjP1dNj9ChYtmeAb4WTKs5IJ7ha3ATRTeXY7/TzlmEZznh40lS6Ov5BdNA+tU+fWQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/three": {
|
||||
"version": "0.146.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.146.0.tgz",
|
||||
@ -1017,6 +1037,12 @@
|
||||
"integrity": "sha512-IUMDPSXnYIbEO2IereEFcgcqfDREOgmbGqtrMpVPpACTU6pltYLwHgVkrnYv0XhWEcjio9sYEfIEzgn3c7nDqA==",
|
||||
"dev": true
|
||||
},
|
||||
"dat.gui": {
|
||||
"version": "0.7.9",
|
||||
"resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.9.tgz",
|
||||
"integrity": "sha512-sCNc1OHobc+Erc1HqiswYgHdVNpSJUlk/Hz8vzOCsER7rl+oF/4+v8GXFUyCgtXpoCX6+bnmg07DedLvBLwYKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz",
|
||||
|
@ -9,7 +9,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dat.gui": "^0.7.9",
|
||||
"@types/three": "^0.146.0",
|
||||
"dat.gui": "^0.7.9",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.2.3",
|
||||
"vite-plugin-plain-text": "^1.2.1"
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
Object3D,
|
||||
ShaderMaterial,
|
||||
SphereGeometry,
|
||||
Vector3,
|
||||
} from 'three';
|
||||
|
||||
import { plainText as vertexShader } from './shaders/atmosphere.vert';
|
||||
@ -17,7 +18,7 @@ export class Atmosphere extends Object3D {
|
||||
public Scale = 1;
|
||||
public ScaleDepth = 0.25;
|
||||
public G = -0.95;
|
||||
public Wavelength = [0.65, 0.57, 0.475];
|
||||
public Wavelength = new Vector3(0.65, 0.57, 0.475);
|
||||
|
||||
public geom?: SphereGeometry;
|
||||
public mesh?: Mesh;
|
||||
@ -35,12 +36,30 @@ export class Atmosphere extends Object3D {
|
||||
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[0], 4),
|
||||
1 / Math.pow(this.Wavelength[1], 4),
|
||||
1 / Math.pow(this.Wavelength[2], 4),
|
||||
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 };
|
||||
@ -60,8 +79,18 @@ export class Atmosphere extends Object3D {
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
38
src/globe.ts
38
src/globe.ts
@ -7,6 +7,7 @@ import {
|
||||
Color,
|
||||
DirectionalLight,
|
||||
ShaderMaterial,
|
||||
MeshPhongMaterial,
|
||||
} from 'three';
|
||||
|
||||
import { plainText as vertexShader } from './shaders/earth.vert';
|
||||
@ -14,15 +15,31 @@ import { plainText as fragmentShader } from './shaders/earth.frag';
|
||||
import { Atmosphere } from './atmosphere';
|
||||
|
||||
export class Globe extends Object3D {
|
||||
private sphere = new SphereGeometry(1, 128, 128);
|
||||
private atmosphere = new Atmosphere(1, 1.05);
|
||||
private earthMaterial?: ShaderMaterial;
|
||||
private sphere?: SphereGeometry;
|
||||
private clouds = new SphereGeometry(1.02, 64, 64);
|
||||
public atmosphere = new Atmosphere(1, 1.05);
|
||||
public earthMaterial?: ShaderMaterial;
|
||||
public earthMesh?: Mesh;
|
||||
|
||||
private loader = new TextureLoader();
|
||||
|
||||
constructor(private planetRadius: number) {
|
||||
super();
|
||||
}
|
||||
|
||||
set radius(radius: number) {
|
||||
this.planetRadius = radius;
|
||||
this.atmosphere.planetRadius = radius;
|
||||
this.earthMaterial && this.atmosphere.setUniforms(this.earthMaterial);
|
||||
this.createMesh();
|
||||
}
|
||||
get radius() {
|
||||
return this.planetRadius;
|
||||
}
|
||||
|
||||
public async loadTexture(name: string) {
|
||||
return new Promise<Texture>((resolve, reject) => {
|
||||
this.loader.load(`/${name}`, resolve, undefined, reject);
|
||||
this.loader.load(`./${name}`, resolve, undefined, reject);
|
||||
});
|
||||
}
|
||||
|
||||
@ -55,10 +72,19 @@ export class Globe extends Object3D {
|
||||
|
||||
this.atmosphere.setUniforms(this.earthMaterial);
|
||||
this.atmosphere.setLight(light);
|
||||
this.earthMesh = new Mesh(this.sphere, this.earthMaterial);
|
||||
this.add(this.earthMesh);
|
||||
this.createMesh();
|
||||
this.add(this.atmosphere);
|
||||
}
|
||||
|
||||
public tick() {}
|
||||
|
||||
private createMesh() {
|
||||
if (this.sphere) {
|
||||
this.sphere.dispose();
|
||||
this.earthMesh && this.remove(this.earthMesh);
|
||||
}
|
||||
this.sphere = new SphereGeometry(this.planetRadius, 128, 128);
|
||||
this.earthMesh = new Mesh(this.sphere, this.earthMaterial);
|
||||
this.add(this.earthMesh);
|
||||
}
|
||||
}
|
||||
|
55
src/main.ts
55
src/main.ts
@ -3,6 +3,7 @@ import { Renderer } from './renderer';
|
||||
import { DirectionalLight } from 'three';
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
|
||||
import './style.css';
|
||||
import { GUI } from 'dat.gui';
|
||||
|
||||
const main = new Renderer();
|
||||
|
||||
@ -10,7 +11,7 @@ const dirLight = new DirectionalLight(0xffffff, 1);
|
||||
dirLight.position.set(10, 10, 10);
|
||||
main.scene.add(dirLight);
|
||||
|
||||
const globe = new Globe();
|
||||
const globe = new Globe(1);
|
||||
main.resize();
|
||||
globe.initialize(dirLight).catch(console.error);
|
||||
main.scene.add(globe);
|
||||
@ -19,6 +20,58 @@ main.camera.position.set(0, 0, 2);
|
||||
|
||||
const control = new OrbitControls(main.camera, main.canvas);
|
||||
|
||||
const gui = new GUI();
|
||||
const atmosGui = gui.addFolder('Atmosphere');
|
||||
const updateAtmosShader = () => {
|
||||
globe.atmosphere.setUniforms(globe.atmosphere.shader);
|
||||
globe.atmosphere.setUniforms(globe.earthMaterial!);
|
||||
};
|
||||
// any's because for some reason the generic expects a string indexed record
|
||||
atmosGui
|
||||
.add<any>(globe.atmosphere.Wavelength, 'x', 0, 1)
|
||||
.name('R')
|
||||
.onChange(updateAtmosShader);
|
||||
atmosGui
|
||||
.add<any>(globe.atmosphere.Wavelength, 'y', 0, 1)
|
||||
.name('G')
|
||||
.onChange(updateAtmosShader);
|
||||
atmosGui
|
||||
.add<any>(globe.atmosphere.Wavelength, 'z', 0, 1)
|
||||
.name('B')
|
||||
.onChange(updateAtmosShader);
|
||||
|
||||
atmosGui
|
||||
.add<any>(globe.atmosphere, 'thickness', 0.001, 0.5)
|
||||
.name('Thickness')
|
||||
.onChange(updateAtmosShader);
|
||||
atmosGui
|
||||
.add<any>(globe.atmosphere, 'ScaleDepth', 0.01, 1)
|
||||
.name('Scale depth')
|
||||
.onChange(updateAtmosShader);
|
||||
atmosGui
|
||||
.add<any>(globe.atmosphere, 'Rayleigh', 0.0001, 0.01)
|
||||
.onChange(updateAtmosShader);
|
||||
atmosGui
|
||||
.add<any>(globe.atmosphere, 'Mie', 0.0001, 0.01)
|
||||
.onChange(updateAtmosShader);
|
||||
atmosGui
|
||||
.add<any>(globe.atmosphere, 'Exposure', 0, 100)
|
||||
.onChange(updateAtmosShader);
|
||||
atmosGui.open();
|
||||
|
||||
const planetGui = gui.addFolder('Planet');
|
||||
planetGui
|
||||
.add<any>(globe.rotation, 'x', -Math.PI * 2, Math.PI * 2, 0.01)
|
||||
.name('Rotation X');
|
||||
planetGui
|
||||
.add<any>(globe.rotation, 'y', -Math.PI * 2, Math.PI * 2, 0.01)
|
||||
.name('Rotation Y');
|
||||
planetGui
|
||||
.add<any>(globe.rotation, 'z', -Math.PI * 2, Math.PI * 2, 0.01)
|
||||
.name('Rotation Z');
|
||||
// planetGui.add<any>(globe, 'radius', 1, 100).name('Radius');
|
||||
planetGui.open();
|
||||
|
||||
function tick() {
|
||||
requestAnimationFrame(tick);
|
||||
control.update();
|
||||
|
@ -1,10 +1,16 @@
|
||||
#define EARTH
|
||||
#include <common>
|
||||
#include <normal_pars_vertex>
|
||||
|
||||
varying vec3 vViewPosition;
|
||||
varying vec3 vLightDirection;
|
||||
varying vec2 vUv;
|
||||
varying vec3 vEyeNormal;
|
||||
#include <common>
|
||||
#include <normal_pars_vertex>
|
||||
|
||||
varying vec3 v3Direction;
|
||||
varying vec3 c0;
|
||||
varying vec3 c1;
|
||||
|
||||
uniform vec3 light;
|
||||
|
||||
uniform vec3 invWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
@ -19,10 +25,6 @@ uniform float scaleDepth; // The scale depth (i.e. the altitude at which the
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 1.0;
|
||||
|
||||
varying vec3 v3Direction;
|
||||
varying vec3 c0;
|
||||
varying vec3 c1;
|
||||
|
||||
float dscale(float fCos) {
|
||||
float x = 1.0 - fCos;
|
||||
return scaleDepth * exp(-0.00287 + x * (0.459 + x * (3.83 + x * (-6.80 + x * 5.25))));
|
||||
|
@ -3,4 +3,5 @@ import plainText from 'vite-plugin-plain-text';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [plainText.default(/\.vert|\.frag$/)],
|
||||
base: '',
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user