Hello guys i w want to implement drag and drop functionality to my project but i have problem with selecting shader objects on a 3d model
i implemented a cursor follower and passed into fragments but the dot at fragments is always have a margin with cursor ot top right and the margin changes when i scroll far
i couldt find where is the issue please help me. you can see the red dot and cursor position(cursor is black circle)
const OnlyUvMap = () => {
extend({ ShaderMaterial });
const canvasRef = useRef();
function TShirtModel() {
const { nodes } = useGLTF("tshirtv6.glb");
const { camera, scene } = useThree();
const meshRef = useRef();
const raycaster = new THREE.Raycaster(); // For raycasting
const mouse = new THREE.Vector2(); // Mouse position in normalized device coordinates
const cursorUV = useRef(new THREE.Vector2(0.0, 0.0)); // Default UV at the center
useEffect(() => {
if (!meshRef.current) {
return;
}
const handleMouseMove = (event) => {
// Normalize mouse coordinates
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// Set raycaster and detect intersections
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(meshRef.current);
if (intersects.length > 0 && intersects[0].uv) {
// Update cursor UV when intersecting with the mesh
const uv = intersects[0].uv;
console.log("raycaser uv", uv);
// cursorUV.current.set(uv.x, uv.y);
cursorUV.current.set(intersects[0].uv.x, intersects[0].uv.y);
} else {
console.log("No intersection detected.");
console.log("mouse", mouse);
}
};
// Attach mousemove event listener
document.addEventListener("mousemove", handleMouseMove);
return () => {
// Clean up the event listener
document.removeEventListener("mousemove", handleMouseMove);
};
}, [camera]);
if (!nodes) {
console.log("Nodes not loaded yet");
return null; // Wait until the model is loaded
}
console.log(meshRef.current);
return (
<Suspense fallback={<p>wait please</p>}>
<mesh
geometry={nodes.Scene.children[0].geometry}
position={[0, -1.2, 0]}
ref={meshRef}
>
<shaderMaterial
uniforms={{
lightPosition: { value: new Vector3(2.0, 2.0, 2.0) }, // Lighting position
diffuseMap: { value: diffuseMapTexture },
cursorUV: { value: cursorUV.current }, // Pass cursorUV to the shader
dotRadius: { value: 0.02 }, // Dot size
dotColor: { value: new THREE.Color(1.0, 0.0, 0.0) }, // Dot color (red)
}}
vertexShader={vertexShader}
fragmentShader={fragmentShader}
/>
</mesh>
</Suspense>
);
}
const vertexShader = `
varying vec2 vUv;
varying vec3 vPosition;
varying vec3 vNormal;
void main() {
vUv = uv;
vNormal = normalize(normalMatrix * normal); // Standard normal transformation
vPosition = (modelViewMatrix * vec4(position, 1.0)).xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
uniform vec3 lightPosition;
uniform sampler2D diffuseMap;
uniform vec2 cursorUV; // Cursor UV coordinates
uniform float dotRadius; // Radius of the dot
uniform vec3 dotColor; // Color of the dot
varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vPosition;
void main() {
// Lighting calculation
vec3 lightDir = normalize(lightPosition - vPosition);
float lightIntensity = max(dot(adjustedNormal, lightDir), 0.0);
// Sample base diffuse map texture
vec3 baseColor = texture2D(diffuseMap, vUv).rgb;
// Apply light intensity to base color
baseColor *= lightIntensity;
// the dot in the center of the front part
float dist = distance(vUv, cursorUV);
// Blend the dot color into the base color
baseColor = mix(baseColor, dotColor, smoothstep(dotRadius, dotRadius * 0.9, dist));
// vec3 baseColortry = vec3(vUv, 0.0); // Visualize UV as RGB
// Output the final color
// gl_FragColor = vec4(baseColortry, 1.0);
}
`;
return (
<Canvas
ref={canvasRef}
camera={{
position: [0, 0, 1],
fov: 50,
up: [0, 3, 0],
near: 0.1, // Adjusted near clipping plane
far: 10, // Adjusted far clipping plane
}}
style={{
backgroundColor: "rgb(244, 244, 244)",
borderRadius: "30px",
}}
>
<ambientLight intensity={0.9} />
<directionalLight intensity={0.8} position={[2, 2, 2]} castShadow />
<TShirtModel />
<OrbitControls makeDefault />
</Canvas>
);
};
found the issue canvas was occupying 60% of the screen and when i try to find and intersect with mouse coordinates and uv coordinates there is an offset as uv coordinates only related with canvas and mouse coordinates related with whole screen
and the solution is getting relative coordinates:
const rect = getCanvasBounds();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;