Tri-panner 在babylonjs中有支持 但是three.js目前的基础材质并不支持
需要自己定义shader 或者使用目前还没有什么完善的文档的 NodeMaterial
下面展示两种实现方式
/**
* @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 " ,
`
#include
varying vec3 tripPosition;
varying vec3 tripNormal;
`
);
shader.vertexShader = shader.vertexShader.replace(
"#include " ,
`
#include
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 " ,
`
#include
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 " ,
`
#include
diffuseColor.rgb = vec3(triplanarMapping( map ,tripNormal,tripPosition));
`
);
// shader.fragmentShader = shader.fragmentShader.replace(
// "#include ",
// `
// #include
// diffuseColor.rgb = vec3(triplanar_mapping( map ,tripNormal,tripPosition,1.0));
// `
// );
};
};
这是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 " ,
`
#include
nodeVarying2 = (modelMatrix * vec4(transformed,1.0)).xyz;
`
);
};
r155版本写法如下
material.onBeforeCompile = (shader) => {
material.vertexShader = shader.vertexShader.replace(
"#include " ,
`
#include
nodeVarying2 = ( nodeUniform2 * vec4( transformed, 1.0 ) );
`
);
};
这个问题nodeMaterial 没找到如何解决 下面给出自定义材质的解决方案
export const useTriplanarMapping = (mesh) => {
const material = mesh.material.clone();
mesh.material = material;
material.map.colorSpace = THREE.SRGBColorSpace;
material.map.wrapS = THREE.RepeatWrapping;
material.map.wrapT = THREE.RepeatWrapping;
if (material.normalMap) {
material.normalMap.colorSpace = THREE.SRGBColorSpace;
material.normalMap.wrapS = THREE.RepeatWrapping;
material.normalMap.wrapT = THREE.RepeatWrapping;
}
material.onBeforeCompile = (shader) => {
shader.vertexShader = shader.vertexShader.replace(
"#include " ,
`
#include
varying vec3 tripPosition;
varying vec3 tripNormal;
`
);
shader.vertexShader = shader.vertexShader.replace(
"#include " ,
`
#include
vec4 tripPosition4 = modelMatrix * vec4(transformed,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 " ,
`
#include
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 " ,
`
#include
diffuseColor.rgb = vec3(triplanarMapping( map ,tripNormal,tripPosition));
`
);
shader.fragmentShader = shader.fragmentShader.replace(
"#include " ,
`
#include
normal = vec3(triplanarMapping( normalMap ,tripNormal,tripPosition));
normal = normalize( tbn * normal );
`
);
};
};