Unity flat shader?
Hiiiii!!
I'm looking for a shader that's compatible with Unity terrain that would have a flat shader look like so:
The theory is to simply eliminate the "smoothing" effects of the usual shaders by averaging out the vertices normals to produce a single normal and flood the poly with that one colour, instead of the usual smoothed out colour from each edge/vertice.
I have no idea how that would work, and googling hasn't come up with anything...
Is this impossibly difficult?
I'm looking for a shader that's compatible with Unity terrain that would have a flat shader look like so:
The theory is to simply eliminate the "smoothing" effects of the usual shaders by averaging out the vertices normals to produce a single normal and flood the poly with that one colour, instead of the usual smoothed out colour from each edge/vertice.
I have no idea how that would work, and googling hasn't come up with anything...
Is this impossibly difficult?
Comments
Edit: You'll have to make sure though that you have per-triangle normals, and not per-vertex! For per-vertex normals, the normals of each triangle around a vertex is averaged, so for one triangle, there will be 3 normals specified... one at each corner. It will then interpolate to create a smooth effect. HOWEVER, for per triangle normals, you will have a flat normal on the entire surface, hence a flat colour!
EDIT2: From here: http://docs.unity3d.com/Manual/SL-SurfaceShaderLightingExamples.html
Something like this could do the trick:
And in fact, an ordinary diffuse shader will do the trick. Let's just find out how to do those per triangle normals :)
EDIT, AGAIN!!!
I'm not sure how easy it will be to modify your unity terrain to have per face normals. It might in fact be easier to generate your own terrain mesh from a height map if this is the case.
Yes, I've read in places that generating your own mesh terrain is the way to go, but then we need a way to move vertices at runtime... Because we need that too :/
You'll have something like this attached to your game object containing the Mesh and the MeshFilter:
The trick now is just to generate the vertices, triangles, and normals. You'll need to modify that code to have normals, and I'm sure you can leave out the UVs, unless you want to texture your terrain in addition to shading it. I'm quickly figuring it out again and then I'll post some code. I think you specify an array of vertices, so something like:
Those will give you two triangles, which line up to make a flat square. You will need to tell unity which vertices to use though for each triangle, so that's where the mesh.triangles comes in. Your triangle array will be multiples of 3, so that's 3 per triangle. In this example we will have 2 triangles, so the triangles array will be 6 long. Each element of this array points to one of the vertices in the vertices array. I strongly suspect that you can re-use vertices for each triangle but I might be wrong.
So it will be something like:
I think you want to draw it out on paper, and make sure you index them in a counter-clockwise order. The winding order (ie, 0, 1, 2 vs 2, 1, 0) determines whether the surface faces to the front or to the back. If it faces to the back it might not be rendered.
I think at this point you can specify normals, either per vertex or per triangle. I'll see if I can figure it out. So I might come back to you and admit that all of these were lies :D
Thanks so much for your time!
This shader does not regard colour or anything. We can expand it to do this though!
The GLSL shader... I have no idea what it does, it just gives me the unity error pink, but i'm sure you knew that already :P
https://www.assetstore.unity3d.com/en/#!/content/18572
$50
@Denzil I'm on OSX, so... It should be platform independent? But I guess I really don't know what I'm talking about :/
You mention you need to move verts at runtime, if you generate your own mesh you should be able to do that, though?
Anyway, on this, @elyaradine was a mythical unicorn machine and wrote a shader for us that allowed the exact look we needed. Omg he's a genius.
@elyaradine More or less, what was the trick? :)
I just stuck the negative in there because it looked upside down. :P (It was a bit inconsistent for me on DirectX where in the Game view while the game was not running it would show one direction, but in my Scene view and in a running Game view it would show another direction. I guess it doesn't matter as long as the Scene and running Game views sync up, but just so you know.)
From there you've got your per pixel normal that's the same as if you had hard edges, and you can take it from there with lighting/fresnel/whatever.
I'm also not 100% sure what passing the world position vector (I assume it's a vector?) into the derivative functions achieves, don't those just take floats between 0 and 1?
To be honest, I'm not really sure how the derivative functions work myself. I mean, I've read a bit about them, and I can make a guess, but I'm hardly an authority. My understanding is that it actually just takes "some value" that you're checking based on adjacent screen space pixels. That value could be a position, or normal, or anything, and I don't think it even matters what space it's in (as long as you know what you're doing with the result of course); it can be a scalar or vector (or even a matrix?), and just returns what the difference is between the left/right and top/bottom pixels' values for ddx and ddy respectively. It feels like it could be a way to do certain things you're normally do in an postprocess/image shader, but on actual geometry.
@Tuism: Have you seen any weird seams with this? What does it look like when it goes wrong?
The ddy, and ddx functions buffers the values for those pixels in the stage of the pipeline where it is called, and works out pure differences as @Elyaradine mentioned. Across one triangle, the derivatives of the position (in any space), is constant over x and y fragment positions. So that's why the "real" normal can accurately be reconstructed from here. And yes, you will get artifacts the edges of triangles, because the derivative changes here. The question is just whether the change is subtle or not! I suspect the seams might just end up being a mix between the colours on both connecting triangles, effectively hiding it (kinda like anti-aliasing)
OpenGL apparently does have the "flat" flag you can set to make triangles rasterize with the same normal. Or you can also use:
I don't know if that would work in the Unity implementation of those shaders though. (I haven't tried, and I generally avoid doing things that don't work for both OpenGL and DirectX.)
[edit] Apparently DirectX has an equivalent (interpolation modifiers), but it only exists in shader model 4 (DX11 in Unity afaik).
DX11 running on latest nVidia divers
So I would like to upload this Unity project up to GitHud - for community consumption. However the project is quite large. What is the best way to "source control" a Unity projects files?
Should I drop the "meta data" folder (Geos\Library\metadata). Is that folder needed? it is over 100mb alone.
Thx
Because I'm also running DX11, and it looks messed up in my Game view until the game's running. <_<
--
You only really need to upload the Assets folder. The Library folder is kind of more for caching, afaik, and is recreated when you import the project for the first time.
Busy uploading to GitHub now - thx for the folder advice.
Shader error in 'Unlit/HardEdge': cannot map expression to pixel shader instruction set at line 65 (on d3d11_9x)
Compiling Fragment program with DIRECTIONAL SHADOWS_OFF LIGHTMAP_OFF DIRLIGHTMAP_OFF DYNAMICLIGHTMAP_OFF
Platform defines: UNITY_NO_LINEAR_COLORSPACE UNITY_ENABLE_REFLECTION_BUFFERS UNITY_PBS_USE_BRDF3
Shader error in 'Unlit/HardEdge': cannot map expression to pixel shader instruction set at line 65 (on d3d9)
Compiling Fragment program with DIRECTIONAL SHADOWS_OFF LIGHTMAP_OFF DIRLIGHTMAP_OFF DYNAMICLIGHTMAP_OFF
Platform defines: UNITY_ENABLE_REFLECTION_BUFFERS UNITY_PBS_USE_BRDF1 UNITY_SPECCUBE_BOX_PROJECTION UNITY_SPECCUBE_BLENDING
Switched "Rendering" in project settings from "Forward" to "Deferred".
Looks like it is all happiness now.
I pasted it here instead.
https://pastebin.com/GW3dCLzj
There might potentially be ways around that, but it really depends on your specific use case, and unless you've got very specific gameplay that needs it, I can't really think of any reason why doing it in the shader would be better/faster.