-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
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
WebGPURenderer: Depth Pixel & Logarithmic Depth Buffer #27243
Conversation
export const depth = nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH ); | ||
export const depthTexture = nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_TEXTURE ); | ||
export const depthPixel = nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH_PIXEL ); | ||
|
||
depthPixel.assign = ( value ) => depthPixelBase( value ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just depthPixel.assign = depthPixelBase
maybe?
return cameraProjectionMatrix.mul( modelViewMatrix ).mul( this.positionNode ); | ||
if ( builder.shaderStage === 'fragment' ) { | ||
|
||
return varying( builder.context.mvp ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a bit of a hack to me -- I propose instead to introduce a property like vertexOutput
which can be used here (and remove builder.context.mvp
then). @sunag What do you think?
* WebGPURenderer: Depth Pixel & Logarithmic Depth Buffer * Update puppeteer.js
const renderer = new WebGPURenderer( { antialias: true, logarithmicDepthBuffer: logDepthBuf } ); | ||
renderer.setPixelRatio( window.devicePixelRatio ); | ||
renderer.setSize( SCREEN_WIDTH / 2, SCREEN_HEIGHT ); | ||
renderer.setAnimationLoop( render ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While migrating the examples towards setAnimationLoop()
I have noticed an issue in this example. The render()
function updates both renderers but since setAnimationLoop()
is called twice, the frame rate is double as high as expected.
How are apps supposed to use more than one WebGPURenderer
with a single global animation loop?
AFAIK, if the example calls setAnimationLoop()
only for a one renderer, the internal state of the second one isn't correct (since NodeFrame.update()
isn't called and renderer.info
isn't updated).
If the example uses an animation loop per renderer, which animation loop does it use to update its "global state"? No matter which one you use, the second animation loop might use frame-late data.
Maybe we need a way to trigger the update logic in the Animation
class from outside somehow...
Edit: This is not only issue with multiple renderers. Consider an app that manages its animation loop separately and can't use setAnimationLoop()
. How does it update the state of the renderer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also battling a bit with this problem as I was planning to introduce renderer.xr.setAnimationLoop()
(Quest Browser can have immersive + non immersive at the same time).
Where do the physics run? 🤔
We'll probably have to create an issue for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
..If the example uses an animation loop per renderer, which animation loop does it use to update its "global state"? No matter which one you use, the second animation loop might use frame-late data...
This should not be the expected result, Animation
has a frame counter per Renderer, regardless of the user using setAnimationLoop()
as would happen in WebGLRenderer
, this ensures that the user can still use requestAnimationFrame
without harming the events per frame in the Nodes
.
While migrating the examples towards setAnimationLoop() I have noticed an issue in this example. The render() function updates both renderers but since setAnimationLoop() is called twice, the frame rate is double as high as expected.
I think this is behavior is correct if two renderers depend on using setAnimationLoop()
, both must be isolated, and this conflict of Node updates should not exist as we have an Animation
and NodeFrame
class per Renderer in WebGPURenderer
. It could just use one setAnimationLoop
or one requestAnimationFrame
for multiples Renderers, if this doesn't work it could be a bug.
Although it is an unusual approach to use more than one device, practically no engine duplicates devices, perhaps the user could solve this with RenderTargets
, scissor, etc. if the renderer is working and declared in the same thread, in case of different threads having independent setAnimationLoop
should be more useful.
I'm also battling a bit with this problem as I was planning to introduce renderer.xr.setAnimationLoop() (Quest Browser can have immersive + non immersive at the same time).
Shouldn't Renderer.setAnimationLoop()
manage these calls internally, and we only have one function for this event?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I've tried to fix the demo in #28249.
What I'm unsure about:
- Since
Animation
isn't used now, how isinfo.reset()
called? Does the app needs to do this? - Is the missing call in
nodeFrame.update()
inAnimation
an issue? Does the app has to call this method as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since Animation isn't used now, how is info.reset() called? Does the app needs to do this?
I was considreing the user customize the Info
if needed, so he could create new classes for this #27889 (comment)
What do you think about share the info between renderers?
const info = new Info(); // it can be a customized Info class too
renderer1.info = info;
renderer2.info = info;
Is the missing call in nodeFrame.update() in Animation an issue? Does the app has to call this method as well?
It continued to be updated, Animation
class of WebGPURenderer
have a requestAnimationFrame()
internal to sync the frame events, it's canceled if the user dispose the renderer.
three.js/examples/jsm/renderers/common/Animation.js
Lines 17 to 29 in 32d19eb
const update = ( time, frame ) => { | |
this.requestId = self.requestAnimationFrame( update ); | |
if ( this.info.autoReset === true ) this.info.reset(); | |
this.nodes.nodeFrame.update(); | |
this.info.frame = this.nodes.nodeFrame.frameId; | |
if ( this.animationLoop !== null ) this.animationLoop( time, frame ); | |
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Um, my feeling is the update loop in Animation
should only run if the user does use setAnimationLoop()
.
If the user manages the animation loop on app level and not via the renderer, the user should tell the renderer when to update its internal frame counter, the timer and other frame related components.
A separate Info
object which is managed on app level and injected into the renderer (or multiple renderers) could be indeed one solution.
Example
https://raw.githack.com/mrdoob/three.js/dev/examples/webgpu_camera_logarithmicdepthbuffer.html
We introduce an
OutputStruct
, we addeddepthPixel
which is equivalent togl_FragDepth
, it can be used as assign, e.g:depthPixel.assign( value )
or to include in some WGSL Function, e.g:Renderer.logarithmicDepthBuffer
NodeMaterial.depthNode = node
To set the depth buffer using nodes.WebGLBackend