Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raycast update #33

Merged
merged 25 commits into from
Apr 1, 2021
Merged

Raycast update #33

merged 25 commits into from
Apr 1, 2021

Conversation

SaFrMo
Copy link
Contributor

@SaFrMo SaFrMo commented Mar 23, 2021

Copied from #31:

Raycaster-first

Sometimes I want to raycast against everything in a crowded scene - in this case, I'd rather write a single raycaster's pointerEnter and pointerLeave functions than those of all the objects in the scene. To accomplish this, we could add a Raycaster component:

<Camera>
  <Raycaster @pointerEnter="onEnter" @pointerLeave="onLeave"/>
</Camera>
export default {
  methods: {
    onEnter(intersections) {
      console.log(intersections)
    },
    onLeave(inactiveIntersections){ 
      console.log(inactiveIntersections)
    }
  }
}

This would raycast against everything (raycaster.intersectObjects(scene.children)) and fire appropriate callbacks when pointer interactions start and end. We could also include an optional prop targetObjects if the user wants to specify which objects to target if they don't want all of them.

Object-first

I'm finding the <Renderer mouse-over> and mesh :onHover prop a little confusing - maybe we could do something like this:

  • Add pointerEnter and pointerLeave props to all Meshes
  • In a mesh's initialization, if either pointerEnter or pointerLeave are defined, check for this.three.raycaster.
    • If one is defined, add the mesh to the list of target objects the raycaster can intersect.
    • If one is not defined, tell this.three to create one (a new method like this.three.initializeRaycaster()), then add the mesh to the list of target objects.

From there, three.raycaster can handle calling events on meshes when the pointer enters or leaves them. This way we don't need any Renderer-level awareness of raycasting and the pointerEnter/pointerLeave events more closely match the Raycast component above (plus they're more clearly named for handling non-mouse inputs).

TODO

  • Optimize
  • Click events
  • Raycaster-first
  • Object-first
  • Add onPointerLeave callback if pointer leaves mouse_move_element
  • Code formatting
  • Switch all touch events to placeholders
  • BUG: Multiple trois instances on a page all activate raycaster. Scope to current trois renderer
  • BUG: Test overlapping z-indexes - onPointer... callbacks only check the object in question, so we may get false positives hovering a mesh that's behind another. Possible fix: pass list of objects to check to pointerObjects prop or similar?

Out of scope

Touch events will be out of the scope of this PR - I'll leave in placeholders (// TODO: touch) where they'll probably fit in.

@SaFrMo SaFrMo marked this pull request as ready for review March 26, 2021 17:38
@SaFrMo
Copy link
Contributor Author

SaFrMo commented Mar 26, 2021

Ready for review! A couple big changes in this PR, so here are some notes:

Raycaster component

See here for an example (source).

<Camera>
    <!-- if the Raycaster is a child of a camera, use that camera as the ray origin -->
    <Raycaster 
        :onPointerOver="callback that accepts an array of all new intersections, like onMouseEnter" 
        :onPointerLeave="callback that accepts an array of all newly-ended intersections, like onMouseLeave" 
        :onPointerOver="callback that accepts array of all current intersections"
        :onClick="callback that accepts array of currently intersected objects"

        :onBeforeRender="callback that fires every frame - optional, accepts the created raycaster. setting this property assumes the user is implementing all raycaster functionality and nullifies all other props and built-in functionality."
        :scene="THREE scene - optional, defaults to current scene"
        :camera="camera - optional, defaults to parent camera"
        :intersects="array of objects to check for intersections - optional, casts against all scene children by default"
        />
</Camera>

Object3D additions

See here for an example (source). New Object3D props (all optional):

  • onPointerEnter: Function, accepts an object with properties { object, intersect }, containing the object being hovered and the actual intersection.
  • onPointerOver: Function, accepts an object with properties { object, intersect }, containing the object being hovered and the actual intersection.
  • onPointerLeave: : Function, accepts an object with properties { object }, containing the object no longer being hovered.
  • onClick: Function, accepts an object with properties { object, intersect }, containing the object being clicked and the actual intersection.
  • usePointerEvents: Boolean, default false. If set to true, this object will emit pointerEnter, pointerOver, pointerLeave, and click events, all with the same arguments as the props. Function props are preferred over events to avoid the extra overhead of event emitting, but this option is provided if the user prefers events.
  • pointerObjects: Array of objects to cast against. Defaults to just the given object. Set to true (ie, <Object3D pointer-objects>) to cast against all scene children.

Deprecations and other notes

  • mouseMove, mouseRaycast, mouseOver, and click are all no longer used on the renderer.
  • usePointer on the Renderer is true by default. Switch to false to prevent mouse event handling on the renderer element. Example:
    <!-- Do not listen to mousemove events - marginal performance improvement -->
    <Renderer :use-pointer="false">

@klevron
Copy link
Member

klevron commented Apr 1, 2021

Thanks Sander for your work, really helpful

@klevron klevron merged commit a583889 into troisjs:master Apr 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants