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

Gizmo up vector #496

Merged
merged 4 commits into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .storybook/stories/GizmoHelper.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { array, boolean, color, number, select, withKnobs } from '@storybook/addon-knobs'
import * as React from 'react'
import { Vector3 } from 'three'
import { GizmoHelper, OrbitControls, useGLTF, GizmoViewcube, TrackballControls, GizmoViewport } from '../../src'
import { Setup } from '../Setup'

export default {
title: 'Gizmos/GizmoHelper',
component: GizmoHelper,
decorators: [
(storyFn) => (
<Setup controls={false} cameraPosition={new Vector3(0, 0, 10)}>
{storyFn()}
</Setup>
),
withKnobs,
],
}

const GizmoViewcubeStory = () => {
const { scene } = useGLTF('LittlestTokyo.glb')
const gizmo = select('gizmo', ['view cube', 'view port'], 'view cube', 'General')
const controls = select('controls', ['orbit', 'trackball'], 'orbit', 'General')

return (
<>
<primitive object={scene} scale={[0.01, 0.01, 0.01]} />
<GizmoHelper
alignment={select(
'alignment',
['top-left', 'top-right', 'bottom-right', 'bottom-left'],
'bottom-right',
'General'
)}
margin={[number('marginX', 80, {}, 'General'), number('marginY', 80, {}, 'General')]}
>
{gizmo === 'view cube' ? (
<GizmoViewcube
faces={array('faces', ['Right', 'Left', 'Top', 'Bottom', 'Front', 'Back'], '|', 'ViewCube')}
opacity={number('opacity', 1, { min: 0, max: 1, step: 0.1, range: true }, 'ViewCube')}
color={color('color', 'white', 'ViewCube')}
strokeColor={color('strokeColor', 'gray', 'ViewCube')}
textColor={color('textColor', 'black', 'ViewCube')}
hoverColor={color('hoverColor', 'lightgray', 'ViewCube')}
/>
) : (
<GizmoViewport
axisColors={[
color('colorX', 'red', 'ViewPort'),
color('colorY', 'green', 'ViewPort'),
color('colorZ', 'blue', 'ViewPort'),
]}
labelColor={color('labelColor', 'black', 'ViewPort')}
hideNegativeAxes={boolean('hideNegativeAxes', false, 'ViewPort')}
/>
)}
</GizmoHelper>

{controls === 'trackball' ? <TrackballControls makeDefault /> : <OrbitControls makeDefault />}
</>
)
}

export const DefaultStory = () => (
<React.Suspense fallback={null}>
<GizmoViewcubeStory />
</React.Suspense>
)

DefaultStory.storyName = 'Default'
47 changes: 0 additions & 47 deletions .storybook/stories/GizmoViewcube.stories.tsx

This file was deleted.

49 changes: 0 additions & 49 deletions .storybook/stories/GizmoViewport.stories.tsx

This file was deleted.

4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,11 +388,13 @@ Adds a `<Plane />` that always faces the camera.

#### GizmoHelper

[![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/gizmos-gizmohelper--default-story)

Used by widgets that visualize and control camera position.

Two example gizmos are included: GizmoViewport and GizmoViewcube, and `useGizmoContext` makes it easy to create your own.

Make sure to set the `makeDefault` prop on your controls, in that case you do not have to define the onTarget prop.
Make sure to set the `makeDefault` prop on your controls, in that case you do not have to define the onTarget and onUpdate props.

```jsx
<GizmoHelper
Expand Down
21 changes: 10 additions & 11 deletions src/core/GizmoHelper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ const matrix = new Matrix4()
const [q1, q2] = [new Quaternion(), new Quaternion()]
const target = new Vector3()
const targetPosition = new Vector3()
const targetQuaternion = new Quaternion()

type ControlsProto = { update(): void; target: THREE.Vector3 }

Expand Down Expand Up @@ -76,9 +75,7 @@ export const GizmoHelper = ({
radius.current = mainCamera.position.distanceTo(target)

// Rotate from current camera orientation
dummy.position.copy(target)
dummy.lookAt(mainCamera.position)
q1.copy(dummy.quaternion)
q1.copy(mainCamera.quaternion)

// To new current camera orientation
targetPosition.copy(direction).multiplyScalar(radius.current).add(target)
Expand All @@ -89,24 +86,26 @@ export const GizmoHelper = ({
}

const animateStep = (delta: number) => {
invalidate()
if (!animating.current) return

if (q1.angleTo(q2) < 0.01) {
animating.current = false
return
}

const step = delta * turnRate

// animate position by doing a slerp and then scaling the position on the unit sphere
q1.rotateTowards(q2, step)
// animate orientation
mainCamera.position.set(0, 0, 1).applyQuaternion(q1).multiplyScalar(radius.current).add(focusPoint.current)
mainCamera.up.set(0, 1, 0).applyQuaternion(q1).normalize()
mainCamera.quaternion.copy(q1)

// animate orientation
mainCamera.quaternion.rotateTowards(targetQuaternion, step)
mainCamera.updateProjectionMatrix()
if (onUpdate) onUpdate()
else if (defaultControls) defaultControls.update()

if (q1.angleTo(q2) < 0.01) {
animating.current = false
}
invalidate()
}

React.useEffect(() => {
Expand Down
10 changes: 5 additions & 5 deletions src/core/GizmoViewcube.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const FaceCube = (props: GenericProps) => {
e.stopPropagation()
setHover(null)
}
const handlePointerDown = (e: Event) => {
const handleClick = (e: Event) => {
e.stopPropagation()
tweenCamera(e.face.normal)
}
Expand All @@ -109,7 +109,7 @@ const FaceCube = (props: GenericProps) => {
raycast={raycast}
onPointerOut={handlePointerOut}
onPointerMove={handlePointerMove}
onPointerDown={props.onClick || handlePointerDown}
onClick={props.onClick || handleClick}
>
{[...Array(6)].map((_, index) => (
<FaceMaterial key={index} index={index} hover={hover === index} {...props} />
Expand All @@ -130,18 +130,18 @@ const EdgeCube = ({ onClick, dimensions, position, hoverColor = colors.hover }:
e.stopPropagation()
setHover(true)
}
const handlePointerDown = (e: Event) => {
const handleClick = (e: Event) => {
e.stopPropagation()
tweenCamera(position)
}
return (
<mesh
scale={1.1}
scale={1.01}
position={position}
raycast={raycast}
onPointerOver={handlePointerOver}
onPointerOut={handlePointerOut}
onPointerDown={onClick || handlePointerDown}
onClick={onClick || handleClick}
>
<meshBasicMaterial color={hover ? hoverColor : 'white'} transparent opacity={0.6} visible={hover} />
<boxGeometry args={dimensions} />
Expand Down