In threejs, i'm working on a showerbase project using shader. One of my material got visible mineral veins on it and I noticed when it wrap around the border, the veins are not aligned.
I made a simple cube using the material to demonstrate the problem:
The final product can change in size and I can also cut geometry in it depending on user input but a simple cube illustrate well the problem. What technique should I use to achieve the desire result?
Here is the current code of the shader
mat.onBeforeCompile = function( shader ) {
if (mat.map) {
shader.uniforms.triplanarTexture = { value: mat.map };
shader.uniforms.triplanarScale = mat.userData.triplanarScale;
if (mat.normalMap) {
shader.uniforms.triplanarNormalMap = { value: mat.normalMap };
}
shader.vertexShader = `
varying vec3 vWorldPosition;
varying vec3 vTriplanarNormal; // Use a distinct name for world-space normal
${shader.vertexShader}
`;
shader.vertexShader = shader.vertexShader.replace(
'#include <begin_vertex>',
`
#include <begin_vertex>
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
vTriplanarNormal = normalize(mat3(modelMatrix) * normal); // Transform normal to world space
`
);
shader.fragmentShader = `
uniform float triplanarScale;
uniform sampler2D triplanarTexture;
varying vec3 vWorldPosition;
varying vec3 vTriplanarNormal; // Use the distinct name in fragment shader too
${shader.fragmentShader}
`;
const triplanarSampleFunction = `
vec4 sampleTriplanarTexture(sampler2D tex, vec3 p, vec3 n, float scale) {
vec3 blend_weights = abs(n);
blend_weights = normalize(max(vec3(0.001), blend_weights));
blend_weights /= (blend_weights.x + blend_weights.y + blend_weights.z);
vec4 colX = texture2D(tex, p.yz * scale);
vec4 colY = texture2D(tex, p.xz * scale);
vec4 colZ = texture2D(tex, p.xy * scale);
return colX * blend_weights.x + colY * blend_weights.y + colZ * blend_weights.z;
}
`;
shader.fragmentShader = shader.fragmentShader.replace(
'void main() {',
`${triplanarSampleFunction}\nvoid main() {`
);
// Replace the standard map lookup with our tri-planar lookup
shader.fragmentShader = shader.fragmentShader.replace(
'#include <map_fragment>',
`
vec4 texelColor = sampleTriplanarTexture(triplanarTexture, vWorldPosition, vTriplanarNormal, triplanarScale);
diffuseColor *= texelColor; // Apply the triplanar texture to diffuseColor
`
);
}
shader.fragmentShader = shader.fragmentShader.replace(
'#include <output_fragment>',
`
#ifdef OPAQUE
gl_FragColor = vec4( outgoingLight, opacity );
#else
gl_FragColor = vec4( outgoingLight, diffuseColor.a ); // Use diffuseColor.a for transparency if applicable
#endif
if (!gl_FrontFacing) {
vec3 backfaceColor = vec3( 0.4, 0.4, 0.4 );
gl_FragColor = vec4( backfaceColor, opacity ); // Ensure opacity is used for backface
}
`
);
mat.userData.shader = shader;
};