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

发布时间:2024年01月17日

请添加图片描述

在这里插入图片描述

介绍

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 ) );
     `
     );
 };
文章来源:https://blog.csdn.net/printf_hello/article/details/135648800
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。