Three.js技术咨询:能否为平面/立方体分区域应用双纹理?
在Three.js平面/立方体上实现分区域纹理
当然可以在同一个平面或立方体上应用多种纹理!针对你想把平面上下半部分分开用不同纹理的需求,我给你分享两种高效的实现方式:
方法一:自定义着色器(ShaderMaterial)—— 推荐动态场景使用
这种方法性能最优,适合需要动态调整纹理或有交互需求的场景。核心思路是在片元着色器中根据UV坐标的Y值判断当前像素处于平面的上半还是下半区域,然后分别采样对应的纹理。
直接修改你现有代码的material部分即可,完整示例如下:
var geometry = new THREE.PlaneGeometry( 2, 2 ); var loader = new THREE.TextureLoader(); // 加载两种目标纹理 var textureTop = loader.load('textures/stone.png'); var textureBottom = loader.load('textures/your-second-texture.png'); // 替换成你的第二张纹理路径 // 保持你原本的纹理重复配置 textureTop.wrapS = THREE.RepeatWrapping; textureTop.wrapT = THREE.RepeatWrapping; textureTop.repeat.set(4, 4); textureBottom.wrapS = THREE.RepeatWrapping; textureBottom.wrapT = THREE.RepeatWrapping; textureBottom.repeat.set(4, 4); // 自定义着色器材质 var material = new THREE.ShaderMaterial({ uniforms: { textureTop: { value: textureTop }, textureBottom: { value: textureBottom } }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: ` uniform sampler2D textureTop; uniform sampler2D textureBottom; varying vec2 vUv; void main() { vec4 color; // 根据UV的Y值划分上下区域(0.5是中间分界点) if(vUv.y > 0.5) { // 调整上半区UV,让纹理按设置的repeat参数正常重复 color = texture2D(textureTop, vec2(vUv.x, (vUv.y - 0.5) * 2.0)); } else { // 调整下半区UV,保证纹理重复效果一致 color = texture2D(textureBottom, vec2(vUv.x, vUv.y * 2.0)); } gl_FragColor = color; } ` }); var mesh = new THREE.Mesh(geometry, material); scene.add(mesh);
这里特意调整了UV坐标,确保两种纹理在各自区域内都能按照你设置的repeat参数正常重复,不会出现拉伸或错位的问题。
方法二:Canvas合成纹理—— 适合静态场景使用
如果你的纹理不需要动态变化,也可以先在Canvas上绘制好上下分区域的纹理,再把Canvas作为Three.js的纹理使用。这种方法更直观,不需要写着色器代码。
示例代码如下:
var geometry = new THREE.PlaneGeometry( 2, 2 ); var loader = new THREE.TextureLoader(); // 用Promise确保两种纹理都加载完成再处理 Promise.all([ new Promise(resolve => loader.load('textures/stone.png', resolve)), new Promise(resolve => loader.load('textures/your-second-texture.png', resolve)) ]).then(([textureTop, textureBottom]) => { // 创建Canvas元素,设置合适的分辨率 const canvas = document.createElement('canvas'); canvas.width = 1024; canvas.height = 1024; const ctx = canvas.getContext('2d'); // 绘制上半部分纹理 ctx.drawImage(textureTop.image, 0, canvas.height/2, canvas.width, canvas.height/2); // 绘制下半部分纹理 ctx.drawImage(textureBottom.image, 0, 0, canvas.width, canvas.height/2); // 将Canvas转为Three.js纹理 const combinedTexture = new THREE.CanvasTexture(canvas); combinedTexture.wrapS = THREE.RepeatWrapping; combinedTexture.wrapT = THREE.RepeatWrapping; combinedTexture.repeat.set(4, 4); // 创建材质和网格 var material = new THREE.MeshBasicMaterial({ map: combinedTexture }); var mesh = new THREE.Mesh(geometry, material); scene.add(mesh); });
这种方法的好处是不用接触着色器,调试起来更简单,但如果需要频繁更换纹理,性能会比着色器方法差一些。
如果是给立方体的某个面做分区域纹理,只需要确保该面的UV坐标范围是0-1,然后套用同样的逻辑处理就行啦~
内容的提问来源于stack exchange,提问作者Matías Cánepa
相关产品推荐
相关产品推荐

