Hi there, in advance I’d like to share that I’m pretty new to shaders but have a gist of the basic concepts, so bear with me as I try to sound like I know what I’m talking about here…
Being new to shaders and image effects, I only have tidbits of information that others have shared on how this effect might be achieved, but I don’t think I know enough to write the shader/image effects needed to make those things happen. This part is my knowledge so far (which may be wrong): The lightening effect (green arrow) on the outer edges appears to be an effect on the entire screen and not a specific material because it will lessen as the camera gets closer to the edges. The darkening effect on the inner edges (blue arrow) would normally make me think SSAO or some other ambient occlusion, but the fact that it looks so similar to the outer edges but in a darker tone makes me think it is also part of this effect. I believe this also involves using a normal map of the camera’s view to detect the edges?
I really just need guidance on all of the terms and concepts that are all involved in this specific effect and how they are used so that I can begin to make progress. Code is also greatly appreciated! Thanks a bunch.
Trove is very clearly using normal maps (as seen from the blocky artifacts in the shading). Could be a second atlas, or more likely a single box face normal map with careful UV mapping.
The example image above doesn’t look like normal maps, but rather just a bright edge. Again, likely just done with a texture and careful UV mapping.
Real time shaders alone lack the ability to create rounded edges without custom encoding of a lot of information into your mesh and/or textures and complicated shaders… at which point just using a normal map is way, way cheaper and easier to implement.
I would opt for a normal map under normal (pun intended) circumstances, but the meshes I am working with to achieve this effect are all procedurally generated with data like “there is a voxel at x,y,z with color a.” My current setup also includes a texture that is generated that has a pixel for each color contained in the set of voxels, and each face UV maps to that pixel on the texture. That setup doesn’t need to stay the same, but the procedural generation part will.
That being said, I can’t quite think of a way to use a normal map texture to achieve the effect - I imagine I would need a normal map for each possible face of a cube, similar to the pic below but with more cases than the 9 shown. Even then, I will run into an issue of my UV mapping for handling colors conflicting with what my UV mapping for handling normals. I might be missing something though. Did you have in mind a way to go about this? (I am not tied down to my current setup for mesh/texture generation, just that it all needs to come from data instead of an obj and texture files)
On the comment about the first pic just using a brighter edge, that’s actually my desired effect. For my purposes (and opinion haha), it looks good enough to convey roundedness. Would the way to go about this be different if the goal is just to brighten the edges that face outwards?
For normal maps or bright edges the implementation is basically the same. Either have an atlas like you have above, or add in edge splits in your geometry so you only need a single full face normal and an internal corner, and scale the UVs anywhere you need a flat face / long single edge.
So for that implementation, I would lose a lot of control over what color each voxel is because I currently use UV mapping to map to a texture atlas used for colors, not normals. This is because my mesh is procedurally generated and could have a different color for each voxel. To my knowledge there isn’t a way to UV the albedo and normal maps differently
If possible, I’d like to step back the question to “how can this be achieved with shaders/image effects,” because I am growing more confident that the game I am referencing using this effect does not use normal maps, and possibly not even a texture with brighter edges. In the video attached, I am moving the camera close and then far away again to show how the effect changes intensity/size. This is really the biggest reason I think there is an image effect at play here (that may be the wrong terminology, I am referring to the effects that manipulate pixels after Unity has rendered out the screen :p)
You can have more than one UV set, up to 8. In fact each UV set is a Vector4 / float4 that you can pack two 2D UVs into, so you can have up to 16 completely unique UVs. Unity’s built in RecalculateTangents function assumes the normal maps are no the first UV’s xy components, but as long as the UVs used by the normal maps have the same orientation as that first UV they’ll still work properly.
That particular effect, yes, that could be done as a post process. It appears to be doing an inverse SSAO on convex edges. You’ll notice the dark interior edges also scale with distance. Most SSAO implementations go to great lengths to make sure the effect stays consistent in world space, but that one is purely screen space.
This is a screen space effect using normal texture and depth. If you look at the Blender code, then they have two concepts “curvature” (darkens the far edges and brightens the near edges) and “cavity” (this is an AO effect that makes the edges smoother).
I am still finishing this effect right now as there are some difficulties with distance and mode (perspective / orthographic). When I finish, I plan to publish it in the asset store.
I decided to show part of the “Curvature” effect. It also does not work with an orthographic camera yet, but maybe that will be enough for you.
I just don’t want to deal with this effect now, while there is a lot of other work.
This is all written and tested on Unity 2019 LTS and URP 7.5.3.
Basic settings:
Filter Mode - allows you to make a smoother transition from the thickness.
Scale, Ridge and Valley - thickness and saturation of light and dark edges.
This shader is exactly what I was looking for. However it works great in the game but in scene view I got a totally black view. Any ideas on how to fix this?
Thanks!
Sorry, this is because I wanted to reduce draw calls.
I don’t have access to a computer right now and won’t be able to rewrite the code. You can do it yourself using the Blit Pass that Unity has for the example.
You need the Execute method. In my version, it renders everything in one draw call, in this example a temporary texture and two draw calls are used.
Alternatively, you can see the implementation here.
A lot of work and to do. Here in the attachment file, everything should work with it as it should.
Sorry, there is no way to check on Windows, if there are problems - then write.
Added a scene with an example to the package. Also, if there are problems or artifacts, I added a quick implementation of Blit in the settings: