Transparent layer of meshStandardMaterial three js React

I'm implementing a simple 3D-paint and want to implement an erasing. In order to do it I decided to use two layers of canvas: one for texture image and another one (transparent) for drawing to erase only canvas for drawing. Can you please advice how to have one meshStandardMaterial with the image texture (which shouldn't be modified while painting/erasing) and one ore more transparent meshStandardMaterial just for painting Here is the component code:

<Canvas onCreated={({ gl }) => { gl.physicallyCorrectLights = true; }} camera={{ position: [0, 0, 10] }} > {isControlsAllowed && <Controls />} <mesh onPointerLeave={handleDrawStop} onPointerDown={() => { setIsControlsAllowed(false); }} onPointerUp={() => { setIsControlsAllowed(true); }} onPointerMove={(ev) => { handleBrushPointerMove(ev, previousPoint.current); }} geometry={geometry} > <meshStandardMaterial attach="material" metalness={0} roughness={1} > <canvasTexture ref={currentTextureRef} attach="map" image={currentCanvasRef.current} /> </meshStandardMaterial> <meshStandardMaterial attach="material" metalness={0} roughness={1}> <canvasTexture ref={currentDrawingTextureRef} attach="map" image={currentDrawingCanvasRef.current} /> </meshStandardMaterial> </mesh> <ambientLight intensity={1} /> <spotLight position={[0, 0, 10]} intensity={10} /> <spotLight position={[-10, 0, -5]} intensity={10} /> <spotLight position={[10, 0, -5]} intensity={10} /> </Canvas> 

My hook code:

const currentCanvasRef = useRef(document.createElement("canvas")); const currentTextureRef = useRef<CanvasTexture>(null); const currentDrawingCanvasRef = useRef(document.createElement("canvas")); const currentDrawingTextureRef = useRef<CanvasTexture>(null); useLayoutEffect(() => { const context = currentDrawingCanvasRef.current.getContext("2d"); context?.clearRect( 0, 0, currentDrawingCanvasRef.current.width, currentDrawingCanvasRef.current.height ); createCanvasTextureFromImage("/Stool.jpg"); }, []); const createCanvasTextureFromImage = ( imageUrl: string, ) => { const canvas = currentCanvasRef.current; new ImageLoader().load(imageUrl, (image) => { const ctx = canvas.getContext("2d"); canvas.width = image.width; canvas.height = image.height; if (ctx) { ctx.clearRect(0.0, 0.0, canvas.width, canvas.height); ctx.drawImage(image, 0.0, 0.0, image.width, image.height); } }); }; const handleBrushPointerMove = ( currentPoint: ThreeEvent<PointerEvent>, prevPoint?: ThreeEvent<PointerEvent> ) => { // Some drawing logic }; 

What I'm expecting to see:

enter image description here

And what I'm actually see:

enter image description here

UPDATE: I just checked that array of materials doesn't work for mesh. Although each of the materials works separately, when using an array, the 3D model is not displayed at all

1 Answer

To Answer Your Comment :

  1. Increase the Offset: Increase the distance between the two meshes to prevent overlap. Adjust the mesh position:
position={[0, 0, 0.005]} 
  1. Depth Write/Read: Modify depth settings of the materials:
depthWrite={false} depthTest={false} 
  1. Polygon Offset: Use Three.js's polygon offset to artificially push the mesh backward in z-depth:
polygonOffset={true} polygonOffsetFactor={1} polygonOffsetUnits={1} 
  1. Use a Shader: Manipulate the depth in shaders to ensure correct rendering order. Requires knowledge of GLSL.

  2. Rethink Layering: Consider painting directly onto the image canvas, eliminating the need for a second mesh.

Start with the simplest solution (increasing the offset) and progress to more complex solutions as needed.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like