Strange normal map behaviour

here’s my code, super simple. trying to create some sorta frosted class effect with refractions. any idea what’s up the the ugly black in top left corner? my guess is that it’s something with the thickness value, but i can’t figure it out. the model is just a simple 2d plane with 4 vertices

any help appreciated !

function Banner() {
  const groupRef = useRef();
  const lightRef = useRef();
  const scroll = useScroll();
  const texture = useTexture(ice);
  texture.repeat.set(3,3);
  texture.wrapS = THREE.RepeatWrapping;
  texture.wrapT = THREE.RepeatWrapping;
  texture.offset = new THREE.Vector2(0.5, 0.5);
  const {nodes} = useLoader(GLTFLoader, bannerBG);
  const rawMouse = useMousePosition();

  useFrame(() => {
    var mouse = new THREE.Vector2(
      rawMouse.x - window.innerWidth / 2,
      rawMouse.y - window.innerHeight / 2,
    );
    var y = scroll.range(0 / 2, 1 / 2) * 5;
    groupRef.current.position.set(
      groupRef.current.position.x,
      y,
      groupRef.current.position.z,
    );
    lightRef.current.position.set(mouse.x / 100, -mouse.y / 100, 5);
  });
  return (
    <group ref={groupRef}>
      <mesh position={[0, 0, -10]} scale={[100, 100, 100]}>
        <planeGeometry attach="geometry" args={[1, 1, 1]} />
        <meshPhysicalMaterial attach="material" color="rgb(0, 0, 0)" />
      </mesh>
      <mesh
        geometry={nodes.Plane.geometry}
        position={[0, 0, 2]}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[1, 1, 1]}
      >
        <BackgroundParticles />
        <meshPhysicalMaterial
          normalMap={texture}
          attach="material"
          transmission={1}
          metalness={0.0}
          roughness={0.0}
          opacity={1}
          ior={1.5}
          thickness={0.1}
          color="white"
        />
      </mesh>
      <pointLight ref={lightRef} intensity={111} />
    </group>
  );
}



Since you mentioned that the ugly black appears in the top left corner, and since your light source’s position is dependent on the mouse’s position, it’s possible that certain angles or positions of the light are not sufficiently illuminating your geometry. This can result in black regions where the light doesn’t reach.

// Initialize default light position
lightRef.current.position.set(0, 0, 5);

// Update light position based on mouse movement within useFrame
useFrame(() => {
  var mouse = new THREE.Vector2(
    rawMouse.x - window.innerWidth / 2,
    rawMouse.y - window.innerHeight / 2,
  );
  lightRef.current.position.lerp(new THREE.Vector3(mouse.x / 100, -mouse.y / 100, 5), 0.1);
});

This change uses linear interpolation to smoothly update the light’s position based on mouse movement, ensuring the light does not jump to extreme positions that might cause parts of your mesh to be underlit.

i thought about that too, but that seems not to be the problem (i’ve tried multiple light sources and they do not make a difference). it’s as if the IOR value goes up the further u go from bottom right corner. also it’s fully transparent so light shouldn’t make a difference on the plane’s appearance in the first place?

also it appears to be in screen-space, somehow. i can rotate the camera and mesh and the black will be always in camera’s top left corner

what is this behaviour?

If you add VertexNormalHelper, do the normals point in the correct directions?

Also, does the size of the black effect change if you change ior and thickness?

i tried flipping normals in blender and it didn’t change anything. black effect doesn’t change with thickness or ior it’s very strange

anyway, using thicknessmap instead of normalmap i kind of got the effect i wanted, still not sure what was up with that black thing tho