pmndrs / drei Goto Github PK
View Code? Open in Web Editor NEW๐ฅ useful helpers for react-three-fiber
Home Page: https://drei.pmnd.rs/
License: MIT License
๐ฅ useful helpers for react-three-fiber
Home Page: https://drei.pmnd.rs/
License: MIT License
Hi,
I discovered a bug that should be a quick fix. In the main MeshWobbleMaterial example (link: https://codesandbox.io/s/r3f-sky-g5373), with versions past 0.0.67 the following error occurs:
Class constructor WobbleMaterialImpl cannot be invoked without 'new'
This error can be easily reproduced in that codesandbox by switching drei to version 0.0.68
I believe this is probably caused by a change in the constructor when MeshDistortMaterial was added as that has the same error and I think was possibly added at that version.
Thanks and let me know if you need any more info.
While all version of drei <= 0.32 work with Server Side Rendering, all verion >= 0.33 fail in Gatsby (and I supposed most Server Side Rendering solutions) with this error:
failed Building static HTML for pages - 10.964s
ERROR #95312
"document" is not available during server-side rendering.
See our docs page for more info on this error: https://gatsby.dev/debug-html
> 1 | import _inheritsLoose from '@babel/runtime/helpers/inheritsLoose';
| ^
2 | import { createContext, forwardRef, createElement, Component, Fragment } from 'react';
3 | import createCache from '@emotion/cache';
4 | import { getRegisteredStyles, insertStyles } from '@emotion/utils';
Error: WebpackError: ReferenceError: document is not defined
- core.esm.js:1
[@emotion-core-npm-10.0.28-490246e9e8-2.zip]/[@emotion]/core/dist/core.esm.js:1:1
This seems to be related to the introduction of troika
, I think troika uses document
with no checks, failing on server side.
I'm having trouble importing this module for code that runs both on the server as well as in the browser (through a webpack bundle).
I'm imorting things like this:
import { HTML } from "drei";
Which results in an error:
node_modules\three\examples\jsm\controls\OrbitControls.js:10
import {
SyntaxError: Unexpected token {
Any way to import this library in node without it resulting in errors?
I'm trying to move a 2d plane with clickable objects.
Everything works fine with MapControls
, but if I start panning when the cursor is over an object a click event is triggered when the mouse is released.
Here's a sandbox to show the problem. The black objects are clickable: try to move the map starting from one of them and watch the console.
Do you think it's possible to prevent the click event from firing up if the camera has moved?
Is it possible to apply the StandardEffect to a specific mesh or group? I'm trying to apply the bloom effect to a specific item in a scene.
We could move all the examples from codesandbox to a storybook hosted on netlify, or a maybe even a cra.
On one hand it would be a nice way to collect examples, on the other it would give a good dev env.
Hi! So, everybody who develops r3f things wants to share videos, but its either screen-grabs or quicktime, which is not good, and hard to loop.
So i thought it might be a great idea to do a GIF recorder with r3f. Or, lets say, generative art tool.
I did this with ccapture, which is working, but im not sure how to better implement that all yet.
There are 3 things to improve, which im having hard times yet, but i decided i create this issue, and see if someone wants this kind of tool at all :)
playhead
accessible from components, usually 0..1 range value, used to make loop, usePlayhead mb? Will something like this work?import { useThree } from 'react-three-fiber'
export function usePlayhead( duration) {
const { clock } = useThree()
return [clock.elapsedTime%duration]
}
here is current code of the "tool", its really simple, and mb you can find that useful.
import ReactDOM from 'react-dom'
import React, { useRef, useState, Suspense } from 'react'
import { Canvas, useFrame, extend, useThree} from 'react-three-fiber'
import ccapture from "ccapture.js";
const SETTINGS = {
duration: 2,
}
const capturer = new CCapture({
format: "webm",
framerate: 25,
verbose: true,
// motionBlurFrames: 6
});
function Recorder() {
let shouldRecord = false;
let isRecording = false;
let prevPlayhead = 0;
document.onkeyup = function(e) {
if (e.which == 82) { // press R to start recording
alert("recording now");
shouldRecord = true;
}
};
useFrame((state) => {
let currentPlayhead = state.clock.getElapsedTime()%SETTINGS.duration;
if(isRecording && currentPlayhead<prevPlayhead){
shouldRecord = false;
isRecording = false;
capturer.stop();
capturer.save();
}
if(!isRecording && shouldRecord && currentPlayhead<prevPlayhead){
isRecording = true;
capturer.start();
}
if(isRecording){
capturer.capture(state.gl.domElement)
}
prevPlayhead = currentPlayhead
})
return (
<group dispose={null}>
</group>
)
}
function Box(props) {
const ref = useRef()
useFrame(() => (ref.current.rotation.x = ref.current.rotation.y += 0.01))
return (
<mesh
ref={ref}
{...props}
>
<boxBufferGeometry attach="geometry" args={[1,1,1]} />
<meshBasicMaterial attach="material" color={'hotpink'} />
</mesh>
)
}
ReactDOM.render(
<Canvas colorManagement>
<Box />
<Recorder />
</Canvas>,
document.getElementById('root')
)
I have created an implementation for DeviceOrientationControls and have created a PR #66 . It might be useful for others and is one less controller missing from Three.
Hi,
Thank you for this library !
I was wondering what is the way to start/stop audio with PositionalAudio?
Here is my code :
const Audio = (props) => {
return (
<mesh {...props}>
<boxBufferGeometry attach="geometry" />
<meshBasicMaterial attach="material" color="hotpink" />
<PositionalAudio url={props.url} distance={0.5} loop={false} />
</mesh>
)
}
export default Audio
I have the following node:
<Text
anchorX="center"
anchorY="middle"
fontSize={0.8 * initialRadius}
color="black"
font={buildUrl("/fonts/Roboto-Bold.ttf")}
>
{props.textLabel}
</Text>
When the text changes I only see the first character of the new text appearing. The other ones are invisible, the character is still positioned as if the other characters would be present.
When adding a key property to the Text element with the contents of the props.textLabel this issue is resolved. However, I assume this is some kind of a bug and changing the children text should update the text without having to set a key
.
Example:
The purple token text has been updated from B
to asdas
It would be nice if the doco for the scaleFactor prop of the HTML component mentioned that the HTML element is also scaled based on the distance to a PerspectiveCamera, but not for an OrthographicCamera or if scaleFactor is undefined.
Reminder to myself to add a full-size background plane component.
https://gist.github.com/pfreema1/091b088481deca42b88d3f83f13cf1b8
mode
prop that handles the side effect ( control.setMode(mode) )disableControls
(needs a better name) prop that disables controls when interacting with the TransformControlsconst orbitControls = useRef()
...
<TransformControls
mode={"scale"}
disableControls={orbitControls}
>
...
</TransformControls>
<OrbitControls ref={orbitControls} />
These are all typical cases and I don't see any reason not to add them
Based on the demo: https://codesandbox.io/s/r3f-drei-transformcontrols-uvqn6?file=/src/index.js:496-526
When importing drei in an app that renders with SSR, an error is thrown as troika-3d-text
has multiple references to the document
object. This can be circumvented by loading components that require this using lazy or dynamic imports, but unfortunately, importing anything from drei
will bring in troika-3d-text
, so it is impossible to, for example, use the awesome <HTML />
component for a loading state for the modules we want to lazy load that contain these document
references.
Here is the full error:
Server Error
ReferenceError: document is not defined
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Call Stack
<unknown>
file:///Users/me/www/cdb/node_modules/troika-3d-text/dist/textmesh-standalone.umd.js (4285:16)
<unknown>
file:///Users/me/www/cdb/node_modules/troika-3d-text/dist/textmesh-standalone.umd.js (2:66)
Object.<anonymous>
file:///Users/me/www/cdb/node_modules/troika-3d-text/dist/textmesh-standalone.umd.js (5:2)
Module._compile
internal/modules/cjs/loader.js (955:30)
Object.Module._extensions..js
internal/modules/cjs/loader.js (991:10)
Module.load
internal/modules/cjs/loader.js (811:32)
Function.Module._load
internal/modules/cjs/loader.js (723:14)
Module.require
internal/modules/cjs/loader.js (848:19)
require
internal/modules/cjs/helpers.js (74:18)
Object.troika-3d-text/dist/textmesh-standalone.umd
webpack:///external%20%22troika-3d-text/dist/textmesh-standalone.umd%22 (1:0)
__webpack_require__
webpack:///webpack/bootstrap (27:0)
Object../node_modules/drei/dist/index.cjs.js
node_modules/drei/dist/index.cjs.js (19:29)
__webpack_require__
webpack:///webpack/bootstrap (27:0)
Module../src/pages/index.tsx
file:///Users/me/www/cdb/.next/server/static/development/pages/index.js (55469:62)
__webpack_require__
webpack:///webpack/bootstrap (27:0)
Object.3
file:///Users/me/www/cdb/.next/server/static/development/pages/index.js (55642:18)
We added DeviceOrientationControls in #66 but THREE.DeviceOrientationControls doesn't dispatch a change event:
https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/DeviceOrientationControls.js
Same for FlyControls ( being added in #64 )
https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/FlyControls.js
Compare to OrbitControls
https://github.com/mrdoob/three.js/blob/b5c272cf408cb33153190fa715d81581bd95ee47/examples/jsm/controls/OrbitControls.js#L266
If we want to keep consistency between all controls, we would need to either open an issue or PR on three.
Hi,
thanks for the effort and very nice utilities.
My team and I have implemented fly controls and we would like to submit a pull request, can we?
Thank you
I tried whipping up an AudioAnalyser demo using ( from this discussion pmndrs/react-three-fiber#520 ) but there seems to be a problem accessing the ref
Sandbox here: https://codesandbox.io/s/r3f-audo-analyser-cmieg
I had to work around it by checking in useFrame if the ref was defined:
useFrame(() => {
if (analyser.current) {
const data = analyser.current.getAverageFrequency();
...
} else if (sound.current) {
analyser.current = new THREE.AudioAnalyser(sound.current, 32);
}
});
This smells really bad, I'm not sure if I'm missing something
I am experiencing this issue with create-react-app when building for production:
Creating an optimized production build...
Failed to compile.
./node_modules/drei/dist/index.js
Attempted import error: 'addAfterEffect' is not exported from 'react-three-fiber'.
"drei": "0.0.63",
"react-three-fiber": "4.2.12",
"three": "0.118.3",
I tried something like this:
<TransformControls position={props.position} ref={ref}>
<mesh position={props.position}>
{/* geometry and material omitted for brevity */}
</mesh>
</TransformControls>
and fire a callback like so:
ref.current.addEventListener('dragging-changed', function(e) {
props.onChange(ref.current.object.position);
});
but when the position is updated and the view re-rendered, the mesh and the UI helper will jump away for the same distance of the last drag. My gut feeling is that there are some internal offset stored by the control which breaks this controlled pattern.
FWIW: Next.js kept complaining with cannot use import statement outside a module
. I had to include three and drei in the transpile modules array to get OrbitControls to work:
next.config.js
const withTM = require('next-transpile-modules')(['three', 'drei'])
module.exports =withTM()
Hope this helps someone else.
Hello hello!
Don't know if this is too small / uncommon to warrant inclusion, but I've often used the following to quickly set the scene's environment to an HDRI map.
import { useEffect } from 'react'
import { UnsignedByteType, PMREMGenerator } from 'three'
import { useThree } from 'react-three-fiber'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'
// or pass as a prop / import from project assets..
const HDRI = 'https://hdrihaven.com/files/hdris/royal_esplanade_1k.hdr'
export default () => {
const { gl, scene } = useThree()
const pmremGenerator = new PMREMGenerator(gl)
const loader = new RGBELoader()
loader.setDataType(UnsignedByteType)
pmremGenerator.compileEquirectangularShader()
useEffect(() => {
loader.load(HDRI, texture => {
const envMap = pmremGenerator.fromEquirectangular(texture).texture
scene.environment = envMap
// one can also set scene.background to envMap here
texture.dispose()
pmremGenerator.dispose()
})
}, [scene, loader, pmremGenerator])
return null
}
Very useful library, this one! Nominating the next one be named trois. :P
if fullscreen prop is added to HTML tag
<HTML fullscreen ... />
and content height is bigger than 100vh, horizontal scrollbar appeared (because of vertical scrollbar)
I think that horizontal scrollbal is unnecessary and not pretty because of content width is less than 100%
Hello everyone, when I use OrbitControls and I make click on the 3D object, appear a blue frame. I need to remove it. Thanks
When I try to import drei
in a Parcel 2 project, like this:
import { OrbitControls } from 'drei'
that's what I get:
I think it's good to generate a bundle with not only dist/index.js
but each component separately as well. It is possible if Rollup config uses output dir instead of output file. so we will be able to import each component separately without stats.js
being a direct dependency.
4.14.2
^0.0.32
^2.0.0-alpha.3.2
CameraHelper in three js is a very good thing for debugging cameras. It does not play well with react-three-fiber because it need camera as its parameter. Adding a draw-helper prop to camera components in drei could solve this problem. When we need to debug our camera, we can set
<Camera makeDefault={false} defaultHelper={true}/>
and we can see and debug the camera.
I've noticed a strange behaviour when you combine AO from StandardEffects and InstancedGeometry.
If you have any other objects on the scene you can see a "ghost" of the single instance on the center.
Try enabling and disabling the flag on the start of this sandbox:
https://codesandbox.io/s/r3f-instanced-colors-cvbdq?file=/src/index.js
When I pass ref to OrbitControls, ref.current
does not return the object immediately after the component mounted, it takes a while for ref.current
to evaluate to OrbitControls. This is confusing me and I think this might be a bug?
React.useEffect(() => {
console.log(ref.current) // undefined
setTimeout(()=>console.log(ref.current), 2000) // OrbitControls
}, [])
Thanks for the Text
wrapper for Troika's TextMesh!
Stylistically I like the choice to specify the text content as the JSX element's content, that feels very HTML-ey even if you can't do inline markup.
However it seems that this removes the ability to specify a custom material declaratively e.g. with a <meshStandardMaterial attach="material" .../>
child. The ability to use any material is one of troika-3d-text's best features, and r3f's declarative child approach for materials is so clean, it would be a shame to lose that integration. Is there a way to preserve it?
Hi.
I want to create some popup over another mesh with . It works, but click event fired twice - first in popup div and second in mesh under it.
I tried event.stopPropagation() on first event but it didn't work.
Example - https://codesandbox.io/s/event-propagation-from-html-f0t4v?file=/src/index.js
(if red div box is clicked there are two messages in console - one from div box and one from mesh)
function Content() {
const onMeshClick = e => {
console.log("mesh clicked")
}
const onHtmlClick = e => {
e.preventDefault()
e.stopPropagation()
console.log("html clicked")
}
const onDivClick = e => {
e.preventDefault()
e.stopPropagation()
console.log("div clicked")
}
return (
<Canvas>
<ambientLight />
<Plane args={[5, 5]} onClick={onMeshClick}>
<meshBasicMaterial attach="material" color="green" />
</Plane>
<Html onClick={onHtmlClick}>
<div style={{ width: "40px", height: "40px", backgroundColor: "red" }} onClick={onDivClick} />
</Html>
</Canvas>
)
}
These could be useful to simplify common loader use-cases, having to import from examples is counter-intuitive.
import { useGLTF, useTexture } from 'drei'
...
const gltf = useGLTF("./Fox.bin", { draco: true })
const texture = useTexture("./texture.png")
For #27, Sorry the alternative destructure strategy is actually problematic:
because it now passes undefined values to the transform control, e.g. enabled={undefined}
, or showX={undefined}
, causing very weird errors. Not expert of TS, is there a way to not pass undefined props to the control?
When working with HTML component you loose all the React contexts, breaking libraries like MaterialUI that relies on theming.
It's possible to find another solution that doesn't involve calling ReactDOM.render
, maybe using portals?
<HTML>
primitives throw the following linting error with default standard/semistandard(/eslint?) config:
error Imported JSX component HTML must be in PascalCase react/jsx-pascal-case
Is it possible to rename <HTML>
back to <Dom>
(as was in r3f) or similar?
Can be done globally by changing the scene decorator here https://github.com/react-spring/drei/blob/master/.storybook/Setup.tsx
Webpack works around this problem, might be worth fixing.
The codesandbox example for <Line />
results in several errors and won't show any output ...
React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check your code at index.js:14.
The error I'm getting is
Type '{ sunPosition: Vector3; }' is not assignable to type 'IntrinsicAttributes & RefAttributes<Sky>'.
Property 'sunPosition' does not exist on type 'IntrinsicAttributes & RefAttributes<Sky>'. TS2322
As such I'm not able to set this prop value on the Sky.
I'm implementing transformControls but even when I disable some axis it still transforming in this direction. You can test it in this fiddle https://codesandbox.io/s/r3f-drei-transformcontrols-0ngho?file=/src/index.js if you drag from the center of the gizmo the rotation applies in all directions
But I was testing your storybook and this problem is solved https://drei-storybook.netlify.app/?path=/story/controls-transformcontrols--transform-controls-lock-st
time
prop should be optional because it's not required for MeshWobbleMaterial
to work in TypeScript.
I'd like to be able to disable the text selection feature of the troika text. Possible?
Hi there,
When using the Text component in a react-native app (with expo-gl) I get the following error:
TypeError: element.setAttribute is not a function. (In 'element.setAttribute(eventName, 'return;')', 'element.setAttribute' is undefined)
isEventSupported
react-dom.development.js:2484:18
<anonymous>
react-dom.development.js:3828:15
<anonymous>
react-dom.development.js:25213
loadModuleImplementation
require.js:322:6
<global>
index.js:36:7
loadModuleImplementation
require.js:322:6
<unknown>
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:338646:45
loadModuleImplementation
require.js:322:6
<unknown>
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:338533:26
loadModuleImplementation
require.js:322:6
<unknown>
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:124908:53
loadModuleImplementation
require.js:322:6
<unknown>
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:124791:51
loadModuleImplementation
require.js:322:6
<global>
AppEntry.js:5
loadModuleImplementation
require.js:322:6
guardedLoadModule
require.js:201:45
global code
AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:409896:4
Simply importing the package seem to trigger the error.
I've just moved a project to TypeScript and have noticed that in the target
prop for OrbitControls
I can no longer pass an array due to typings. I now have to import Vector3
from three
instead.
Old way (JS only):
<OrbitControls target={[0, 0, 0]} />
Workaround (TS):
import { Vector3 } from "three";
...
<OrbitControls target={new Vector3(0, 0, 0)} />
While the workaround is simple, it would be nice to accept an array in TS for parity. I'm assuing that the solution will be similar to this one from R3F: pmndrs/react-three-fiber#208
I suspect it should be something like this:
import React, { Suspense, useEffect, useRef } from 'react'
import { extend, Canvas, useFrame, useThree } from 'react-three-fiber'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { GlitchPass } from 'three/examples/jsm/postprocessing/GlitchPass'
extend({ EffectComposer, RenderPass, GlitchPass })
const GlitchEffect = ({ children }: { children: any}) => {
const { gl, scene, camera, size } = useThree()
const composer = useRef<EffectComposer>()
useEffect(() => composer?.current?.setSize(size.width, size.height), [size])
useFrame(() => composer?.current?.render(), 1)
return (
<>
<effectComposer ref={composer} args={[gl]}>
<renderPass attachArray="passes" args={[scene, camera]} />
<glitchPass attachArray="passes" renderToScreen />
</effectComposer>
{children}
</>
)
}
export default Glitch
The problem is that it doesn't work :/
it returns this:
TypeError: subscribe is not a function
useFrame/<
./node_modules/.pnpm/registry.npmjs.org/react-three-fiber/4.1.1_ef52f985fc79b351c986d6f8e8a73b95/node_modules/react-three-fiber/web.js:979
976 | useLayoutEffect(() => void (ref.current = callback), [callback]); // Subscribe/unsub
977 |
978 | useEffect(() => {
> 979 | const unsubscribe = subscribe(ref, renderPriority);
| ^ 980 | return () => unsubscribe();
981 | }, [renderPriority]);
982 | return null;
the implementation was taken from react-three-fiber recipes
On Chrome Version 83.0.4103.116,
going to the PositionalAudio->Default component, and then navigating to a different component, will not stop the audio playing from PositionalAudio
I'm using a simple hook to reduce boilerplate when using helpers, let me know if it's something that could be useful:
What about integration with the ProfiledContourGeometry?
https://discourse.threejs.org/t/profiledcontourgeometry/2330
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.