import React, { useRef, useEffect } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
import { useLoader } from '@react-three/fiber';
import * as THREE from 'three';
import getStarfield from '../../public/src/getStarfield.js';
import { getFresnelMat } from '../../public/src/getFresnelMat.js';
function Earth() {
const earthGroupRef = useRef();
const { scene } = useThree();
useEffect(() => {
const earthGroup = earthGroupRef.current;
earthGroup.rotation.z = -23.4 * Math.PI / 180;
const stars = getStarfield({ numStars: 2000 });
scene.add(stars);
return () => {
scene.remove(stars);
};
}, [scene]);
useFrame(() => {
if (earthGroupRef.current) {
earthGroupRef.current.children.forEach((mesh, index) => {
if (index == 2) {
mesh.rotation.y += 0.0013 ;
}else{
mesh.rotation.y += 0.001 ;
}
});
}
});
const map = useLoader(THREE.TextureLoader, '../public/textures/2k_earth_daymap.jpg');
const specularMap = useLoader(THREE.TextureLoader, '../public/textures/02_earthspec1k.jpg');
const bumpMap = useLoader(THREE.TextureLoader, '../public/textures/01_earthbump1k.jpg');
const lightsMap = useLoader(THREE.TextureLoader, '../public/textures/2k_earth_nightmap.jpg');
const cloudsMap = useLoader(THREE.TextureLoader, '../public/textures/04_earthcloudmap.jpg');
const cloudsAlphaMap = useLoader(THREE.TextureLoader, '../public/textures/05_earthcloudmaptrans.jpg');
const earthMaterial = new THREE.MeshPhongMaterial({
map: map,
specularMap: specularMap,
bumpMap: bumpMap,
bumpScale: 0.04,
});
const lightsMaterial = new THREE.ShaderMaterial({
uniforms: {
lightsMap: { value: lightsMap },
lightDirection: { value: new THREE.Vector3(-2, 0.5, 1.5) }, // Adjust based on your light source
},
vertexShader: `
varying vec3 vWorldNormal;
varying vec2 vUv;
void main() {
vUv = uv;
vWorldNormal = normalize(mat3(modelMatrix) * normal);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1);
}
`,
fragmentShader: `
uniform sampler2D lightsMap;
uniform vec3 lightDirection;
varying vec3 vWorldNormal;
varying vec2 vUv;
void main() {
float lightFactor = clamp(dot(normalize(vWorldNormal), normalize(lightDirection)), 0.0, 1.0);
float transition = smoothstep(-0.1, 0.1, lightFactor);
vec4 nightLights = texture2D(lightsMap, vUv);
gl_FragColor = mix(nightLights, vec4(0.0, 0.0, 0.0, 1.0), transition);
}
`,
blending: THREE.AdditiveBlending,
transparent: true,
});
const cloudsMaterial = new THREE.MeshStandardMaterial({
map: cloudsMap,
transparent: true,
opacity: 0.8,
blending: THREE.AdditiveBlending,
alphaMap: cloudsAlphaMap,
});
const fresnelMaterial = getFresnelMat();
const geometry = new THREE.IcosahedronGeometry(1, 64);
return (
<group ref={earthGroupRef}>
<mesh geometry={geometry} material={earthMaterial} />
<mesh geometry={geometry} material={lightsMaterial} />
<mesh geometry={geometry} material={cloudsMaterial} scale={1.003} />
<mesh geometry={geometry} material={fresnelMaterial} scale={1.01} />
</group>
);
}
export const Model = () => {
return (
<Canvas camera={{ position: [0, 0, 5], fov: 75 }} gl={{ clearColor: 0x00000 }} >
<OrbitControls minDistance={1.8} maxDistance={10}/>
<ambientLight intensity={0.01} />
<directionalLight position={[-2, 0.5, 1.5]}intensity={1}/>
<Earth />
</Canvas>
);
};
I’ve been trying to make the light material render the world’s surface at night but it’s not working very well. There are still dark spots appearing from time to time. I think it’s a ShaderMaterial or fragmentShader material. However, I’ve been searching for a solution for 2 hours and nothing works.