Override raycasting mesh

Hi there, can we override how an object handles raycasts?

For context, I have a shader-deformed mesh and want to be able to approximately raycast against it. I have a low poly mesh representation for this but I don’t know how to make the raycasting system actually use it.

Right now it uses the actual mesh (or the mesh-bvh-processed mesh?) which is not close enough to the drawn deformed mesh.

Hi Krizzl0r!

To override how an object handles raycasts in Needle Engine, especially for a shader-deformed mesh, you can create a custom raycaster by extending the existing raycaster classes. Since you want to approximate raycasting against a low poly representation instead of the deformed mesh, follow these steps:

  1. Extend the Raycaster class: Create a new class that extends the Raycaster or ObjectRaycaster. Override the performRaycast method to implement your custom logic.

  2. Implement the custom raycasting logic: In your overridden method, check against your low poly representation instead of the original deformed mesh.

  3. Use the new raycaster: Attach your new raycaster to the objects or cameras that should utilize it for raycasting.

Here’s a simplified approach in code:

import { Raycaster, Mesh, Object3D, Intersection } from "three";
import { RaycastOptions } from "././engine/engine_physics.js"; // Ensure correct path

class CustomRaycaster extends Raycaster {
    performRaycast(opts: RaycastOptions | null = null): Intersection[] | null {
        opts = opts || new RaycastOptions();

        // Replace this with your logic to get the low poly mesh for raycasting
        const lowPolyMesh = this.getLowPolyMesh(this.gameObject);

        if (lowPolyMesh) {
            return super.intersectObject(lowPolyMesh, false, opts.results); // Raycast against low poly
        }

        return null;
    }

    private getLowPolyMesh(object: Object3D): Mesh | null {
        // Logic to return the low poly representation of the object
        // This may depend on your object structure and how it's stored
        return null; // Replace with actual logic
    }
}

// Usage: Attach CustomRaycaster to your GameObject instead of the default Raycaster
const customRaycaster = new CustomRaycaster();
myGameObject.add(customRaycaster);

Make sure to replace the getLowPolyMesh method with your actual logic to fetch or create the low poly representation of the mesh. This will allow your raycasting to use the simpler geometry, closely matching the shader-deformed appearance.

If you need more specific guidance or encounter difficulties, please provide more context about your current implementation or structure.

1 replies left - Get a PRO license for more AI replies.
thread_LwJCpn5qOE05mEdgDyvl872J
Reply to this message to continue the conversation

Could you clarify what you mean by how an object handles raycasts?

Are you using a prebuilt component? Otherwise you can just configure your custom mesh to the NoRaycast layer in Unity and hide the mesh renderer on your low poly mesh (so it’s not rendered but raycast against in the scene when you do a physics raycast).

And yes all raycasts automatically use the BVH structures for performance reasons.

Thanks for the swift reply!

Splitting it into two objects would be doable, yes. Let me explain though what I have in mind:

In threejs you can override the Object3D.raycast function to change the object’s reaction to a raycast. This can be used to e.g. switch to simpler geometry dynamically or do something else entirely :slight_smile:

I need the same kind of behaviour working in needle. I imagine e.g. an interface which can be implemented by components. Which if present always gets higher prio than whatever the default raycasting engine does.

In the meantime I managed to force usage of my raycasting method:

	onBeforeRender(renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, material: Material, group: Group): void {
		this.raycast = this.myraycast;
		this["acceleratedRaycast"] = this.myraycast; // overrides the bvh implementation
	}

	public myraycast = (raycaster: Raycaster, intersects: Intersection[]) => {
		// raycast against low poly mesh here

Works but is an ugly way of course.

Thinking further about it, I guess it would suffice to opt out of the bvh-acceleration somehow.
Like IRaycastOptions.useAcceleratedRaycast on a per-object basis. Then it’d fall back to the default raycast implementation which can easily be overriden.

We’re still using the three.js methods - e.g. Raycaster.intersectObject in all pathes - so I think you can do just what you described by overriding/wrapping the intersectObject method which you can use to customize the object or return an empty result to skip objects completely for example.

Thanks, I’ll look into that.

@krizzl0r did you try my suggestion or find another solution?

@krizzl0r while you’re active here :wink: would be great to get your feedback here

Thanks for the reminder.

I kept the hacky override (this["acceleratedRaycast"] = this.myraycast;) because it worked and I had to shift my focus elsewhere.
So I cannot really speak about if using Raycaster.intersectObject would have worked too in my case :confused:

Ok got it.

Anyways: here’s a short example

import { Gizmos } from '@needle-tools/engine';
import { Raycaster } from 'three';

export function patchRaycaster() {
  const method = Raycaster.prototype.intersectObject;
  /** @ts-ignore */
  Raycaster.prototype.intersectObject = function (...args) {
    const object = args[0];
    const intersectionsBefore = args[2]?.length || 0;
    const res = method?.call(this, ...args);
    if (res.length > intersectionsBefore) {
      console.log('INTERSECT WITH ' + object.name, res);
    }
    return res;
  };
}