Maison >interface Web >js tutoriel >Comment puis-je simuler une atmosphère réaliste autour d'un modèle terrestre 3D à l'aide de Three.js et d'un fragment shader personnalisé ?

Comment puis-je simuler une atmosphère réaliste autour d'un modèle terrestre 3D à l'aide de Three.js et d'un fragment shader personnalisé ?

DDD
DDDoriginal
2024-11-12 11:09:02474parcourir

How can I simulate a realistic atmosphere around a 3D Earth model using Three.js and a custom fragment shader?

Three.js est une bibliothèque JavaScript populaire pour créer des graphiques 3D dans le navigateur. Il est souvent utilisé pour créer des visualisations et des jeux interactifs. L'un des défis des graphiques 3D est de restituer des objets qui ne sont pas opaques, comme des nuages ​​ou de la fumée. Ces objets laissent passer la lumière, ce qui peut créer un aspect plus doux et plus réaliste.

Dans ce cas, le but est d'ajouter un effet « atmosphère » à une représentation de la Terre. L'atmosphère sera une couche semi-transparente qui entoure la Terre et disperse la lumière, lui donnant un aspect plus réaliste.

Pour obtenir cet effet, nous allons créer un fragment shader qui calculera la couleur de chaque pixel. dans l'atmosphère en fonction de sa position dans l'atmosphère et de la direction de la source lumineuse. Le fragment shader utilisera une technique appelée "diffusion atmosphérique" pour simuler la manière dont la lumière est diffusée par les particules dans l'atmosphère.

Voici le code du fragment shader :

#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif

uniform vec3 lightDirection;
uniform sampler2D earthTexture;

varying vec2 vUv;
varying vec3 vNormal;

void main() {
  // Compute the surface normal at this position
  vec3 normal = normalize(vNormal);
  // Compute the direction from this point to the light source
  vec3 lightDir = normalize(lightDirection);
  // Compute the amount of light that is scattered in this direction
  float scattering = dot(normal, lightDir);
  // Compute the color of the atmosphere at this position
  vec3 color = texture2D(earthTexture, vUv).rgb * scattering;
  // Output the color
  gl_FragColor = vec4(color, 1.0);
}

Ce fragment le shader prend plusieurs entrées :

  • lightDirection : La direction vers la lumière source.
  • earthTexture : La texture utilisée pour représenter la Terre.
  • vUv : Les coordonnées de texture du pixel actuel.
  • vNormal : Le vecteur normal du pixel actuel.

Le fragment shader calcule d'abord la normale à la surface au pixel actuel. Il calcule ensuite la direction du pixel actuel vers la source de lumière. Ces deux valeurs sont utilisées pour calculer la quantité de lumière diffusée dans la direction du pixel.

Le fragment shader calcule ensuite la couleur de l'atmosphère au pixel actuel en multipliant la couleur de la texture de la Terre par la quantité de diffusion. La couleur résultante est affichée sous forme de couleur de fragment.

Pour utiliser ce shader de fragment, nous devons créer un matériau qui l'utilise. Voici un exemple de matériau qui utilise le shader de fragment de diffusion atmosphérique :

const material = new THREE.ShaderMaterial({
  fragmentShader: `
    #ifdef GL_FRAGMENT_PRECISION_HIGH
    precision highp float;
    #else
    precision mediump float;
    #endif
    
    uniform vec3 lightDirection;
    uniform sampler2D earthTexture;
    
    varying vec2 vUv;
    varying vec3 vNormal;
    
    void main() {
      vec3 normal = normalize(vNormal);
      vec3 lightDir = normalize(lightDirection);
      float scattering = dot(normal, lightDir);
      vec3 color = texture2D(earthTexture, vUv).rgb * scattering;
      gl_FragColor = vec4(color, 1.0);
    }
  `,
  uniforms: {
    lightDirection: { value: new THREE.Vector3(0, 1, 0) },
    earthTexture: { value: new THREE.TextureLoader().load('earth.jpg') }
  }
});

Ce matériau prend deux uniformes :

  • lightDirection : La direction vers la source de lumière.
  • earthTexture : La texture utilisée pour représenter la Terre.

Le matériau utilise l'uniforme lightDirection pour calculer la quantité de lumière diffusée dans chaque direction. Il utilise l'uniforme earthTexture pour représenter la surface de la Terre.

Pour utiliser ce matériau, nous devons créer un maillage et l'attribuer au matériau. Voici un exemple de la façon de créer un maillage et de l'attribuer au matériau :

const geometry = new THREE.SphereGeometry(10, 32, 32);
const material = new THREE.ShaderMaterial({
  fragmentShader: `
    #ifdef GL_FRAGMENT_PRECISION_HIGH
    precision highp float;
    #else
    precision mediump float;
    #endif
    
    uniform vec3 lightDirection;
    uniform sampler2D earthTexture;
    
    varying vec2 vUv;
    varying vec3 vNormal;
    
    void main() {
      vec3 normal = normalize(vNormal);
      vec3 lightDir = normalize(lightDirection);
      float scattering = dot(normal, lightDir);
      vec3 color = texture2D(earthTexture, vUv).rgb * scattering;
      gl_FragColor = vec4(color, 1.0);
    }
  `,
  uniforms: {
    lightDirection: { value: new THREE.Vector3(0, 1, 0) },
    earthTexture: { value: new THREE.TextureLoader().load('earth.jpg') }
  }
});
const mesh = new THREE.Mesh(geometry, material);

Ce code crée une géométrie de sphère avec un rayon de 10, 32 segments et 32 ​​anneaux. Il crée ensuite un matériau qui utilise le shader de fragment de diffusion atmosphérique. Enfin, il crée un maillage et l'attribue au matériau.

Une fois le mesh créé, il peut être ajouté à la scène. Voici un exemple de la façon d'ajouter le maillage à la scène :

#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif

uniform vec3 lightDirection;
uniform sampler2D earthTexture;

varying vec2 vUv;
varying vec3 vNormal;

void main() {
  // Compute the surface normal at this position
  vec3 normal = normalize(vNormal);
  // Compute the direction from this point to the light source
  vec3 lightDir = normalize(lightDirection);
  // Compute the amount of light that is scattered in this direction
  float scattering = dot(normal, lightDir);
  // Compute the color of the atmosphere at this position
  vec3 color = texture2D(earthTexture, vUv).rgb * scattering;
  // Output the color
  gl_FragColor = vec4(color, 1.0);
}

Ce code ajoute le maillage à la scène. Le maillage sera maintenant rendu à l’aide du shader de fragment de diffusion atmosphérique. Le résultat sera une atmosphère semi-transparente qui entoure la Terre.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:ChatGPT pour le débogageArticle suivant:ChatGPT pour le débogage