Blobby things, bezier curves and shaders (Part II)
When we last left off, we had a result that looked like this.
While this does look like a blob, it has some artifacts ( you can see slivers of "spokes along the edges of the triangles), and the blob can only be a solid color, which is fairly limiting, unless your game has super minimalistic art-style.
Today I'll be tackling these issues by, first, fixing the buggy rendering and then adding the ability to texture map the blob.
Fixing the rendering issues
The solution I used for this was to take a completely manifold mesh and just mask of the pixels that fall outside the bezier loop.
To start off, we don't need a triangles that filled up the center anymore, so we remove the code that generated that, this should leave you with triangles that look like this, pretty much like how our initial triangle generation looked.
Reverted Triangulation |
Now, just flip the discard condition in the bezier shader to render the pixeld outside and discard the pixels inside( Now we discard if y*y - x < 0). Result should look like this.
The Mask |
Now, instead of rendering these pixels to the framebuffer ( the display) we want to render it into an buffer in GPU VRAM called the "stencil buffer". Its not rendered to the display, it just store an 8-bit integer for each pixel/fragment, and you can use in your shader to reject or accept pixels.
OpenGL Pipeline |
It is in the last "Per-Sample Operations" stage that you can have some Stencil Buffer write or Stencil Buffer read and reject/accept operations for the fragment.
In our case we want to write 1 into the Stencil Buffer for each of the red pixels in the mask. In Unity ShaderLab allows us to specify the stencil logic at the top of our Subshader pass block.
But wait, we can't stop there, we also do not want the mask to render to framebuffer, we can specify just a couple of lines at the top of the Subshader block to do this.
For the mask we need the following code at the top of the shader
Step 2
Now, that we have our mask ready, we want to render the mesh that gets masked. The triangle generation for this pretty trivial, we add outer ring of rigidbodies and the central rigidbody as vertices and make, and have the triangles ordered clockwise, with two outer loop vertices and the third vertex of the triangle being the center.
If that was too confusing, the image below illustrates how you do it. The blue numbers represent the indices of the respective vertices and the orange arrow shows in which order you're sup[posed to add the triangles.
Mesh Triangulation illustration |
Now, we need a new shader and associated material for this mesh. Start off by creating a new Standard -> Unlit shader, this will already have all the code needed for being able to add texture maps as well, we just need to a some code at the top telling this object to render in a pass after mask, and to not render the pixels which have a corresponding value of 1 in the pixel shader.
Setting the UV Co-ordinates of the mesh
We also need to assign UV co-ordinates to our mesh vertices, I decided to set the central vertex with a (u,v) of (0.5, 0.5) making it correspond to the center of the texture, for the loop vertices i set them up as follows :
u = - 0.5f * cos(theta) + 0.5f
v = 0.5f * sin(theta) + 0.5f;
Angles |
Now, initially I hardcoded the phi 2*PI/NumTris, giving each triangle a fixed UV, this worked OK for most situations but as the blob would simulate the value of phi would change and this would cause the texture maps to stretch/ compress.
Switching it to actually measure the value of phi every frame inside Update() and updating the UV's accordingly resulted in a much better looking blob.
Here's the function that does that
Results
And, thus we have a nice texture mapped blob!
0 comments :
Post a Comment