-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Panning / Orbit Controls #27
Comments
I would recommend three js controls for sure. There exist a couple, orbit is just one of them. It sucks that three isn't fully modular still, so i just copy stuff from this PR: mrdoob/three.js#15832 Controls need a reference to the camera, you can either create your own camera or use the default camera and fetch it via useThree, and it needs to be updated every frame, for this you should useRender. So basically: import { apply, Canvas, useRender, useThree } from 'react-three-fiber'
import { OrbitControls } from '../resources/controls/OrbitControls'
// Make OrbitControls known as <orbitControls />
apply({ OrbitControls })
function Controls(props) {
const ref = useRef()
const { camera } = useThree()
useRender(() => ref.current.obj.update())
return <orbitControls ref={ref} args={[camera]} {...props} />
}
function App() {
return (
<div style={{ width: '100%', height: '100%', position: 'absolute' }}>
<Canvas camera={{ position: [0, 0, 300] }}>
<Controls />
<group position={[x, y, 0]}>
{bars.map(b => (
<Bar start={b[0]} end={b[1]} yIndex={b[2]} />
))}
</group>
</Canvas>
</div>
)
} Orbit has lots of options: https://threejs.org/docs/index.html#examples/controls/OrbitControls you can switch off rotation and zoom so that only pan is allowed. |
Awesome, thanks! I've managed to get a few different control systems working. It doesn't appear to be doing it with your example in CodeSandbox. I have the exact same OrbitControl code so maybe it has something to do with the default camera? I'll play around with setting up a custom camera. function Controls(props) {
const ref = useRef()
const { camera } = useThree()
useRender(() => {
console.log('Controls -> useRender -> camera', camera)
ref.current.obj.update()
})
return <orbitControls ref={ref} args={[camera]} {...props} />
}
function App() {
return (
<div style={{ width: "100%", height: "100%", position: "absolute" }}>
<Canvas camera={{ position: [0, 0, 300] }}>
<Controls />
<group>
{bars.map((b,i) => <Bar key={i} start={b[0]} end={b[1]} yIndex={b[2]} />)}
</group>
</Canvas>
</div>
);
} |
Nope didn't seem to make a difference. Any ideas? function CanvasContent() {
const camera = useRef()
const controls = useRef()
const { size, setDefaultCamera } = useThree()
useEffect(() => void setDefaultCamera(camera.current), [])
useRender(() => {
console.log('cam', camera.current)
controls.current.obj.update()
})
return (
<group>
<perspectiveCamera
ref={camera}
aspect={size.width / size.height}
radius={(size.width + size.height) / 4}
fov={55}
position={[0, 0, 300]}
onUpdate={self => self.updateProjectionMatrix()}
/>
{camera.current && (
<group>
<orbitControls ref={controls} args={[camera.current]} enableDamping dampingFactor={0.1} rotateSpeed={0.1} />
<group>
{bars.map((b, i) => <Bar key={i} start={b[0]} end={b[1]} yIndex={b[2]} />)}
</group>
</group>
)}
</group>
)
}
function App() {
return (
<div style={{ width: "100%", height: "100%", position: "absolute" }}>
<Canvas>
<CanvasContent />
</Canvas>
</div>
);
} |
I haven't tried the code i posted, but doing it now ... and seems fine: https://codesandbox.io/s/387z7o2zrq it doesn't seem to pan up/down, but i think that is related to how these controls work, probably they need a specific up vector or something like that, it's purely threejs at that point. As for NaN, controls write into the camera, if they are set up wrong or are missing any critical data, they can screw up the camera. Must be a reason somewhere why it's doing that. If you put that into a sandbox, i can investigate - would also be interesting to me if it's three-fibers fault. |
Code sandbox is failing to load dependencies for me atm but I'm sure this is working https://codesandbox.io/s/14r8y3k144 I haven't been able to test the code above in sandbox, but strangely I'm having the same problems locally. The only difference I can possibly think of is the wrapper div |
Ok, the |
your box worked for me, i upgraded three-fiber to latest and changed three/src/Three to just 'three' https://codesandbox.io/s/o5mj1l8y0z But i can pan the contents.
The expanding happens when the container doesn't have a size. needs to be relative/absolute to something and have a width/height, percentages, fixed values, everything goes. Otherwise the resize observer will start to push the bounds. |
Ok, got it working thanks! Interestingly you need to add the following css otherwise the orbit / pan breaks if any parent container has html, body {
height: 100%;
width: 100%;
} |
I don't know yet - you think it's a good idea to have a resize observer inside the canvas? I can understand it might look like magic, and usually that's not a good thing. On the other hand, three canvas isn't responsive, if you resize the browser the view stays put and you would have to await resize events (which isn't enough if it's inside a dynamically sized div) and update the context renderer manually. |
Yeah, I had a bit of trouble with it at first - but in saying that I would love things to resize automatically, and would end up trying to implement it myself anyway. I've been trying to think if there's a way to stop the auto-expanding from inside Perhaps you could add an |
that would be an option. maybe also cutting out the resize-observer-polyfill and letting users decide to include that on their own. it's just additional weight if it's running in evergreen browsers. |
Yeah, that could work. Say the polyfill was included, another approach would be to just throw an error if the container is dimensionless. It's not that it's a hard issue to fix, but because you don't know that If you just say |
Please help! Here's the code I wrote: import {
DodecahedronBufferGeometry, EdgesGeometry,
LineSegments, LineBasicMaterial
} from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import React, { useRef } from 'react'
import { Canvas, extend, useThree, useRender } from 'react-three-fiber'
const geometry = new DodecahedronBufferGeometry(1, 1)
const edges = new EdgesGeometry(geometry)
const lines = new LineSegments(edges, new LineBasicMaterial({ color: 'red' }))
extend({ OrbitControls })
const Sphere = () => {
// Setup OrbitControls
const { camera } = useThree()
const ref = useRef()
useRender(() => ref.current.obj.update())
return (
<Canvas>
<orbitControls args={[camera]} ref={ref} />
<primitive object={lines} />
</Canvas>
)
}
export default Sphere What should I do? |
useThree is context based, it doesn't work outside of canvas, plus, you can have multiple canvases. best wrap it into a component, here's an easy example: https://codesandbox.io/s/xvvn4vxqnz |
Thank you @drcmda for help! Now it works. I didn't know that The code above works pretty fine: import {
DodecahedronBufferGeometry, EdgesGeometry,
LineSegments, LineBasicMaterial
} from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import React, { useRef } from 'react'
import { Canvas, extend, useThree, useRender } from 'react-three-fiber'
const geometry = new DodecahedronBufferGeometry(1, 1)
const edges = new EdgesGeometry(geometry)
const lines = new LineSegments(edges, new LineBasicMaterial({ color: 'red' }))
extend({ OrbitControls })
const Model = () => <primitive object={lines} />
const Controls = props => {
const { camera } = useThree()
const controls = useRef()
useRender(() => controls.current && controls.current.update())
return <orbitControls ref={controls} args={[camera]} {...props} />
}
const Sphere = () => {
return (
<Canvas>
<Controls enableDamping rotateSpeed={0.3} dampingFactor={0.1} />
<Model />
</Canvas>
)
}
export default Sphere |
seems that useRender is not anymore available, how to use orbitcontrols in latest v4 version? |
You need |
I needed to pass the
This article helped https://codeworkshop.dev/blog/2020-04-03-adding-orbit-controls-to-react-three-fiber/ |
I'm trying to implement a panning system on scroll events, and I have managed to get something working but it appears I've done it in the slowest way possible.
I've noticed you're using
orbitalControls
here (https://codesandbox.io/embed/mo0xrqrj79) and I'm trying to jam it into my system with little success. Are you able to explain a little how that all works?It looks like the orbital controls tell the renderer how to position the camera, and you need to use useRender to tell the objects to rerender, and. Is that correct?
Here's my very slow attempt a panning (sorry, I couldn't get it rendering correctly on CodeSandbox)
The text was updated successfully, but these errors were encountered: