Search code examples
reactjsthree.js3dreact-three-fiber

What is uv in PointerEvent react three fiber


I'm trying to make a simple drawing on 3D models. It works perfectly in this example for sphere but when I'm trying to use my own obj 3D models I don't see uv in PointerEvent and drawing doesn't work. I didn't find any documentation describing what is uv so please can anyone describe what is it and why I don't see it for my obj models and see it for sphere from example? My code:

import { Canvas, ThreeEvent, extend, useLoader, useThree } from '@react-three/fiber';
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
import { BufferGeometry, CanvasTexture, Group, Mesh } from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';

import './styles.scss';

extend({ OrbitControls });

declare global {
  // eslint-disable-next-line @typescript-eslint/no-namespace
  namespace JSX {
    interface IntrinsicElements {
      orbitControls: any;
    }
  }
}

const Controls: React.FC = () => {
  const orbitControlsRef = useRef<OrbitControls>();
  const { camera, gl } = useThree();

  return <orbitControls ref={orbitControlsRef} args={[camera, gl.domElement]} minDistance={1.25} />;
};

const SandBox: React.FC = () => {
  const [allowControls, setAllowControls] = useState(true);
  const canvasRef = useRef(document.createElement('canvas'));
  const textureRef = useRef<CanvasTexture>(null);

  const obj = useLoader(OBJLoader, 'src/assets/meshes/pyramid.obj');

  const geometry = useMemo(() => {
    let g;
    obj.traverse(c => {
      if (c.type === 'Mesh') {
        const _c = c as Mesh;
        g = _c.geometry;
      }
    });
    return g;
  }, [obj]);

  useLayoutEffect(() => {
    const canvas = canvasRef.current;

    canvas.width = 1024;
    canvas.height = 1024;

    const context = canvas.getContext('2d');
    if (context) {
      context.rect(0, 0, canvas.width, canvas.height);
      context.fillStyle = 'white';
      context.fill();
    }
  }, []);

  const handleBrushPointerMove = (ev: ThreeEvent<PointerEvent>) => {
    if (allowControls) {
      return;
    }
    if (ev) {
      console.log(ev);
      const canvas = canvasRef.current;

      const x = ev.unprojectedPoint.x * canvas.width;
      const y = (1 - ev.unprojectedPoint.y) * canvas.height;

      const context = canvas.getContext('2d');
      if (context) {
        context.beginPath();
        context.arc(x - 2, y - 2, 4, 0, 2 * Math.PI);
        context.fillStyle = 'black';
        context.fill();
        textureRef.current!.needsUpdate = true;
      }
    }
  };

  return (
    <>
      <Canvas
        onCreated={({ gl }) => {
          gl.physicallyCorrectLights = true;
        }}
        camera={{ position: [0, 0, 2] }}
      >
        {allowControls && <Controls />}
        <mesh
          onPointerDown={() => setAllowControls(false)}
          onPointerUp={() => setAllowControls(true)}
          onPointerMove={handleBrushPointerMove}
          geometry={geometry}
        >
          <meshStandardMaterial attach="material" metalness={0} roughness={1}>
            <canvasTexture ref={textureRef} attach="map" image={canvasRef.current} />
          </meshStandardMaterial>
        </mesh>
        <ambientLight intensity={0.5} />
        <spotLight position={[0, 0, 10]} intensity={10} />
        <spotLight position={[-10, 0, -5]} intensity={10} />
        <spotLight position={[10, 0, -5]} intensity={10} />
      </Canvas>
    </>
  );
};

export default SandBox;

Thanks


Solution

  • The problem was in the model I used. It has not any UV-mapping. After that, I downloaded the model with UV-mapping and it turned over possible to draw.