question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Raycaster ignores displacement maps and their effct on geometries

See original GitHub issue

Describe the bug

I’m not sure if this is a bug or the expected behavior, but according to the Three.js manual, “a displacement map affects the position of the mesh’s vertices” and “the displaced vertices can cast shadows, block other objects, and otherwise act as real geometry”, so based on that, they should affect the results produced by a Raycaster. However, they do not.

To Reproduce

Steps to reproduce the behavior:

  1. Create a basic Three.js setup
  2. Rotate the camera around an object that is using a displacement map
  3. Use Raycaster to cast a ray towards the object
  4. Notice that the logged distance to the intersect point with the object doesn’t change

Code

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      body {margin: 0;}
    </style>
  </head>
  <body>
    <script type="importmap">
      {
        "imports":
        {
          "three": "http://localhost:8080/three.module.js",
          "ArcballControls": "http://localhost:8080/ArcballControls.js"
        }
      }
    </script>
    <script type="module">
      import * as THREE from "three";
      import {ArcballControls} from "ArcballControls";
      var scene, camera, light, renderer, earth, controls, reqid, paused = false;
      function createcontrols()
      {
        controls = new ArcballControls(camera, renderer.domElement, scene);
        controls.addEventListener("change", function(e) {renderer.render(scene, camera); controls.update();});
      };
      function create()
      {
        renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
        camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100);
        camera.position.set(0, 0, 1.75);
        light = new THREE.AmbientLight("rgb(255, 255, 255)");
        light.position.copy(camera.position);
        var geometry = new THREE.SphereGeometry(1, 360, 180);
        var material = new THREE.MeshPhongMaterial();
        material.map = new THREE.TextureLoader().load("http://localhost:8080/Earth.png");
        material.displacementMap = new THREE.TextureLoader().load("http://localhost:8080/Earth - Height.png");
        material.displacementScale = 0.002 * 99;
        earth = new THREE.Mesh(geometry, material);
        scene = new THREE.Scene();
        scene.add(camera);
        scene.add(light);
        scene.add(earth);
        createcontrols();
        document.addEventListener("keyup", function(e)
        {
          switch (e.code)
          {
            case "KeyP": console.log("P"); paused = !paused; if (!paused) {animate();} else {stagnate();}; break;
          };
        }, {passive: false});
      };
      function raycast()
      {
        var cameradirection = new THREE.Vector3();
        camera.getWorldDirection(cameradirection);
        cameradirection.normalize();
        var cameraorigin = new THREE.Vector3();
        camera.getWorldPosition(cameraorigin);
        var raycaster = new THREE.Raycaster(cameraorigin, cameradirection);
        var intersects = raycaster.intersectObjects([earth], false);
        if (intersects.length) {console.log(intersects[0].distance);};
      };
      function animate()
      {
        if (paused) {return;};
        requestAnimationFrame(animate);
        earth.rotation.y += 0.01;
        renderer.render(scene, camera);
        raycast();
      };
      function stagnate()
      {
        if (!paused) {return;};
        cancelAnimationFrame(reqid);
      };
      create();
      animate();
    </script>
  </body>
</html>

Live example

None

Expected behavior

I expect Raycaster to react to the effects that the displacement map “should” have on the geometry of the object (and not only on its material, according to the manual), and log different distances to the intersection point with the object, based on the “height of the terrain” being displaced. I intentionally set a considerable displacement scale in the code above to make it even more obvious. My actual usage scenario is preventing the camera to approach closer than the minimum distance to an object, but according to the altitudes / terrain on the object’s surface. Let me know if Raycaster ignoring displacement maps is a bug or it’s something expected to happen due to the displacement maps being just as “fake” as the bump maps (i.e. not affecting the real geometry of the object).

Screenshots

None

Platform:

  • Device: Desktop
  • OS: Windows 10
  • Browser: Chrome, Edge WebView2 via the WebView plugin for Rainmeter
  • Three.js version: r.140, r.143

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:16 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
LeviPesincommented, Aug 10, 2022

Maybe you shouldn’t use the displacement map but instead just change the geometry based on the map data?

1reaction
Yincognytocommented, Aug 16, 2022

It is better because it avoids creating a new object in loop […] you can create two vectors at the start and then just do something like posval.fromBufferAtribute(geometry.attributes.position, posidx); dirval.fromBufferAttribute(geometry.attributes.normal, posidx);.

You’re right - .fromBufferAttribute() does indeed simplify things, I will use that instead, thanks! Avoiding creating reusable entities is a good advice as well, unfortunately it’s something that I personally only think of once the job of figuring out how to do something (i.e. the “hard” part) is done, since the former almost always needs the latter in order to get something out of it.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Raycaster ignores displacement maps and their effct on ...
I expect Raycaster to react to the effects that the displacement map "should" have on the geometry of the object (and not only...
Read more >
How to raycast plane with displacement map - three.js forum
Raycast ignores the displacement map scale and the ray intersects the plane as the scale has not been set at all.
Read more >
How displacement maps work and how to optimize them in V ...
Vray displacement maps is used to add complex geometries on a surface without having to model them manually which is a very powerful...
Read more >
VRayDisplacementMod - V-Ray for 3ds Max - Chaos Help
Displacement mapping is a technique for adding detail to your scene ... The V-Ray Displacement Modifier adds displacement to geometry.
Read more >
Softimage User Guide: Displacement Maps - Autodesk
A displacement map is a scalar map that displaces a surface at each point in the direction of the object's normal: the geometry...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found