0
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.

HELP

0

Browse other questions tagged or ask your own question.