I am shooting for the previous approach.
Currently, I got the depth map / texture of the penetrating cone as shown below. However, I am struggling to figure out how I can map this texture onto the cone WITHOUT affecting the non-penetrating regions.
^ Depth map of cone(left), face(right), cone penetrating out(below).
Below is the code to create the cone.
const customUniforms = {
cameraNear: { value: coneDepthCamera.near },
cameraFar: { value: coneDepthCamera.far },
targetDepth: { value: null },
opponentDepth: { value: null },
};
const coneGeometry = new THREE.ConeGeometry(1, 2, 32);
const coneMaterial = new THREE.MeshStandardMaterial({
map: loader.load("https://threejs.org/examples/textures/uv_grid_opengl.jpg"),
onBeforeCompile: (shader) => {
// shader.uniforms.targetDepth = customUniforms.targetDepth;
// shader.uniforms.opponentDepth = customUniforms.opponentDepth;
shader.fragmentShader = shader.fragmentShader.replace(
"#include <clipping_planes_pars_fragment>",
`
#include <clipping_planes_pars_fragment>
uniform sampler2D targetDepth;
uniform sampler2D opponentDepth;
uniform float cameraNear;
uniform float cameraFar;
float readDepth(sampler2D depthSampler, vec2 coord) {
float fragCoordZ = texture2D(depthSampler, coord).x;
float viewZ = perspectiveDepthToViewZ(fragCoordZ, cameraNear, cameraFar);
return viewZToOrthographicDepth(viewZ, cameraNear, cameraFar);
}
`
);
shader.fragmentShader = `
#define ss(a, b, c) smoothstep(a, b, c)
${shader.fragmentShader}
`.replace(
`#include <dithering_fragment>`,
`#include <dithering_fragment>
float tDepth = 1.0 - (readDepth(targetDepth, vUv));
float oppDepth = 1.0 - (readDepth(opponentDepth, vUv));
float diffDepth = clamp(tDepth - oppDepth, 0.0, 1.0); // Penetrating depth
vec3 diffDepthTexture = vec3(diffDepth); // Depth texture to use
vec3 mask = ceil(diffDepthTexture); // When there is depth info make it 1
gl_FragColor.rgb = mix(gl_FragColor.rgb, diffDepthTexture, mask);
gl_FragColor.a = 1.0;
`
);
},
});
const coneMesh = new THREE.Mesh(coneGeometry, coneMaterial);
coneMesh.rotateX(Math.PI / 2);
coneMesh.position.set(-0.15, 2.5, -3); // S.t. it penetrates out from face forehead
coneMesh.position.z = -3;
coneMesh.layers.set(2);
scene.add(coneMesh);
Here, what I am trying to do is to use the depth info onto the faces of the cone that are penetrating outside, and keep the non-penetrating region with the original texture(uvmap texture). I am clearly doing something wrong in fragment shader. I spent quite a bit of time but not sure how to implement what I want …
Also, the targetDepth
is the depth of the cone
seen by the perspective camera (visualized with helper). opponentDepth
is the depth of the face
seen by another perspective camera (same config as the camera used to take cone depth)
And below is my render loop:
const tick = () => {
const elapsedTime = clock.getElapsedTime();
// Update controls
controls.update();
// Render to the faceTarget to use it as a texture
renderer.setRenderTarget(faceTarget);
renderer.render(scene, faceDepthCamera);
// Pass tDepth to fragment shader
facePlaneMaterial.uniforms.tDepth.value = faceTarget.depthTexture;
// Render the cone to coneTarget
renderer.setRenderTarget(coneTarget);
renderer.render(scene, coneDepthCamera);
conePlaneMaterial.uniforms.tDepth.value = coneTarget.depthTexture;
// Pass the target and opponent depth to diff shader
diffPlaneMaterial.uniforms.targetDepth.value = coneTarget.depthTexture;
diffPlaneMaterial.uniforms.opponentDepth.value = faceTarget.depthTexture;
customUniforms.targetDepth.value = coneTarget.depthTexture;
customUniforms.opponentDepth.value = faceTarget.depthTexture;
// Regular Render
renderer.setRenderTarget(null);
renderer.render(scene, camera);
// Call tick again on the next frame
window.requestAnimationFrame(tick);
};
tick();
To all shader experts, it would be great if I could get some aid here… 