-
-
Notifications
You must be signed in to change notification settings - Fork 35.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
Use Scene.onBeforeRender() and onAfterRender() in WebGLRenderer for tiled forward lighting and VR post proc #11582
Conversation
@edankwan done, it was a silly conflict with a comment(?) @mrdoob the changes are really minimal and still relevant after all this time. It won't just help with post proc. The updated cameras are also needed to construct the textures needed for forward+ shading, after the cameras update and just before the rendering of objects is performed so onBeforeRender serves two purposes here |
I don't have strong preference but If you have some concerns for |
Hmm... This feels pretty hacky. Can anyone share a snippet of how the code would be used? |
renderer.onBeforeRender = function (scene, camera, renderTarget) {
// Use camera to manually cull lights, generate the per screen tile light lists and store them in texture(s)
}; These textures will then be used by custom materials to implement Forward+ shading as described here Forward-Plus-Renderer. The link mentions depth prepass and compute shaders, but they are not needed. In fact the latest iteration of the technique is called clustered lighting and is even more performant without depth prepass ClusteredShading.pdf Its an alternate implementation of many lights that doesn't need deffered, and is generally faster since we don't always have mrt support. It has many other advantages as well like transparency support. The reason onBeforeRender is needed there is because we need to tap on the camera after it updates. In WebGLRenderer.render the camera can also be swapped with the vr ArrayCamera, so by tapping where it does, onBeforeRender will be called with the correct camera that will be used for the scene rendering |
Here is the very basic PostProcessing + VR example code.
|
@takahirox @mrdoob Also some post proc effects need the camera(s) used to render the original scene. Godrays would be an example of that as they need to calculate the center(s) for the radial blur. onBeforeRender would come in handy here as well |
Hmm... How about something like |
@mrdoob .onBeforeSubmitFrame() would be right before the submitFrame() call right? In this case the scene will be already rendered by the time it is called so the tiled forward technique cannot be implemented. The tiled light textures need to be created just after the cameras have updated but before the scene objects are rendered because their shaders need the up to date textures to perform lighting. Another proposal would be onBeforeRender() where it is and an onAfterRender() just before the frame is submitted. This way post proc can be performed in the latter and it will work for both normal or vr mode. This adds another method but takes out the autoSubmitFrame flag and is symmetric. |
Hmm, do you mind pointing me to the exact lines in the code where we would be calling these functions? |
Oh wait, you already modified the PR. |
src/renderers/WebGLRenderer.js
Outdated
|
||
if ( tempHandler ) { | ||
|
||
_this._onBeforeRender = null; |
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 would put this on your app code instead.
We do similar things when using object.onBeforeRender
already:
https://github.com/mrdoob/three.js/blob/dev/examples/js/objects/Reflector.js#L158-L162
@mrdoob I reverted the code, I guess a warning in the docs should suffice for avoiding the infinite recursion and I also didn't like the tempHandler var in the renderer. In the weekend, I'll get on to making an example for tiled forward lighting and post proc |
I personally prefer |
Happy new year every one, wishes for a prosperous and creative 2018 :) I finally found some time to write an example for tiled forward lighting. It's probably the most basic implementation, using tile texels as bitmasks to accomodate 32 lights on screen. It can be easily extended to more, though it would not be best approach for more than a couple hundred. There are other approaches using one more intermediate texture that can accommodate thousands of lights. I added back the autoSubmitFrame flag as @edankwan suggested. I used the onAfterRender() approach for the demo and the mentioned hack for the infinite recursion is visible and not very pleasing imho. Maybe we could keep both approaches as the code footprint is really tiny. After considering @takahirox suggestion, I decided to leave the flag on the renderer and not the VRManager as the renderer is the one actually submitting the frames so it makes more sense to me that he should carry the toggle. |
And here's the example live https://wizgrav.github.io/three.js/examples/webgl_tiled_forward.html I need to cleanup the build files for this PR. Your thoughts @mrdoob ? |
src/renderers/WebGLRenderer.js
Outdated
@@ -1099,6 +1105,8 @@ function WebGLRenderer( parameters ) { | |||
|
|||
} | |||
|
|||
_this.onBeforeRender( _this, scene, camera, renderTarget ); |
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.
could this possibly be onAfterAutoUpdate
?
We've already started to "render" so it's more like onBeginRender
.
It seems to me that the only thing special about the Making this call before you actually call
What I was suggesting before was to have an object based
I'm not sure if i explained it well, since i didn't explain it well the first time i was suggesting this. With how it's currently written/named it seems that this would make more sense, while doing the exact same thing?
|
@pailhead in the case of vr, the provided camera is replaced by an, internally updated, ArrayCamera, This is the only reason onBeforeRender is needed, It provides a convenient structure for both cases, vr or non. Same goes for onAfterRender. Some post proc effects also need the camera(s) |
tileData : { type: "v4", value: null }, | ||
tileTexture: { type: "t", value: null }, | ||
lightTexture: { | ||
type: "t", |
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.
type
specification should not be needed.
mtl.uniforms.lightTexture = State.lightTexture; | ||
for( var u in conf.uniforms ) { | ||
var vu = conf.uniforms[u]; | ||
if(mtl.uniforms[u].value.set) { |
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.
maybe
if ( mtl.uniforms[ u ].value && mtl.uniforms[ u ].value.set ) {
} | ||
|
||
// Generate the light bitmasks and store them in the tile texture | ||
function tileLights(renderer, scene, camera) { |
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.
Can you clean up your whitespace formatting a bit? https://zz85.github.io/mrdoobapproves/
new THREE.MeshBasicMaterial( { | ||
color: new THREE.Color("hsl(" + chroma + ", " + sat + "%, 50%)"), | ||
transparent: true, | ||
opacity: 0.033 |
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.
is that even visible?
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.
Barely, it makes it look like a cheap glow from the light spheres
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.
It's nice. On my monitor I had to increase the opacity, though.
|
||
var lights = [], objects = []; | ||
|
||
var State = { |
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.
lower case
Much better. :-) I have not been able to study the tiled-forward code yet, but this is an interesting demo of a shader hack. It is also an interesting implementation of post processing in lieu of |
Love how simple the PR turned out to be! 😍 |
The example definitely needs some clean up, but I'll merge this for now. |
Thanks! |
Finally we can start to work on VR + Post-Proc? 😄 |
@wizgrav Would you be willing to continue with the suggested changes? |
@WestLangley yeah, I basically did them but mrdoob merged first. I was also thinking to vr enable the example for completeness |
@wizgrav feel free create another PR with these changes 😊 |
I believe this stuff is related to your post on the forum. |
Use Scene.onBeforeRender on WebGLRenderer to provide a way to get the vr cameras after they are updated for the current frame toimplement forward+ shading and expose the vr cameras for post processing.