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é ?
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 :
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 :
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!