Currently I am implement a paper from UnityLab. I would like to create many passes in a surface shader, and some information should be transfered from previous passes to the current one, like store the previous calculated information in a buffer, and read that buffer in the next pass. The process in the paper contains 6 passes. How can I do it?
You can do multi pass shaders with surface shaders, in fact they already are multi pass shaders by default because that’s already how Unity’s lighting system works.
However how that relates to that particular paper … no, nothing in that paper can be done with surface shaders, really at all.
Surface Shaders are for writing shaders that easily interface with Unity’s existing lighting systems. What’s in that paper is much more complex, making using of multiple full screen passes and raytracing. Multi pass Surface Shaders would be for drawing one object multiple times for something like adding an shell outline on an otherwise normally lit object.
Thank you for the anwser! Surface shaders cannot do multiple full screen pass. So I need to use the traditional vertex and fragement shaders. Am I right?
Yes, you should be using vertex fragment shaders, but they still can’t do multiple full screen passes by itself either. To do what you’re looking to do, you need to be using multiple render textures and Blit() calls from C#.
Can Blit() cooperate with surface shaders? Or just vertex fragment shaders? I already implement the area light with linear transformed cosine in a surface shader.
A surface shader is a vertex fragment shader generator. It actually generates multiple passes which are used by Unity’s lighting system for different parts of the pipeline for rendering an object. Like I said earlier, they’re useful for making shaders that work with the built in rendering paths.
If you call blit using a surface shader, something will indeed render, but as most of the shaders inputs aren’t setup, and Blit explicitly renders a full screen quad, it’ll probably render solid black. It’ll still be trying to do all of the calculations for lighting, but since none of that data is likely to be valid it’s a lot of wasted computation to get nothing.
What you’re looking to do is effectivity replace Unity’s rendering pipeline to some extent. You need to be able to render a mesh with a few different shaders to different render textures, do some processing to those images, then combine. That’s a combination of multiple separate shaders and different ways of rendering them.
Ah… I am still confused on how to do it. It seems that Blit is only for the post processing. In this case, I can pack the result of Sn and Un in an RGBA texture(x,y,result of Sn, result of Un). Then use Blit to pass them to a new shader, to do some denoise stuff. In this part, Bilt is very useful.
However, how can I render the same srceen 2 times from scratch? I need to render U first, and save the texture, and then render the Sn and Un. What I would like to do here is not to pass the texture of U to the shader of Sn and Un, but render the screen from scratch. There is no link between U and Un and Sn. In general, I want to render U and Sn and Un independently. How can I do it?
You’re basically asking “How can I write a custom lighting system from scratch.” The short answer is: learn more about graphics programming before you start this.
The longer answer is you need to have a better understanding of what a graphics pipeline is and what something like Unity is doing. Making a simple scene with a few post processing effects enabled and then using the Frame Debugger to step through what’s happening might help you get yourself understanding more of the various steps that are occuring for for the built in rendering pipelines, which in turn may help you understand what you would need to do.
For more of an overview of your options. Generally if you need to render your objects to “the screen”, you’re rendering them to either the frame buffer or a render texture. If you want to render the same objects to two different “screens”, you either need to render the object twice to two different render textures, or use a multi target render which lets you render once to both render textures. For the former it’s a matter of setting the current render target via RenderTexture.active or buffer.SetRenderTarget() or camera.targetTexture, or camera.SetTargetBuffers(), then rendering your objects using GL functions, or Graphics functions, or camera.RenderWithShader(), or camera.SetReplacementShader(), or using a CommandBuffer, then taking the render textures those produce and mixing or modifying them with blit commands to other render textures before eventually blitting them back to the frame buffer for display.
There’s a lot of options, and pros & cons to each of them.
And in terms of actually implementing that paper you’re going to hit a big wall quickly since Unity doesn’t yet support DXR so you’ll have to implement all of the raytraced shadowing yourself as well, likely using a few compute shaders, and collecting, processing, and passing the necessary scene data to the compute shader yourself.