Three.js Tri-panner (三面贴图) 材质 两种实现方式

请添加图片描述

在这里插入图片描述

介绍

Tri-panner 在babylonjs中有支持 但是three.js目前的基础材质并不支持
需要自己定义shader 或者使用目前还没有什么完善的文档的 NodeMaterial

下面展示两种实现方式

自定义shader
/**
 * @description: 替换三角面贴图  https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/triPlanarMat
 * @param {SingleMaterialMesh} mesh
 * @return {*}
 */
export const useTriplanarMapping = (mesh: SingleMaterialMesh) => {
   
    const material = mesh.material.clone();
    mesh.material = material;
    material.map!.wrapS = THREE.RepeatWrapping;
    material.map!.wrapT = THREE.RepeatWrapping;
   
    material.onBeforeCompile = (shader) => {
   
        shader.vertexShader = shader.vertexShader.replace(
            "#include <common>",
            `
            #include <common>
            varying vec3 tripPosition;
            varying vec3 tripNormal;
        `
        );
        shader.vertexShader = shader.vertexShader.replace(
            "#include <fog_vertex>",
            `
            #include <fog_vertex>
            vec4 tripPosition4 = modelMatrix * vec4(position,1.) ;
            tripPosition = tripPosition4.xyz;
            tripNormal = normal * normalMatrix;
            vec3 world_space_normal = vec3(modelMatrix * vec4(normal, 0.0));
            tripNormal = normal;
        `
        );
        shader.fragmentShader = shader.fragmentShader.replace(
            "#include <common>",
            `
            #include <common>
            varying vec3 tripPosition;
            varying vec3 tripNormal;
            vec3 blendNormal(vec3 normal){
                vec3 blending = abs( normal );
                blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0 
                float b = (blending.x + blending.y + blending.z);
                blending /= vec3(b, b, b);
                return blending;
            }
            
            vec3 triplanarMapping (sampler2D tex, vec3 normal, vec3 position) {
              vec3 normalBlend = blendNormal(normal);
              vec3 xColor = texture(tex, position.yz).rgb;
              vec3 yColor = texture(tex, position.xz).rgb;
              vec3 zColor = texture(tex, position.xy).rgb;
              return (xColor * normalBlend.x + yColor * normalBlend.y + zColor * normalBlend.z);
            }
        `
        );

        shader.fragmentShader = shader.fragmentShader.replace(
            "#include <map_fragment>",
            `
            #include <map_fragment>
            diffuseColor.rgb = vec3(triplanarMapping( map ,tripNormal,tripPosition));
        `
        );
        // shader.fragmentShader = shader.fragmentShader.replace(
        //     "#include <color_fragment>",
        //     `
        //     #include <color_fragment>
        //     diffuseColor.rgb = vec3(triplanar_mapping( map ,tripNormal,tripPosition,1.0));
        // `
        // );
    };
};

NodeMaterial

这是threejs新系统充满未来 目前还没有一个完善的文档 并且不太稳定 r132的时候支持这个材质 r138就被删除了 一些api也都有变化 可以先参考 https://raw.githack.com/sunag/three.js/dev-nodes-doc/docs/index.html#manual/en/introduction/How-to-use-node-material

import {
   
    MeshBasicNodeMaterial,
    texture,
    triplanarTexture,
} from "three/examples/jsm/nodes/Nodes.js";
import {
    nodeFrame } from "three/examples/jsm/renderers/webgl/nodes/WebGLNodes.js";

const skyMat = new MeshBasicNodeMaterial();

skyMat.colorNode = triplanarTexture(
    texture(
        this.helper.loadTexture(
            "/public/textures/coral_stone_wall_diff_1k.jpg",
            (map) => {
   
                map.colorSpace = THREE.SRGBColorSpace;
                map.wrapS = THREE.RepeatWrapping;
                map.wrapT = THREE.RepeatWrapping;
            }
        )
    )
);
skyMat.side = THREE.DoubleSide;

const sky = new THREE.Mesh(new THREE.SphereGeometry(2, 32, 15), skyMat);
scene.add(sky);


animation() {
   
    nodeFrame.update();
}

要注意每一次render 同时调用 nodeFrame.update(); 否则报错

骨骼材质特殊处理

这个问题需要根据three版本进行区别处理

r160版本 使用的是 position
r155版本使用的是 nodeUniform2 * vec4( 忘了叫什么了, 1.0 )
总之每个版本可能不一样 因为 节点系统正在开发 需要对应版本对应处理

r160版本写法如下

material.onBeforeCompile = (shader) => {
   
    material.vertexShader = shader.vertexShader.replace(
        "#include <skinning_vertex>",
        `
        #include <skinning_vertex>
        nodeVarying2 = (modelMatrix * vec4(transformed,1.0)).xyz;
        `
    );
};

r155版本写法如下

material.onBeforeCompile = (shader) => {
   
   material.vertexShader = shader.vertexShader.replace(
         "#include <skinning_vertex>",
         `
         #include <skinning_vertex>
         nodeVarying2 = ( nodeUniform2 * vec4( transformed, 1.0 ) );
     `
     );
 };

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-18 07:00:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-18 07:00:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-18 07:00:03       82 阅读
  4. Python语言-面向对象

    2024-01-18 07:00:03       91 阅读

热门阅读

  1. 在 Centos 7.9 中,安装与配置 Docker 20.10.18

    2024-01-18 07:00:03       54 阅读
  2. flask不使用flask-login插件

    2024-01-18 07:00:03       57 阅读
  3. GO基础进阶篇 (十三)、泛型

    2024-01-18 07:00:03       51 阅读
  4. 服务器租用和托管有哪些注意事项?

    2024-01-18 07:00:03       49 阅读