Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411507 Posts in 69374 Topics- by 58429 Members - Latest Member: Alternalo

April 26, 2024, 05:55:54 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Help me extend my Unity Metaball shader effect?
Pages: [1]
Print
Author Topic: Help me extend my Unity Metaball shader effect?  (Read 3049 times)
alecfa
Level 0
**


:)


View Profile
« on: October 26, 2015, 04:31:02 PM »

Hi everyone! I need some Unity Shader help  Tongue

In my game players need the ability to throw goop. So right now, I've got a system where separate game cameras see feathered, transparent blobs of pixels, passes that to a RenderTexture, renders them if they surpass a color Threshold, and finally check adjacent pixel positions in order to add shadows, highlights and outlines.


Looks pretty good! (What the camera sees on top, what is actually rendered on bottom)


The metaball effect is great cause it really makes everything goop together.

But I need to be able to render four different colors of these at once.  My first thought was to just have four cameras and four render textures, but that quadruples the effect's overhead, and it starts to lag on my laptop.  But I can consolidate some of them! If I assign different colors to the RenderTexture's R,G,and B values, I can check for 3 different color thresholds in one pass. That pesky fourth color still requires its own camera though.



This works, but there's a few problems still:
1. Colors are rendered in order, so Red will always be on top, then Green, then Blue, etc. Throwing new goop should land on top of old goop, and I can't change push one color of goop to the top without snapping all of that goop's color to the top.
2. The 2 added camera system is cumbersome, and I feel it should be able to be done with just 1?
3. I don't have a way to rasterize all the goop on the screen to a texture, which I'll need to do eventually so that zillions of particles don't eventually collect.

Does anyone have any ideas as to how to make the system better?  I would be eternally grateful! Smiley
« Last Edit: October 26, 2015, 04:41:18 PM by alecfa » Logged
Allen Chou
Level 0
**



View Profile WWW
« Reply #1 on: October 26, 2015, 07:00:39 PM »

What about just draw to a texture that is never cleared?
That's how the residue ink effect is done in Ink.



Logged

surt
Level 7
**


Meat by-product.


View Profile
« Reply #2 on: October 26, 2015, 07:14:06 PM »

You have four colours. RGBA textures have four channels. Use one channel per colour and so one texture for all four colours.
Logged

Real life would be so much better with permadeath.
PJ Gallery - OGA Gallery - CC0 Scraps
Cheezmeister
Level 3
***



View Profile
« Reply #3 on: October 26, 2015, 08:39:12 PM »

I would just like to say, pixellated metaballs = a deliciously beautiful contradiction. <3
Logged

෴Me෴ @chzmstr | www.luchenlabs.com ቒMadeቓ RA | Nextris | Chromathud   ᙍMakingᙌCheezus II (Devlog)
alecfa
Level 0
**


:)


View Profile
« Reply #4 on: October 26, 2015, 11:57:55 PM »

You have four colours. RGBA textures have four channels. Use one channel per colour and so one texture for all four colours.
I didn't think this was possible but you're totally right! It can be done! I used additive blending and an RGBA ColorMask to pass the channels individually. 4 colors one camera! Woohoo!


Now that they're all together I tried blending their colors but I don't like how muddy that looked. Plus new goop splats should overwrite the surrounding area - you should be able to tell what was thrown most recently, so the sorting dilemma continues.

What about just draw to a texture that is never cleared?

That's a great suggestion, but then the effect would leave big ugly streak lines across the screen when the goop is airborne. For sorting though I'm thinking I may be able to take dead particles, somehow duplicate them onto a large, entire-map-sized Texture which is never cleared, and then my shader will just always be passing both that big Texture, and also all the alive particles? Is there a way to copy the pixels from a specific Rect in world space to a massive Texture the size of all my applicable goop area?

I would just like to say, pixellated metaballs = a deliciously beautiful contradiction. <3
Thank you!!! This whole game's sort of centered around that effect so it's nice to know people like it!
Logged
oahda
Level 10
*****



View Profile
« Reply #5 on: October 27, 2015, 02:02:14 AM »

wth is a metaball

That looks cool as heck anyhow. I'm feeling inspired!
Logged

BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #6 on: October 27, 2015, 03:32:32 PM »

Instead of blending, I'd use a shader that picks the max channel before thresholding, and uses that as the color. Then two splats near each other will form a neat dividing line, with the same curving that metaball outlines have.

Unfortunately if you want newer splats overwriting older ones, I think you will need a texture that is never cleared.
Logged
Allen Chou
Level 0
**



View Profile WWW
« Reply #7 on: October 27, 2015, 10:58:41 PM »

What about just draw to a texture that is never cleared?

That's a great suggestion, but then the effect would leave big ugly streak lines across the screen when the goop is airborne. For sorting though I'm thinking I may be able to take dead particles, somehow duplicate them onto a large, entire-map-sized Texture which is never cleared, and then my shader will just always be passing both that big Texture, and also all the alive particles? Is there a way to copy the pixels from a specific Rect in world space to a massive Texture the size of all my applicable goop area?

What about only clear the region that you don't want residual goop using stencil buffer or similar tricks?
Logged

alecfa
Level 0
**


:)


View Profile
« Reply #8 on: October 28, 2015, 01:44:11 PM »

What about only clear the region that you don't want residual goop using stencil buffer or similar tricks?
Oooh, thank you for making me Google "stencil buffer", that sounds like it could be really useful!

So someone on the ShaderLab forums suggested using a blending mode of "Blend SrcAlpha OneMinusSrcAlpha, OneMinusDstColor One", which makes the individual color values come through, but blends the alpha channel additively. This would allow me to have theoretically infinite colors of goops, and while that's not within the scope of this project it sounds like the better way to do things. Plus since Alpha isn't limited to displaying a specific color, I can overlap colors without having their RGBA values combine into other unintended colors.



Unfortunately, we're still blending colors together though, so I need to posterize the splats into one of the four applicable colors. I check which color each pixel is closest to in color, and then snap it to that color.


Looking good!

But now how do I shade, highlight, and outline my splats? Beforehand, my sampler2D's were separated into 4 distinguishable channels. In order to check surrounding pixel positions to determine whether it should be shaded and how, I now need to calculate and posterize the color of those surrounding pixels first for stuff like

if(pixelColorAbove != myPixelColor) {
    myPixelColor = highlightPixelColor
}

Which means that I'm checking 20 neighboring pixels...for every pixel... Computers are fast so it keeps up on my desktop, but it lags a bit on my laptop.


...be better than me. Don't do this.

So obviously there's gotta be a better way to do this. It'd be great if I could do a first pass where I posterize everything into those four initial colors, and a second pass where I shade, highlight, and outline, cause then for every pixel I'm not calculating 20 surrounding pixel values, I'm just calculating one. I need to setup a second Tex2D that's written with the values of that posterization, and then use that to calculate all that other junk, but Google hasn't been cooperative in helping me figure that out, so let me know if you know how to do this! For each pixel I'm calculating I'm also doing tex2D (AliveSplats, UV ) + tex2D (DeadSplats, UV), and it'd be more efficient if I just combined the textures first and called tex2D() just once, right? Another thing I'm not sure on how to do :/

Instead of blending, I'd use a shader that picks the max channel before thresholding, and uses that as the color. Then two splats near each other will form a neat dividing line, with the same curving that metaball outlines have.

Unfortunately if you want newer splats overwriting older ones, I think you will need a texture that is never cleared.
You're absolutely right! Creating a camera that never clears specifically for "dead" splats was the answer Smiley

So then I had two materials being rendered, one for "alive" splats (those that are airborne and shouldn't streak across the screen), and one for "dead" splats, that are written to a camera that's never being cleared. This is great! I don't have to do any memory management too because all the particles die within a second or two after throwing the goop, and their resulting splats live on!


But there's another problem, alive splats are all laid on top of dead splats, which works, but it sort of breaks the metaball magic I have going on when moving particles are overlaid on top of still splats. So instead of having two shaders/materials, I now combine the color values from both the alive and dead RenderTextures.

AND IT LOOKS FANTASTIC!!! Both behaviors combine seamlessly in a single pass!


 This looks even better at 60fps but LICECAP only gives me .gif's at like 15 or so Sad


Thank you all SO MUCH for helping me! Let me know if you know how to do those two optimizations I mentioned earlier or anything else like that! Smiley
Logged
oahda
Level 10
*****



View Profile
« Reply #9 on: November 02, 2015, 12:52:24 PM »

NICE.
Logged

zilluss
Level 1
*



View Profile
« Reply #10 on: November 04, 2015, 06:05:23 AM »

I love it. I recently had the same idea (because of my Splatton addiction lately), but your implementation looks waaaaaay better than what I did.
Do you use a fluid particle plugin for the splats or off-the-shelf bodies?

To get rid of some of the if statements you can use smoothstep I think. Looking up neighbouring pixels works faster when you fetch the pixels in the vertex shader because apparently, the driver optimizes this. I create quite a similar effect in my game (See here) and use only one pixel lookup. I can send you the shader code but it's OpenGL, so you'll need to translate it.
Logged

@zilluss | Devlog  Hand Point Right
DazeHill
Level 0
*


View Profile
« Reply #11 on: November 23, 2015, 05:57:27 PM »

Maaaaaaaaaaan! If you knew how much I wish I could do this kind of thing! I know nothing of graphics programming/shaders and I searched everywhere on the assets store for this to no avail... this is genius!
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic