The problem with window transparency in Three.js / Three Fiber

36 views Asked by At

I'm adding a window object, which is a GLTF model. Depending on the window's size, I place a mesh object behind it to simulate glass (to make the interior of the hall visible). This works correctly on one side of the hall (image #1), but on the other sides of the hall, it doesn't work as intended (image #2).

enter image description here enter image description here

import { useState, useEffect } from 'react';
import * as THREE from 'three';
import { Shape, ShapeGeometry, MeshBasicMaterial } from 'three';
import { useSpring, animated } from '@react-spring/web'
import { useDrag } from 'react-use-gesture';
import { useThree } from "@react-three/fiber";
const _ = require("lodash");  

function DraggableWindow(props) {
    const { size, viewport } = useThree();
    const aspect = size.width / viewport.width;
    let sub;
    if(props.direction === 'back' || props.direction === 'front'){
        sub = props.elementPositionToSub;
    }else if(props.direction === 'left' || props.direction === 'right' ){
        sub = props.elementPositionToSubSides;
    }
    let glassRotation;
    if(props.direction === 'front'){

    }else if(props.direction === 'back'){

    }else if(props.direction === 'left'){
        glassRotation = [0, 0, Math.PI];
    }else if(props.direction === 'right'){
        glassRotation = [0, Math.PI, 0];
    }
    const [position, setPosition] = useState((props.direction === 'back' || props.direction === 'front' ? [props.newposition.x, props.newposition.y, props.ModelPos] : [props.ModelPos, props.newposition.y, props.newposition.z]));
    const [rotation, setRotation] = useState([props.newrotation.x, props.newrotation.y, props.newrotation.z]);
    const [scale, setScale] = useState(props.scaleX !== undefined ? [props.scaleX, props.scaleY, 25] : props.scale);
    const [show, setShow] = useState(false);
    const [draggable, setDraggable] = useState(true);
    let circlePosition, circleRotation, xRotation;
    if(props.direction === 'front' || props.direction === 'back'){
        if(props.obj === '1_window'){
            circlePosition = [0, 1.7, -0.09];
            circleRotation = [0, 3.2, 0];
            xRotation = [0, 0, 0];
        }else if(props.obj === '2_window'){
            circlePosition = [1.9, 2.2, 0.07];
            circleRotation = [0, 0, 0];
            xRotation = [0, 0, 0];
        }else if(props.obj === '3_window'){
            circlePosition = [2.21, -0.02, -0.05];
            circleRotation = [0, -Math.PI / 2, 0];
            xRotation = [0, -Math.PI / 2, Math.PI / 4];
        }else if(props.obj === '4_window'){
            circlePosition = [3.95, 1.65, 0.02];
            circleRotation = [0, 0, 0];
            xRotation = [0, 0, 0];
        }
    }else{
        if(props.obj === '1_window'){
            circlePosition = [1.2, 1.7, 0.02];
            circleRotation = [0, 0, 0];
            xRotation = [0, 0, 0];
        }else if(props.obj === '2_window'){
            circlePosition = [0, 2.2, -0.14];
            circleRotation = [0, Math.PI, 0];
            xRotation = [0, 0, 0];
        }else if(props.obj === '3_window'){
            circlePosition = [0.05, 0.09, -0.05];
            circleRotation = [0, Math.PI / 2, 0];
            xRotation = [0, -Math.PI / 2, Math.PI / 4];
        }else if(props.obj === '4_window'){
            circlePosition = [0.65, 1.65, -0.09];
            circleRotation = [0, Math.PI, 0];
            xRotation = [0, 0, 0];
        }
    }

    const bind = useDrag(
        ({ active, offset: [x, y] }) => {
            if(draggable){
                if(props.direction === 'front'){
                    const [, , z] = position;
                    setPosition([x / aspect, -y / aspect, props.ModelPos - sub]);
                    props.setCameraMovement(!active);
                }else if (props.direction === 'back'){
                    const [, , z] = position;
                    setPosition([-x / aspect, -y / aspect, props.ModelPos + sub]);
                    props.setCameraMovement(!active);
                }else if (props.direction === 'left'){
                    const [z, , ] = position;
                    if(props.obj === '4_window'){
                        setPosition([props.ModelPos - (sub + 3.5), -y / aspect, x / aspect]);
                    }else{
                        setPosition([props.ModelPos - sub, -y / aspect, x / aspect]);
                    }
                    props.setCameraMovement(!active);
                }else if (props.direction === 'right'){
                    const [z, , ] = position;
                    if(props.obj === '4_window'){
                        setPosition([props.ModelPos + (sub + 3.5), -y / aspect, -x / aspect]);
                    }else{
                        setPosition([props.ModelPos + sub, -y / aspect, -x / aspect]);
                    }
                    props.setCameraMovement(!active);
                }
            }
        },
        { pointerEvents: true }
    );

    
    useEffect(() => {
        if(props.direction === 'front'){
            setPosition([position[0], position[1], props.ModelPos - sub]);
        }else if(props.direction === 'back'){
            setPosition([position[0], position[1], props.ModelPos + sub]);
        }else if(props.direction === 'left'){
            if(props.obj === '4_window'){
                setPosition([props.ModelPos - (sub + 3.5), position[1], position[2]]);
            }else{
                setPosition([props.ModelPos - sub, position[1], position[2]]);
            }
        }else if(props.direction === 'right'){
            if(props.obj === '4_window'){
                setPosition([props.ModelPos + (sub + 3.5), position[1], position[2]]);
            }else{
                setPosition([props.ModelPos + sub, position[1], position[2]]);
            }
        }
    }, [props.ModelPos]);

    const changeYScale = (e) => {
        // Store the initial position of the mouse\
        setDraggable(false)
        const initialY = e.clientY;
        const onPointerMove = (e) => {
            const deltaY = e.clientY - initialY;
            setScale([scale[0], scale[1] - deltaY, scale[2]])
            setPosition(position)
        };

        const onPointerUp = () => {
          document.removeEventListener('pointermove', onPointerMove);
          document.removeEventListener('pointerup', onPointerUp);
        };

        document.addEventListener('pointermove', onPointerMove);
        document.addEventListener('pointerup', onPointerUp);
    }

    const changeXScale = (e) => {
        // Store the initial position of the mouse\
        setDraggable(false)
        const initialX = e.clientX;
        const onPointerMove = (e) => {
            const deltaX = e.clientX - initialX;
            setScale([scale[0] + deltaX, scale[1], scale[2]])
            if(props.direction === 'front' || props.direction === 'back'){
                setPosition(position)
            }else if(props.direction === 'left'){
                setPosition([position[0] - 3.5, position[1], position[2]])
            }else if(props.direction === 'right'){
                setPosition([position[0] + 3.5, position[1], position[2]])
            }
        };

        const onPointerUp = () => {
          document.removeEventListener('pointermove', onPointerMove);
          document.removeEventListener('pointerup', onPointerUp);
        };

        document.addEventListener('pointermove', onPointerMove);
        document.addEventListener('pointerup', onPointerUp);
    }

    const Rectangle = () => {
        const rectangleShape = new THREE.Shape();
        rectangleShape.moveTo(0, 0);
        rectangleShape.lineTo(0, 1);
        rectangleShape.lineTo(1, 1);
        rectangleShape.lineTo(1, 0);
        rectangleShape.lineTo(0, 0);
      
        const geometry = new THREE.ShapeGeometry(rectangleShape);
      
        return (
          <mesh>
            <geometry attach="geometry" args={[geometry]} />
            <material attach="material" color="blue" />
          </mesh>
        );
      };

    return (
        <mesh
            onPointerEnter={(e) => { 
                const canvas = document.querySelector('canvas'); 
                if(e.object.parent.type === 'Group'){
                    canvas.style.cursor = 'pointer';
                }else{
                    canvas.style.cursor = 'grab';
                }
            }}
            onPointerLeave={() => { const canvas = document.querySelector('canvas'); canvas.style.cursor = null }}
            onClick={() => setShow(true)}
            onPointerMissed={() => setShow(false)}
            position={position}
            rotation={rotation}
            {...bind()}
        >
            <primitive object={props.window} scale={scale}>
                {(show ? <group position={circlePosition} rotation={(props.obj === '3_window' ? [0, 0, 1.6] : [0, 0, 0.8])} onClick={() => props.handleDeleteWindow(props.index)}>
                <mesh rotation={circleRotation}>
                    <circleBufferGeometry args={[0.15, 32]} /> {/* Ustaw odpowiednią średnicę i ilość segmentów */}
                    <meshStandardMaterial color="red" />
                </mesh>
                <mesh rotation={xRotation}>
                    <boxBufferGeometry args={[0.03, 0.2, 0.01]} />
                    <meshStandardMaterial color="white" />
                </mesh>
                <mesh rotation={xRotation}>
                    <boxBufferGeometry args={[0.2, 0.03, 0.01]} />
                    <meshStandardMaterial color="white" />
                </mesh>
            </group> : '')}
            {/* transparent element */}
            <mesh position={[2.3, 0.8, 0]} rotation={glassRotation}>
                <planeBufferGeometry attach="geometry" args={[3.2, 1.6]} />
                <meshPhongMaterial side={THREE.FrontSide} color="#999999" transparent={true} opacity={0.5} premultipliedAlpha={true}/>
            </mesh>
            {(show && props.obj === '4_window' ? 
                <mesh 
                    onPointerDown={(e) => {changeYScale(e)}}
                    onPointerLeave={() => {setDraggable(true); props.setCameraMovement(!props.cameraMovement);}}
                    scale={[0.6, 0.3, 0.5]} rotation={(props.direction === 'front' || props.direction === 'back' ? [0, 0, 0] : (props.direction === 'left' ? [Math.PI, 0, Math.PI] : [Math.PI, 0, Math.PI]))} position={[2.26, 1.9, 0]}
                >
                    <shapeGeometry/>
                    <meshStandardMaterial color="rgba(0, 0, 0, 0.2)"/>
                </mesh> 
            : '')}
            {(show && props.obj === '4_window' ? 
                <mesh  onPointerDown={(e) => {changeXScale(e)}} onPointerLeave={() => {setDraggable(true); props.setCameraMovement(!props.cameraMovement);}} scale={[0.6, 0.3, 0.5]} rotation={(props.direction === 'front' || props.direction === 'back' ? [0, 0, -Math.PI / 2] : (props.direction === 'left' ? [Math.PI, 0, Math.PI / 2] : [Math.PI, 0, Math.PI / 2]))} position={(props.direction === 'front' || props.direction === 'back' ? [4.195, 0.9, -0.1] : [0.4, 0.9, -0.1])}>
                    <shapeGeometry/>
                    <meshStandardMaterial color="rgba(0, 0, 0, 0.2)"/>
                </mesh> 
            : '')}
            </primitive>
        </mesh>
    )
}

Why does the object work correctly when added to one side of the hall, but not for the other sides?

0

There are 0 answers