带有独立 alphamap 的 threejs texturemap UV

threejs texturemap UV with independent alphamap

我有一个大纹理 - 一张照片 - 和一个应该显示主纹理区域的简单小网格。这些网格应该有一个 alphaMap,例如一个圆。

在网格 material 的纹理 (PlaneBufferGeometry) 中,我更改了 UV 贴图,因此它会显示主纹理的适当区域。问题是 UV 映射也应用于 alphaMap,但我希望它独立。

const planeGeometry = new THREE.PlaneBufferGeometry(sz.x, sz.y);
let uvs= planeGeometry.attributes.uv;
for (let ix = 0; ix< uvs.array.length; ix++){
    let x = uvs.getX(ix);
    let y = uvs.getY(ix);
    uvs.setXY(ix, x*.5, y*.75);   // just testing
}

const planeMaterial = new THREE.MeshPhongMaterial({
    map: imageTexture,
    transparent: true,      
    alphaMap ,
    normalMap,
});

有没有办法只更改 material 贴图的 UV 贴图,而让其他贴图(alphaMap 和 normalMap)保持独立...或者有其他方法吗?

解决此问题的最简单方法是单独保留几何体 uvs,而是在照片纹理上使用一些内置的纹理变换属性。它们是 .offset.repeat.rotation。和 .center。您可以阅读描述 in the docs。例如,如果你想将你的照片纹理缩放到 200%,你可以使用

imageTexture.repeat.set(0.5, 0.5);

如果你想移动它:

imageTexture.offset.set(0.0, 0.7);

这只会影响 imageTexture 而不会影响您的 alphaMap 纹理。

如果您想更改旋转原点,

.rotation.center 结合使用。

一个可能的选择是将第二组 uv 坐标添加到您的几何:

// setup new attribute uvs
var uvb = new Float32Array( [
    0.25, 0.75,
    0.75, 0.75,
    0.25, 0.25,
    0.75, 0.25
] );

planeGeometry.setAttribute( 'uvB', new THREE.BufferAttribute( uvb, 2 ) );

并修改 material 着色器以将那组坐标用于您的颜色贴图纹理:

var planeMaterial = new THREE.MeshPhongMaterial( {
    side: THREE.DoubleSide,
    transparent: true,
    map: colorTex,
    alphaMap: alphaTex,
} );

planeMaterial.onBeforeCompile = function( shader ) {

    // vertex modifications
    var vertex_pars = 'attribute vec2 uvB;\nvarying vec2 vUvB;\n';
    var vertex_uv = shader.vertexShader.replace(
        '#include <uv_vertex>',
        [
            '#include <uv_vertex>',
            'vUvB = uvB;'
        ].join( '\n' )
    );

    shader.vertexShader = vertex_pars + vertex_uv;


    // fragment modifications
    var frag_pars = 'varying vec2 vUvB;\n';
    var frag_uv = shader.fragmentShader.replace(
        '#include <map_fragment>',
        [
            'vec4 texelColor = texture2D( map, vUvB );',
            'texelColor = mapTexelToLinear( texelColor );',
            'diffuseColor *= texelColor;'
        ].join( '\n' )
    );

    shader.fragmentShader = frag_pars + frag_uv;

}

此方法的缺点是每次要使用不同的 uv 集时都需要不同的几何体。这可能会对性能产生影响,具体取决于您的应用程序。

JSFiddle Example