You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ThreeJS实现:基于位置为地球模型应用日夜纹理并添加柔化过渡

实现地球昼夜纹理柔化过渡的方案

要实现这个效果,核心是用自定义ShaderMaterial控制纹理混合逻辑,ThreeJS默认材质没法直接实现这种基于朝向的动态纹理切换与柔化过渡。下面是具体实现步骤和代码示例:

核心思路

通过片元着色器计算每个表面点与太阳方向的夹角,生成平滑过渡的混合因子,用这个因子混合白天纹理和带灯光的夜间纹理,避免生硬的明暗分界。

具体实现步骤

1. 准备纹理资源

需要至少两张纹理(可选叠加灯光纹理增强效果):

  • 地球白天纹理:正常地表颜色图
  • 地球夜间纹理:深色地表图
  • 城市灯光纹理:高亮城市灯光区域的灰度图(可选,用来模拟夜间灯光)

2. 编写自定义Shader

顶点着色器

传递表面法线和太阳方向到片元着色器:

varying vec3 vNormal;
varying vec3 vLightDir;
uniform vec3 sunWorldPos;

void main() {
    vNormal = normalize(normalMatrix * normal);
    // 将太阳世界坐标转换为地球局部坐标系下的方向向量
    vec3 sunLocalPos = (modelMatrixInverse * vec4(sunWorldPos, 1.0)).xyz;
    vLightDir = normalize(sunLocalPos - position);
    
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

片元着色器

计算混合因子,采样纹理并完成柔化混合:

uniform sampler2D dayTexture;
uniform sampler2D nightTexture;
uniform sampler2D lightMask;

varying vec3 vNormal;
varying vec3 vLightDir;

void main() {
    // 计算表面法线与太阳方向的点积,朝向太阳的面为正值
    float dotProduct = dot(vNormal, vLightDir);
    
    // 用smoothstep生成平滑过渡的混合因子,调整参数控制过渡宽度
    // 区间越大,过渡带越宽,这里-0.1到0.1是柔和过渡区间
    float mixFactor = smoothstep(-0.1, 0.1, dotProduct);
    
    // 采样纹理(用uv坐标,适配SphereGeometry的默认UV映射)
    vec4 dayColor = texture2D(dayTexture, gl_TexCoord[0].xy);
    vec4 nightColor = texture2D(nightTexture, gl_TexCoord[0].xy);
    vec4 lightColor = texture2D(lightMask, gl_TexCoord[0].xy);
    
    // 给夜间纹理叠加灯光效果,增强真实感
    nightColor = nightColor + lightColor * 0.7;
    
    // 混合白天与夜间颜色
    vec4 finalColor = mix(nightColor, dayColor, mixFactor);
    
    gl_FragColor = finalColor;
}

3. 初始化地球网格与材质

在JS代码中加载纹理并创建ShaderMaterial:

// 加载纹理(实际项目建议用LoadingManager批量加载)
const textureLoader = new THREE.TextureLoader();
const dayTexture = textureLoader.load('path/to/day_texture.jpg');
const nightTexture = textureLoader.load('path/to/night_texture.jpg');
const lightMask = textureLoader.load('path/to/light_mask.png');

// 创建高细分地球几何体,细分度越高过渡越平滑
const earthGeo = new THREE.SphereGeometry(5, 64, 64);

// 创建自定义Shader材质
const earthMaterial = new THREE.ShaderMaterial({
    uniforms: {
        dayTexture: { value: dayTexture },
        nightTexture: { value: nightTexture },
        lightMask: { value: lightMask },
        sunWorldPos: { value: new THREE.Vector3(0, 0, 100) } // 初始太阳位置
    },
    vertexShader: document.getElementById('vertex-shader').textContent,
    fragmentShader: document.getElementById('fragment-shader').textContent,
    side: THREE.FrontSide
});

// 创建地球网格并加入场景
const earth = new THREE.Mesh(earthGeo, earthMaterial);
scene.add(earth);

4. 动态更新太阳方向

如果太阳或地球有动画,在每一帧更新Shader中的太阳位置uniform:

function animate() {
    requestAnimationFrame(animate);
    
    // 假设场景中有sunMesh对象作为太阳
    earthMaterial.uniforms.sunWorldPos.value.copy(sunMesh.position);
    
    renderer.render(scene, camera);
}
animate();

关键细节

  • 过渡宽度:调整smoothstep的两个参数(比如改成-0.2到0.2)可以加宽过渡带,让昼夜边界更柔和。
  • 纹理UV:确保SphereGeometry的UV坐标正确,避免纹理错位。
  • 灯光强度:夜间纹理的灯光叠加系数(示例中的0.7)可根据需求调整,避免灯光过亮或过暗。

内容的提问来源于stack exchange,提问作者cphayash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:05:30