Closed rectalogic closed 4 years ago
Iām hoping to be able to overlay and synchronize a WebGLRenderer and a CSS3DRenderer to mix DOM elements with WebGL as an alternative to the current experimental Dom support https://github.com/react-spring/react-three-fiber/blob/master/readme.md#dom-experimental-web-only
Similar to what is described here http://learningthreejs.com/blog/2013/04/30/closing-the-gap-between-html-and-webgl/
I came up with this which is basically working but seems kind of klunky https://codesandbox.io/s/react-three-fiber-css3d-working-gxke6?file=/src/index.tsx
import React, { useRef, Fragment, useMemo, useEffect } from 'react'
import ReactDOM from 'react-dom'
import { Canvas, useFrame, useThree } from 'react-three-fiber/css3d'
import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer'
import './styles.css'
interface DOMObjectProps {
dom: React.RefObject<HTMLElement>
}
function DOMObject({ dom }: DOMObjectProps) {
const { scene } = useThree()
const ref = useRef<CSS3DObject | null>(null)
useFrame(() => (ref.current!.rotation.x = ref.current!.rotation.y += 0.01))
useEffect(() => {
ref.current = new CSS3DObject(dom.current)
scene.add(ref.current)
return () => scene.remove(ref.current)
}, [dom, scene])
return null
}
interface PortalProps {
children: React.ReactNode
}
function Portal({ children }: PortalProps) {
const root = useMemo(() => document.createElement('div'), [])
return ReactDOM.createPortal(<Fragment>{children}</Fragment>, root)
}
function World() {
const ref = useRef(null)
return (
<Fragment>
<Canvas camera={{ position: [0, 0, 15] }}>
<DOMObject dom={ref} />
</Canvas>
<Portal>
<div ref={ref}>hello</div>
</Portal>
</Fragment>
)
}
ReactDOM.render(<World />, document.getElementById('root'))
Thanks @rectalogic for your example, I'm also interested in a convenient solution for this. With the latest dependencies (react@17.0.0
, react-three-fiber@5.3.18
and three@0.125.2
) I can't get your example to work though, for me the DOMObject
function is never called. Have you continued working with this?
Hi, I'm having similar problem as @danieledler, after updating to the latest packages
"@react-three/drei": "^4.1.8",
"@react-three/fiber": "^6.0.16",
my code stopped working, I see two empty canvas in the DOM. 3Dgl renderer is working but the CSS renderer is missing.
Is css3D not working now with ^4.1.8? I am trying to import it with no luck
You don't need css3d for anything. dreis html component does everything it could do and more.
3d transforms: https://twitter.com/0xca0a/status/1398633764931178498
occlusion: https://twitter.com/0xca0a/status/1407758860203573251
there is no /css3d
render target any longer because you can now just exchange the renderer: <Canvas gl={css3dInstance}
or using the render function render(<App />, { gl: css3dInstance
but that would make little sense since <Html>
exists.
@drcmda thanks for the occlusion example!
I notice that while that does handle the case of the centroid of the 2D componentry being occluded -- it does not handle the occlusion of, say, a corner of the 2D HTML component. Is that something that is in the works?
that would be much harder to implement i think. css2drenderer to my knowledge has no occlusion at all though so i think it's still a step up.
I don't disagree with you -- it would be a lot more difficult. Personally for my use case, it is very helpful to have a "true occlusion."
I have a workaround for this issue, but it is a little hacky and requires using a rendering to a svg
html tag, with the foreignObject
tag inside.
Importantly, there is a lot of work to be done to allow it to use the same stylesheets as the rest of the application.
if its doable and you know the math would be nice to make a trial in drei, as a pr perhaps. the current implementation also went through a couple of them. the current one is really naive and it gives it away immediately that it's all smoke and mirrors.
Yeah totally agree. My current implementation is kind of ugly, but might be helpful for some limited cases. I'll see what I can come up with in the next week or so and get back to you.
On Thu, Jul 8, 2021, 6:31 PM ā @.***> wrote:
if its doable and you know the math would be nice to make a trial in drei, as a pr perhaps. the current implementation also went through a couple of them. the current one is really naive and it gives it away immediately that it's all smoke and mirrors.
ā You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/pmndrs/react-three-fiber/issues/366#issuecomment-876786443, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAPRLLN3TJ2ZNVI3UXVNEGDTWYRMHANCNFSM4MWYY4EA .
Hey,
on a similar note, shouln't it be possible to create our own CSS2DRenderer
, attach it to the canvas element and call it in a custom useFrame
like this:
// Takes over the render-loop, the user has the responsibility to render
useFrame(({ gl, scene, camera }) => {
gl.render(scene, camera)
labelRenderer.render(scene, camera)
}, 1)
with
const labelRenderer = new CSS2DRenderer({ element: canvasDOM })
labelRenderer.domElement.style.position = 'absolute'
labelRenderer.domElement.style.top = '0px'
setLabelRenderer(labelRenderer)
where canvasDOM is the ref passed to <Canvas>
Any hint, why this isn't working?
i forgot how to use that class, but yes, you could render it in useframe. thought again, there is a very powerful html renderer in drei that does everything css2d could, and tons more. in react having to mess with imperative createelement just feels off. but either way, it's probably just a set up issue, "canvasDOM" being the wrong element or something like that.
i forgot how to use that class, but yes, you could render it in useframe. thought again, there is a very powerful html renderer in drei that does everything css2d could, and tons more. in react having to mess with imperative createelement just feels off. but either way, it's probably just a set up issue, "canvasDOM" being the wrong element or something like that.
Thanks for the fast reply!
You're right. I am just trying to step-by-step port some old code to react-three-fiber and don't wanna do it all in one go. Hence I thought I could get everything "up and running" without changing the structure much at first.
Will look into it some more and report my results here :)
You don't need css3d for anything. dreis html component does everything it could do and more.
3d transforms: https://twitter.com/0xca0a/status/1398633764931178498
occlusion: https://twitter.com/0xca0a/status/1407758860203573251
there is no
/css3d
render target any longer because you can now just exchange the renderer:<Canvas gl={css3dInstance}
or using the render functionrender(<App />, { gl: css3dInstance
but that would make little sense since<Html>
exists.
man you saved my day, thank you!!!
An example of using the css3d renderer would be useful. https://github.com/react-spring/react-three-fiber/blob/master/examples/src/demos/dev/CSS3DRenderer.js is empty
I expected it would be something like this, but not sure how to properly use CSS3DObject.