Plan for today is to continue yesterdays task from previous post. Afterwards I am going to come back to creating render target of particles, but with own compositor.
I am sure that solution from topic
would be 100% correct only if particle colour was always white.
I still thank You for that link.
I found it very usefull, especially for tests and it got me thinking on universal solution.
My solution is doing universal alpha blending without background (but with saving and passing a parameter of accumulated alpha), so that it could be used with any background and any possible colour and aplha of particles (eveb black particles).
As I see It, in current solution from level of application, what happens wrong is:
Code: Select all
For every texture coordinate:{
initial colour RGBA is [0,0,0,1];
For each rendered semi-transparent object (with colour delta.rgba) from most distant, to the closest, the previous colour is taken and replaced with very simple alpha-blending output:{
if(depth test passed){
new.a=1;
new.rgb=old.rgb*(1-delta.a) + delta.rgb*delta.a;
}
old = new;
}
}
then there is a trick that "try to guess output alpha".
From the level of of own shader, It could be done more properly. With initial colour RGBA [whatever,whatever,whatever,0].
also new alpha of accumulated layer of particles should be universal, so after concatenation:
Desired weight of solodObjectsColour in finalColour should be:
(1-delta[1].a)*(1-delta[2].a)...(1-delta[N].a)
[we can deduce it from equation of final colour final on NVIDIA article
http://http.developer.nvidia.com/GPUGem ... _ch23.html]
p 3 = d(1 - a1)(1 - a2)(1 - a3) + s 1a1(1 - a2)(1 - a3) + s 2a2(1 - a3) + s 3a3.
It is obvious, that this weight is equal: (
1-accumulatedPartices[N].a).
That means that accumulatedParticles[N].a that we are looking for (achieved after accumulating N particles that passed depth test) is equal:
1 - (1-delta[1].a)*(1-delta[2].a)...(1-delta[N].a)
Let's do something simmilar to mathematical induction to check how to calculate alpha iteratively (I could pass multiplication to another output targer, but I think it could be done in-situ, modifying accumulatedParticles[N].a from prvious iteration accumulatedParticles[N-1].a.
My hypothesis is that it is calculated just like colours. ( EDIT: it was close estimation, read more to find the correct answer)
For N-1 itereations, we have:
accumulatedParticles[N-1].a = 1 - (1-delta1.a)*(1-delta2.a)...(1-delta[N-1].a)
[*]
(1-delta1.a)*(1-delta2.a)...(1-delta[N-1].a) = 1 - accumulatedParticles[N-1].a
also:
(1-delta1.a)*(1-delta2.a)...(1-delta[N-1].a)*(1-delta[N].a) = 1 - accumulatedParticles[N].a
that is why
[**]
(1-delta1.a)*(1-delta2.a)...(1-delta[N-1].a) = (1 - accumulatedParticles[N].a)/(1-delta[N].a)
from [*] and [**] we have:
1 - accumulatedParticles[N-1].a = (1 - accumulatedParticles[N].a)/(1-delta[N].a)
(1 - accumulatedParticles[N-1].a) * (1 - delta[N].a) = 1 - accumulatedParticles[N].a
So recirsive equation that what we are looking for is:
accumulatedParticles[N].a =
1 - (1 - accumulatedParticles[N-1].a)*(1 - delta[N].a) =
1 - (1 - delta[N].a - accumulatedParticles[N-1].a + accumulatedParticles[N-1].a*delta[N].a) =
[***]
delta[N].a + accumulatedParticles[N-1].a - accumulatedParticles[N-1].a*delta[N].a
My hypothesis was that it is calculated like colours
accumulatedParticles[N].a = accumulatedParticles[N-1].a * (1 - delta[N].a) + delta[N].a * delta[N].a
It turns out that it is slightly different, cose if we transform [***], we get:
[****]
accumulatedParticles[N].a = accumulatedParticles[N-1].a * (1 - delta[N].a) + delta[N].a
Te difference is:
(equation like for colour channels) - delta[N].a * delta[N].a + delta[N].a.
Ok...so hypothesis was wrong, but yey- we have recursive equation now, so we do not need another parameter - it can be passed in alpha channel in every iteration.
Let's check if [****] is correct...
For example, if we add solid particle, we shoud get new alpha that is equal 1.
accumulatedParticles[N].a = accumulatedParticles[N-1].a * 0 + 1
When we have something.a in background and we add totally transparent one, we should have no difference. Output should be something.a again.
accumulatedParticles[N].a = accumulatedParticles[N-1].a * 1 + 0
Well, equation
"
accumulatedParticles[N].a = accumulatedParticles[N-1].a * (1 - delta[N].a) + delta[N].a * delta[N].a"
gives the same result here ... so "What is the difference?" one may ask...
This example shows the difference:
We have transparent background (accumulatedParticles[N-1].a=0) and we add particle with transparency 0.5
The output alpha should be 0.5:
accumulatedParticles[N].a = 0*0.5 + 0.5 .... it is ok.
Equation from hypothesis would have given
accumulatedParticles[N].a = 0*0.5 + 0.25, so It seems that new equation is fine and one from hypothesis was wrong.
Youpiaiey!!!
- It works like I wanted.
That is how the right scenario of own shader will look like:
Code: Select all
For every texture coordinate:{
initial colour RGBA is [whatever,whatever,whatever,0];
For each rendered semi-transparent object (with colour delta.rgba) from most distant, to the closest, the previous colour is taken and replaced with alpha-blending output fo calculating only new layer without background:{
if(depth test passed){
new.rgb=old.rgb*(1-delta.a) + delta.rgb*delta.a;
new.a=old.a*(1-delta.a) + delta.a;
}
old = new;
}
}
In the end we do not need any suspiciould tricks :).
PS:
This is not very important thought, but let's mention it anyway:
I'll sligtly modify my proposition:
Code: Select all
(...)
if(depth test passed){
new.rgba = old.rgba*(1-delta.a) + delta.rgba*delta.a;
new.a += (1-delta.a)*delta.a;
}
(...)
We calculate everything on graphic card, so matrix and vector operations can be paralellised. Maybe it is few nanoseconds faster then, to calculate the same equation for every channel: RGB, but also A (it takes the same amount of time, they are calculated paralelly) and then add difference to aplha channel.
The difference is:
- delta[N].a * delta[N].a + delta[N].a = (1-delta[N].a)*delta[N].a;
Like I said, it is not that important - if it does not accelerate very little, It won't slow down too much neither.