I have a question regarding converting a frag vert shader to a surface shader.
Is there a way to duplicate the mesh deformation output into another shader by basically duplicating the Vert deformation/ frag shader output and then feeding it into a surface shader.
What I am wanting to do is add some basic lighting to the deformed mesh since I have been unable to find a way to make point lights work on frag/vert shader.
What would be a good strategy for making point/spot lights work with a vert/frag shader.
Or if i could somehow add a surface shader on another pass to the frag vert shader output.
Long version: Yes, there is!
This is how GPU skinning works in Unity! It renders the mesh with a special skinning shader that outputs new vertex data when then gets used by the user selected shader to actually render! … but that’s not something any of us can actually do, at least not the way Unity does it with stream output.
There’s also more complex setups like outputting your transformed vertex data to a RWStructuredBuffer, but there are big roadblocks in getting a Surface Shader to be able to use that.
So, really I lied. The long version is still no.
However, you don’t really want to do this anyway. You’re over thinking the problem. Your real question should be “can I do vertex deformation in a Surface Shader”. The answer to that is yes.
So, here’s the thing. A Surface Shader is also a vertex fragment shader. Or more specifically a vertex fragment shader generator. A Surface Shader essentially lets you write only the parts you care about, and then adds those functions vertex fragment shader templates that include the support for the rest of Unity’s lighting system. You can look at the generated code from a Surface Shader, which is the vertex fragment shader the game actually uses. If you’re really curious you can look at this tutorial that goes into more depth on how Unity’s lighting system works. https://catlikecoding.com/unity/tutorials/rendering/part-4/
The short version of Unity’s lighting system, at least for how it works when using the built-in forward rendering path, is each light is done by rendering the object using multiple passes; the entire mesh is re-rendered once per light. The first, aka “base” pass renders the main directional light, ambient / baked lighting, and reflections. The “add” pass renders one real time light, either directional, point, or spot. If you want to have a single object be lit by 10 lights, you have to render the entire object 10 times. Technically the base pass can also do up to 4 “non-important” lights, which are calculated per vertex diffuse lighting, and thus won’t be affected by normal mapping, or specular, and can’t cast shadows.
If you want a lot of lights, you might want to look into using the deferred rendering path which can support hundreds or thousands of lights much more efficiently. Though be warned that any transparent objects will still be forward lit as deferred only works with opaque objects.
Hrm thanks for the tip, what I would need to see is an example of a surface shader with a vertex deformation function that is similiar to a vert shader so I can figure out how to migrate it over.
I see how it’s done with vert/frag, are the functions the same in surface shaders? Meaning could you nearly copy paste the funcions over with just a few changes and still achieve the same deformation result?
Again, a surface shader is just a vertex fragment shader. All the same functions are available, as well as a few additional ones that are surface shader specific (mostly ones only valid in the surf function).
The main difference between a vertex fragment shader and a surface shader is the input & output values available are a bit more fixed. For example you have access to the data in appdata_full, but not stuff like the vertex id, and while you can pass custom data via the Input struct, you have to output an object space position by replacing the v.vertex in appdata_full.
Ah i see, here is an example extruding along a normal.
No I just have to look at converting this frag shader over and see if I can get some point lights going.
What I’m doing is im working with the Crest Ocean system and I’m using Azure Sky for day night cycle and I’m basically wanting point lights to hit the ocean surface.
So if I can achieve the same effect that the ocean system is providing with mesh deformation, why not go with a surface shader and open up the possibility for some lighting instead of a frag/vert shader.
The way the ocean system works is it uses titled mesh and they can be made uniform so I see no reason why point lights shouldn’t accurately hit the surface once there is some lighting capability with the shader.
Ah … yeah, sticking that in a surface shader isn’t going to make supporting multiple lights that much easier. Crest uses a quite extensive custom lighting model which would be difficult to replicate with how Surface Shaders work. It looks like there was some work put into supporting multiple lights already, but it was either removed or never finished.
I would say to get that shader working in a Surface shader and getting it to look the same is way more work than getting the vertex fragment shader to handle multiple lights. That’s mostly duplicate the first pass, set the light mode to ForwardBase, delete all the stuff related to reflections, and calculate the attenuation factor.
I don’t know the ocean system has very limited lighting… directional light, Fresnel, reflections that’s about it.
It only supports a single directional light. The shader for Crest isn’t all that complicated really. Suimono is much more complex, Suimono also supports point and spot lights and is really pretty…
The problem with Suimono is the buoyancy system is slow and horribly innacurate when dealing with any sort of wave height.
He basically tries to guess the wave height based on settings and by doing many pixel samples… It’s a performance hog on top of not being very accurate and there isnt really a way to fix it unless you sample the verts with the shader itself instead of sampling the position of the heightmap.
If Crest did support point and spot lights, it would probably be the best ocean system that exists given it’s simulation capability with mesh deformation around other mesh objects and it’s surprisingly fast to boot. It’s definitely has the most accurate buoyancy system that exists. I’ve tried them all, even tried to make my own.
I’m going to be uploading a video in a few days showcasing a prototype im working on which you will get a good laugh out of, thinking of making a game, something small but fun and doable by one person.
It’s a simple model overall, sure, but there’s a lot of layers to it that won’t be easy to replicate due to the ways Surface Shader expects lighting to work. Basically it means totally redoing a ton of code.
The biggest problem is the way Unity’s built in forward rendering path handles point lights for transparent objects is really inefficient for large objects. You’ll be effectively re-rendering the entire object for each light. That gets expensive quickly when your object is covering most of your screen. Most projects limit the number of lights per object to something like 4 or so, which means only the 4 brightest lights overlapping the bounds of the mesh will be used.
The LWRP and HDRP make a lot of improvements here, especially the HDRP, which has support for multiple shadow casting lights on transparent objects.
Really, using “vertex lights” might be a cheap, fast way of adding point light support to the shader. You could even do “vertex lights” per pixel if you want them to look a little better, though the mesh density is probably dense enough for it to be fine.
Yah, I’m just gonig to build out my prototype. Lighting the ocean isn’t the most important thing. If there is still room in the pipe after I get the other systems going ill take a look at adding vertex lights.
I’m actually making two different scenes to test with, one is an open world with day night cycle which ive managed to get looking decent even without the night time ocean lighting, it’s not triple A quality but decent.
The other is the scene for the prototype of a simple Obstacle Course / Racing game I want to build using the Crest ocean system which ill be making heavy use of it’s surface deformation system.
Of course i have bigger plans for a game but after a decent amount of experience making prototypes over the years… ive learned a valuable lesson… not to try to build GTA V by myself.
Ill roll out a video maybe by the end of the day. It’s a nice showcase for Crest lol, my video is a lot cooler than what is on their forum page, I also put abit of time into it and have some custom modifications to the ocean system.