Skip to content

Commit

Permalink
added earth
Browse files Browse the repository at this point in the history
  • Loading branch information
Resaki1 committed Jan 11, 2024
1 parent 5922c7e commit 7576a55
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 14 deletions.
Binary file added public/textures/earth_clouds.webp
Binary file not shown.
Binary file added public/textures/earth_day.webp
Binary file not shown.
Binary file added public/textures/earth_specular.webp
Binary file not shown.
136 changes: 136 additions & 0 deletions src/components/Planet/Planet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { Sphere, shaderMaterial, useTexture } from "@react-three/drei";
import { extend, useFrame } from "@react-three/fiber";
import { useRef } from "react";
import {
AdditiveBlending,
DoubleSide,
Euler,
Group,
Mesh,
Vector3,
} from "three";

const AtmosphereShaderMaterial = shaderMaterial(
// Uniforms
{
sunDirection: new Vector3(0, 0, 1),
},
`
varying vec3 vPosition;
varying vec3 vNormal;
void main() {
vPosition = position;
vNormal = normalize(normal);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
`
uniform vec3 sunDirection;
varying vec3 vPosition;
varying vec3 vNormal;
const float Hr = 8.0; // Rayleigh scale height
const float Hm = 1.2; // Mie scale height
const vec3 betaR = vec3(5.8e-6, 1.35e-5, 3.31e-5); // Rayleigh scattering coefficients
const float betaM = 4e-5; // Mie scattering coefficient
const float planetRadius = 94.5; // Planet radius
const float atmosphereThickness = 5.0; // Atmosphere thickness
float rayleighPhase(float cosTheta) {
return (3.0 / (16.0 * 3.14159265)) * (1.0 + cosTheta * cosTheta);
}
float miePhase(float cosTheta, float g) {
float g2 = g * g;
return (3.0 / (8.0 * 3.14159265)) * ((1.0 - g2) / (2.0 + g2)) * (1.0 + cosTheta * cosTheta) / pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5);
}
void main() {
vec3 normalizedPosition = normalize(vPosition);
float heightAboveSurface = length(vPosition) - planetRadius;
// Calculate the atmospheric density based on height
float rho = exp(-heightAboveSurface / Hr) + exp(-heightAboveSurface / Hm);
vec3 betaRTheta = betaR * rho;
float betaMTheta = betaM * rho;
float cosTheta = dot(normalizedPosition, sunDirection);
float rayleigh = rayleighPhase(cosTheta);
float mie = miePhase(cosTheta, 0.76);
// Intensity of the scattering effect
vec3 scatter = (betaRTheta * rayleigh + betaMTheta * mie) * 1.0;
// Final color based on the scattering
vec3 finalColor = vec3(1.0) - exp(-scatter);
// Calculate alpha for the edge fade effect
// The alpha should start at 1 at the planet's surface and go to 0 at the edge of the atmosphere
float edgeStart = planetRadius; // At the planet's surface
float edgeEnd = planetRadius + atmosphereThickness; // At the upper limit of the atmosphere
float alpha = smoothstep(edgeEnd, edgeStart, heightAboveSurface);
// Apply the calculated alpha value
gl_FragColor = vec4(finalColor * scatter, alpha);
}
`
);

extend({ AtmosphereShaderMaterial });

const position = new Vector3(100, 0, -100);
const rotation = new Euler(1.1 * Math.PI, 1.8 * Math.PI, 0.8 * Math.PI);
const sunDirection = new Vector3(0, 0, -1);

const Planet = () => {
const planet = useRef<Group>(null!);
const atmosphere = useRef<Mesh>(null!);
const texture = useTexture({
map: "/textures/earth_day.webp",
specularMap: "/textures/earth_specular.webp",
});
const clouds = useTexture({
map: "/textures/earth_clouds.webp",
alphaMap: "/textures/earth_clouds.webp",
});

useFrame(({ camera }) => {
if (planet.current) {
planet.current.position.copy(camera.position).add(position);
}
});

return (
<group position={position} rotation={rotation} ref={planet}>
<Sphere args={[81, 48, 48]} ref={atmosphere}>
<atmosphereShaderMaterial
attach="material"
args={[
{
sunDirection: sunDirection,
},
]}
side={DoubleSide}
depthWrite={false}
blending={AdditiveBlending}
/>
</Sphere>
<Sphere args={[80, 48, 48]}>
<meshPhongMaterial
{...texture}
shininess={100}
specular={"lightblue"}
/>
</Sphere>
<Sphere args={[80.2, 48, 48]}>
<meshPhongMaterial {...clouds} transparent alphaTest={0} />
</Sphere>
</group>
);
};

useTexture.preload("/textures/earth_day.webp");

export default Planet;
2 changes: 2 additions & 0 deletions src/components/Scene/Scene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import SpaceShip from "@/components/Spaceship";
import StarsComponent from "../Stars/StarsComponent";
import Star from "../Star/Star";
import "./Scene.scss";
import Planet from "../Planet/Planet";

const Scene = () => {
const [movement, setMovement] = useState<{
Expand Down Expand Up @@ -54,6 +55,7 @@ const Scene = () => {
)}
<ambientLight intensity={0.5} />
<Star />
<Planet />
<SpaceShip movement={movement} />
<StarsComponent />
</Canvas>
Expand Down
32 changes: 18 additions & 14 deletions src/components/Star/Star.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useFrame } from "@react-three/fiber";
import { useRef } from "react";
import { Mesh, Vector3 } from "three";

const position = new Vector3(0, 0, 500);
const position = new Vector3(0, 0, 512);

const Star = () => {
const star = useRef<Mesh>(null!);
Expand All @@ -16,24 +16,28 @@ const Star = () => {
});

return (
<mesh ref={star} position={position}>
<>
<directionalLight // Star
position={position}
intensity={12}
color="white"
castShadow
scale={512}
/>
<Sphere args={[5, 128, 128]}>
<meshStandardMaterial
color="white"
emissive="white"
emissiveIntensity={512}
toneMapped={false}
/>
</Sphere>
<Billboard>
<Image url="/assets/star.png" scale={16} transparent />
</Billboard>
</mesh>
<mesh ref={star} position={position}>
<Billboard>
<Image url="/assets/star.png" scale={64} transparent />
</Billboard>
<Sphere args={[16, 16, 16]}>
<meshStandardMaterial
color="white"
emissive="white"
emissiveIntensity={512}
toneMapped={false}
/>
</Sphere>
</mesh>
</>
);
};

Expand Down
10 changes: 10 additions & 0 deletions src/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import "@react-three/fiber";

declare module "@react-three/fiber" {
interface ThreeElements {
atmosphereShaderMaterial: ReactThreeFiber.MaterialNode<
THREE.ShaderMaterial,
[THREE.ShaderMaterialParameters]
>;
}
}

0 comments on commit 7576a55

Please sign in to comment.