【问题标题】:Multi-map-channel models and textures in three.jsthree.js 中的多地图通道模型和纹理
【发布时间】:2018-07-02 16:06:40
【问题描述】:

我正在尝试在 three.js 中使用两个以上的贴图通道来为我的模型分配纹理。令我惊讶的是,three.js 中没有原生材质支持多组 uv。因此我必须使用 ShaderMaterial 并编写自己的顶点/片段着色器才能访问多个贴图通道。

现在我确实设法让多通道 uvs 使用我编写的简单代码:

<script id="vertex_shh" type="x-shader/x-vertex">

    //VERTEX SHADER//

        varying vec2 vUv;
        attribute vec2 uv2;
        varying vec2 vUv2;
        attribute vec2 uv3;
        varying vec2 vUv3;
        attribute vec2 uv4;
        varying vec2 vUv4;
        attribute vec2 uv5;
        varying vec2 vUv5;


        void main()
        {
            vUv = uv;
            vUv2 = uv2;
            vUv3 = uv3;
            vUv4 = uv4;
            vUv5 = uv5;                 

            vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
            gl_Position = projectionMatrix * mvPosition;
        }

    // END //

    </script>       



    <script id="fragment_shh" type="x-shader/x-fragment">   

    //FRAGMENT SHADER//

        uniform sampler2D tCh1;
        uniform sampler2D tCh2;
        uniform sampler2D tCh3;
        uniform sampler2D tCh4;         
        uniform sampler2D tCh5;

        varying vec2 vUv;
        varying vec2 vUv2;
        varying vec2 vUv3;
        varying vec2 vUv4;
        varying vec2 vUv5;


        void main(void)
        {
            vec3 DiffuseComp;
            vec4 TexCh1 = texture2D(tCh1, vUv);
            vec4 TexCh2 = texture2D(tCh2, vUv2);
            vec4 TexCh3 = texture2D(tCh3, vUv3);
            vec4 TexCh4 = texture2D(tCh4, vUv4);
            vec4 TexCh5 = texture2D(tCh5, vUv5);

            DiffuseComp = ((TexCh1.rgb * (1.0 - TexCh4.rgb) + (TexCh2.rgb * TexCh4.rgb)) * (1.0 - TexCh5.rgb)) + (TexCh3.rgb * TexCh5.rgb);
            gl_FragColor= vec4(DiffuseComp, 1.0);   
        }

    // END //

        /* SHADER */
        var vertShader = document.getElementById('vertex_shh').innerHTML;
        var fragShader = document.getElementById('fragment_shh').innerHTML;

        var attributes = {};

        var uniforms = {
        tCh1: { type: "t", value: Textura1},
        tCh2: { type: "t", value: Textura2},
        tCh3: { type: "t", value: Textura3},
        tCh4: { type: "t", value: Textura4},
        tCh5: { type: "t", value: Textura5}
        };          


        /* MATERIAL */
        var multitexsh = new THREE.ShaderMaterial({
        uniforms: uniforms,
        attributes: attributes,
        vertexShader: vertShader,
        fragmentShader: fragShader
        });

但是,我的问题是我基本上需要一个具有此功能的着色器以及 Phong 着色器的一些基本功能:照明(来自场景灯光)和镜面高光。我完全迷失在这里。我已经尝试寻找方法来将此功能添加到本机着色器或将上述功能从 phong 材质添加到我自己的着色器,但没有发现任何信息足以用我非常基本的编码技能做到这一点.. 任何人都可以进来帮帮我吗?


编辑:

感谢 pailhead 让它与 onBeforeCompile 一起工作。这是在 r89 上,更新代码如下:

        /* MANAGERS, LOADERS */
        var manager = new THREE.LoadingManager();
        var loader = new THREE.FBXLoader( manager );
        var textureLoader = new THREE.TextureLoader( manager );

        /*TEXTURE */
        var prodtex ='textures/testing/cubetex.jpg';
        var prodtex2 ='textures/testing/cube_blendmap.jpg';

        var Textura1 = textureLoader.load (prodtex);
        var Textura2 = textureLoader.load (prodtex);
        var Textura3 = textureLoader.load (prodtex2);

        /* MATERIAL */
        var MAT = new THREE.MeshPhongMaterial();
        MAT.map = Textura1;     

        /* MY SHADER CHANGES*/
        const uv2_chunkToReplaceVS = 'attribute vec2 uv2; varying vec2 vUv2; attribute vec2 uv3; varying vec2 vUv3;'
        const uv2_chunkToReplaceVSV = 'vUv2 = uv2; vUv3 = uv3;'
        const uv2_chunkToReplaceFS = 'uniform sampler2D tCh1; uniform sampler2D tCh2; uniform sampler2D tCh3; varying vec2 vUv2; varying vec2 vUv3;'
        const map_chunkToReplaceFSV = 'vec4 TexCh1 = texture2D(tCh1, vUv); vec4 TexCh2 = texture2D(tCh2, vUv2); vec4 TexCh3 = texture2D(tCh3, vUv3); vec4 texelColor = texture2D( map, vUv ); texelColor = mapTexelToLinear( texelColor ); TexCh1 = mapTexelToLinear( TexCh1 ); TexCh2 = mapTexelToLinear( TexCh2 ); TexCh2 = mapTexelToLinear( TexCh2 ); diffuseColor *= TexCh1 * (1.0 - TexCh3) + (TexCh2 * TexCh3);'

        MAT.onBeforeCompile = shader=>{
        shader.uniforms.tCh1= {type: "t", value: Textura1};
        shader.uniforms.tCh2= {type: "t", value: Textura2};
        shader.uniforms.tCh3= {type: "t", value: Textura3};

        shader.fragmentShader = shader.fragmentShader.replace('#include <map_fragment>', map_chunkToReplaceFSV);
        shader.vertexShader = shader.vertexShader.replace('#include <uv2_pars_vertex>', uv2_chunkToReplaceVS );
        shader.vertexShader = shader.vertexShader.replace('#include <uv2_vertex>', uv2_chunkToReplaceVSV );
        shader.fragmentShader = shader.fragmentShader.replace('#include <uv2_pars_fragment>', uv2_chunkToReplaceFS);
        };


        /* MODEL */
        loader.load( ('models/' + 'cube' + '.FBX'), function( object ) {
            //set material//
            object.traverse( function ( child ) {
                if ( child instanceof THREE.Mesh ) {
                    child.material = MAT;
                };
            } );                
            scene.add (object);
        });

【问题讨论】:

标签: three.js glsl textures channel shadermaterial


【解决方案1】:

您可以使用名为onBeforeCompile 的材料的未记录功能。

它是在三个解析着色器模板之前和编译着色器之前调用的回调。

模板可能如下所示

//someTemplate.vert

#include <common>
#include <some_pars_vertex>

void main(){
  #include <some_vertex>
  #include <another_vertex>

  gl_Position = projectionMatrix * foobar;
}

假设您想添加更多的 uv 通道。你会在 GLSL 中创建一些 sn-ps/函数。这必须在全局范围内发生(void main(){...} 以上):

//myBeforeVoidMain.vert

attribute vec2 aUV2;
attribute vec2 aUV3;

varying vec2 vUv2;
varying vec2 vUv3;

那么这必须发生在主函数中:

//myUv.vert
vUv2 = aUV2;
vUv3 = aUV3;

您可以注入此代码,但在哪里以及如何注入?

如何:

const chunkToReplace = THREE.ShaderChunk.uv_pars_vertex

myMaterial = new THREE.MeshPhongMaterial()
myMaterial.onBeforeCompile( shader=>{
  shader.uniforms.myUniform = {value:foo} 
  shader.vertexShader = shader.vertexShader.replace( '#include <uv_pars_vertex>', chunkToReplace + myChunk )
})

地点:

您需要熟悉两者: https://github.com/mrdoob/three.js/tree/dev/src/renderers/shaders/ShaderChunk https://github.com/mrdoob/three.js/tree/dev/src/renderers/shaders/ShaderLib

你需要考虑一下。可以注意到&lt;common&gt; 几乎存在于每个库的全局范围内。但是,因为它包含在 vert 和 frag 着色器中,所以不能在其中提及 attribute,因此 frag 着色器将无法编译。

为顶点着色器添加属性、统一和变量的一个好块是uv_pars_vertex,因为它也存在于几乎所有着色器中。

对于这个特殊问题,您还必须扩展片段着色器。再次将变量放在uv_pars_fragment 中,然后您必须找到使用这些 uv 通道的其余逻辑。

注意:

将两个通道打包到一个属性中可能是个好主意:

attribute vec4 aUv23;

...
  vUv2 = aUv23.xy;
  vUv3 = aUv23.zw;

【讨论】:

  • 你好 pailhead,感谢您提供如此深入的回答。我想这是一种方法。我还没有尝试过,因为在我阅读您的答案之前,我已经开始研究另一种方法。我正在尝试从块中构建着色器。我首先从 phong 复制所有块,然后删除我不需要的块。然后只剩下几个夹头,我会用我自己的替换 UV_pars 等并编辑 gl_fragcolor 以实现多个 uv。然而,我的着色器(虽然它是 PhongMaterial 的副本)不像 phongshader 那样工作。这种方法是否合法?我可能做错了什么?
  • 你好。我试过用 onBeforeCompile 来做这件事。一定错过了一些东西。你能看看原帖吗?它是用我当前的代码编辑的
  • onBeforeCompile( shader=&gt; shader.uniforms.tch1 = { value: tex } )
  • pailhead,感谢您的意见。但是,我确实认为,这里的语法一定有问题.. 不应该用 'blah' 替换 #include 把 phongshader 弄乱? :) 因为这就是我所做的,但什么也没发生: Mat.onBeforeCompile(shader=>{shader.vertexShader = shader.vertexShader.replace('#include ', 'blah');})
  • 应该的,你用的是哪三个版本?
猜你喜欢
  • 1970-01-01
  • 2018-01-18
  • 2013-11-13
  • 2016-02-27
  • 1970-01-01
  • 1970-01-01
  • 2017-04-26
  • 2019-10-18
  • 1970-01-01
相关资源
最近更新 更多