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

Three.js中实现SKY标记纹理始终面向屏幕的方案问询

解决方案:屏幕空间UV映射实现静态SKY纹理

核心思路

让SKY表面的纹理采样直接绑定到屏幕坐标,而非3D空间坐标,这样无论相机怎么移动旋转,纹理始终和屏幕对齐,效果就像透过3D模型的“洞”看到网页背景。

具体实现步骤

1. 自定义ShaderMaterial实现屏幕UV采样

给所有标记为SKY的网格单独用自定义ShaderMaterial,通过顶点着色器传递屏幕空间位置,片元着色器直接用屏幕UV采样纹理:

顶点着色器代码

varying vec2 vScreenUV;

void main() {
    vec4 clipSpacePosition = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    // 把NDC坐标转成0-1范围的屏幕UV
    vScreenUV = clipSpacePosition.xy / clipSpacePosition.w * 0.5 + 0.5;
    gl_Position = clipSpacePosition;
}

片元着色器代码

uniform sampler2D skyTexture;
uniform vec2 textureRepeat; // 控制纹理平铺次数,对应网页background-repeat

varying vec2 vScreenUV;

void main() {
    // 应用平铺,模拟网页背景的repeat效果
    vec2 tiledUV = vScreenUV * textureRepeat;
    gl_FragColor = texture2D(skyTexture, tiledUV);
}

2. 处理多纹理场景

如果有多个不同的SKY纹理,不用为每个纹理写单独的Shader,靠uniform数组和索引就能搞定:

修改片元着色器支持多纹理

uniform sampler2D skyTextures[5]; // 根据实际数量调整
uniform int textureIndex; // 当前网格用的纹理索引
uniform vec2 textureRepeat;

varying vec2 vScreenUV;

void main() {
    vec2 tiledUV = vScreenUV * textureRepeat;
    gl_FragColor = texture2D(skyTextures[textureIndex], tiledUV);
}

JS中配置材质

// 加载所有SKY纹理
const skyTextures = [
    new THREE.TextureLoader().load('sky1.png'),
    new THREE.TextureLoader().load('sky2.png'),
    // ...更多纹理
];
// 给每个SKY网格设置材质
skyMesh.material = new THREE.ShaderMaterial({
    uniforms: {
        skyTextures: { value: skyTextures },
        textureIndex: { value: 0 }, // 对应第一个纹理
        textureRepeat: { value: new THREE.Vector2(2, 2) } // 平铺2x2
    },
    vertexShader: 顶点着色器代码,
    fragmentShader: 片元着色器代码,
    transparent: true, // 要透明洞效果就开这个
    depthWrite: false // 避免遮挡后面的物体
});

3. 优化细节

  • 要模拟“洞”的效果,确保SKY纹理的透明区域正确,同时材质开启transparent: true和depthWrite: false,防止遮挡场景里的其他物体。
  • 要是想让纹理和网页背景完全对齐,把textureRepeat设成和网页背景一致的重复系数,同时监听窗口resize事件,同步更新相机和渲染器的尺寸。

为什么之前的方案不行?

  • RenderTargets + envMap:这类方案是基于3D空间的环境映射,纹理会跟着相机视角做空间变换,自然会出现滑动和缩放,不符合屏幕静态的需求。
  • 多纹理实例问题:通过Shader的uniform数组和索引,不用为每个纹理创建单独的Shader实例,只要在每个网格的材质里指定对应的索引就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:20:33