Thread: Alpha blending w/o color loss

  1. #31
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    The order in which they are rendered has little to do with how the phenomena works in real life. The alpha blended images must be drawn after all other images or the alpha blending fails. As well I would have to create a light-based clipping volume to cause the planets to disappear and or include another lighting variable that the planets would test against to see if they would in fact be visible. This is not a 3D sun. All of my sun's and light sources are accomplished using 2D billboards with a technique that although criticized on this board is used quite often and I've found it in several books as well.

    There is not any depth sorting going on yet in this engine which cause the alpha blended billboards to incorrectly be drawn on top of by the planets. The billboards do not write to the zbuffer and as such do not exist according to the buffer. But this has to be done so that my billboards can be transparent in places which is necessary for a sun. I've seen other sun corona effects with pixel shaders in Shader X2: Tips and Tricks but I've not been impressed with them.

    I am frustrum culling simply based on the camera look vector right now which is not totally perfect since the dot product will produce values that pass the test, yet should not be drawn because they do not lie in the frustrum. The next phase is to test against the cube generated by the frustrum and then clip against the six sides of the volume. However, I'm not sure this is worth the extra cycles at this point. At the very least, the only objects affected by my not so perfect cull algo are those that lie between 0 and about .30 on either side of the camera. This, of course, also depends on the actual position of the object. I'm only culling based on the planet position vector, not based on the actual vertices of the planet which would be a very costly cull.

    I'm going to do sun coronas by additive alpha blending another texture onto the billboard. I'm not sure yet if I'm going to generate this procedurally inside of a pixel shader or if I'm going to use a static one. Although it would be cool to see the sun actually surge and change shape, I'm not so sure it would look right at great distances.

    I'm also going to change all planets to progressive meshes and perhaps add 3 materials and textures per planet.

    The next step right now is to implement my pixel shader. I'm not so sure I'm going to include specular calculations because planets by their very nature are not shiny. So I'll probably leave the specular calculation for another shader that could be applied to more metallic surfaces. I'd like to do some bump mapping as well but I need to be careful about the level of detail on the planets or the illusion of distance and vastness of space will be lost.

    The sun glare quad is rendered last and it has to be. The sun, since it is a billboard, is rendered after the non-alpha blended polies in the same manner as the explosions, nebulas, lasers, etc.

    If you have any further suggestions on the engine I'm all ears.

  2. #32
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Quote Originally Posted by Perspective
    From that site:
    The outermost layer of the sun is the corona. Only visible during eclipses,
    So, the "corona" you actually see is a phenomenon in your eye.

    I'm not criticizing the particlar mehtod you've chosen to implement stars Bubba, I'm just saying that planets aren't visible in front of a sun and that planets don't hide the corona or the streaks when they are "in front" of them.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  3. #33
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I've come up with some possible answers to the problem. The reason you cannot see the corona normally is because you are being bombarded with light rays coming directly at you this obscuring the corona. While I cannot simulate all the light rays I can 'fake it'.

    Here is a possible setup. I will borrow from DOOM 3's stencil shadow volumes method.

    First image: this shows the typical stencil shadow volume setup.

  4. #34
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Here is the vector workup for the above image. I rotated it 90 degrees to show the vectors better.

  5. #35
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    And here are some possible solutions to the corona issue.

  6. #36
    ---
    Join Date
    May 2004
    Posts
    1,379
    straight over my head

  7. #37
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Perhaps I didn't do a good job of explaining it.

    Here is the method I will probably use. It is the third method in my last illustration.

    Here is the concept behind it:

    Since we know from geometry that if the dot product of the normal to the plane in question and the light source is >0 the plane is receiving light, we can deduce that the plane as well must be facing the light. Not exactly rocket science. Since I'm already going to be computing the dot product at the vertices and interpolating in my pixel shader I can use this information to produce my sun corona effect around the planet.

    Essentially if the surface being lit is being lit by a sun or a bright object then I must create the billboard corona around the planet or object in question. This will be a very very bright billboard that is alpha blended and additive blended with the background and with the object. I will also be able to limit the billboard being drawn to certain angles like dot>.70. This would equate to about -45 to +45 degrees. This means that the corona effect will only be drawn if the object in question is within -45 to +45 degrees of the light source. This will prevent corona's from being drawn outside of the actual sun billboard which would look very strange.

    But to do this I need a couple more pieces of information in my class. Each light source that is extremely bright must have a smaller sampling of a very bright corona-like texture that will be then passed to the object(s) that fall within the correct range for the effect. I also will probably need to maintain the normalized vector for the light source so that I do not have to normalize it later thus wasting processor cycles.

    I will attempt to implement this very soon because I like the idea of objects being obscured by extremely bright light sources.
    Last edited by VirtualAce; 10-27-2004 at 01:05 AM.

  8. #38
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    And there are some errors in my picture.
    It was very hard to get the text to look right since it was so lengthy.

    Here is the vector workup.

    The first thing that must be done is find the vertexes that are silhouette edges - or vertexes that lie at the edge of the occluder object. This is a time consuming process and is far beyond the scope of this post so I will skip it for now.

    Let's just say we already know the edge vertexes and they are stored in EdgeVertex[].

    The variables
    Our light source position is Light.Pos and is a Vector3 or D3DXVECTOR3 - 3 floats.

    Known values/equations
    We know where the occluder is in world space. We know where the light is in world space.
    We also know the parametric equation for a line.

    Code:
    newPoint=Origin+(Vector*Distance);
    For example if we want to extend point A at an angle of 30 degrees and a distance of 100 units in 2D:

    Code:
    ExtendedA.x=A.x+(cos(DEGTORAD(30))*100);
    ExtendedA.y=A.y+(sin(DEGTORAD(30))*100);
    To extend a 3D line from VertexA in the direction of 3D vector V for a known distance D to create VertexB we do this:

    Code:
    VertexB.x=VertexA.x+(V.x*D);
    VertexB.y=VertexA.y+(V.y*D);
    VertexB.z=VertexA.z+(V.z*D);
    or in Vector notation:
    Code:
    VertexB=VertexA+(V*d);
    This is just a simple displacement.

    Back to the shadow volumes
    Ok so we know the light source position and the vertex edge in question.

    The vector from the occluder vertex edge to the light is:
    Code:
    Vector3 LightVector(EdgeVertex[i].Pos-Light.Pos);
    This must be normalized so we can work with unit vectors. Otherwise we will get some very large values and it will complicate the math.

    Code:
    nrmLightVector=Normalize(LightVector);
    This is just a simple:
    Code:
     
    ...
    float length=sqrt((LightVector.x*LightVector.x)+(LightVector.y*LightVector.y)+(LightVector.z*LightVector.z));
     
    float oneOverLength=1.0f/length;
     
    nrmLightVector3.x=LightVector.x*oneOverLength;
    nrmLightVector3.y=LightVector.y*oneOverLength;
    nrmLightVector3.z=LightVector.z*oneOverLength;
    ...
    Ok so now we have a normalized light vector called nrmLightVector. Let's say we want to extend our shadow for our object for 100 units. In actuality you would either compute the angle of the light source in relation to the actual height/width of the object. After all shadow lengths are proportional to the width/height of an object and the angle of the incoming light rays. But we are just going to use 100. Our shadow is going to be 100 units long.

    Our new shadow vertex is:
    Code:
    ShadowVertex=EdgeVertex[i]+(nrmLightVector*100.0f);

    We do this for both sides of the object and for all corner edge vertexes. We don't want to do this for every edge vertex because every edge does not contribute directly to the shadow. For instance in a very tall building that has uniform width all the way to the top. To compute a shadow volume for this we would simply use the top two vertexes that formed the roof and were facing AWAY from the light source. They must be facing away from the light source because if we selected those facing it, the shadow would actually pierce our object. Not what we want.

    Again this is not totally correct because of our 'fake' shadow distance but it is close enough for simplicity's sake.

    So now we have created two new vertexes from two edge vertexes on our object. The only thing we do now is cap them with a line at the far end and near end (draw a horizontal line between the two new vertexes and draw a line between the two known vertexes). These act as our shadow volume 'caps'. Note that I'm only using two vertexes to explain this, but in actual practice you would probably have more. Now triangulate the shadow volume. You are done with the shadow volume.

    After this comes the important part of figuring out what lies in shadow and what does not based on depth-fail or depth-pass methods so we can paint the stencil buffer correctly. After we figure this out we then render the shadow volume into the stencil buffer. Pixels that fail the stencil buffer test get 'darkened'. How dark is up to you. Pixels that pass the test are simply rendered as is.

    There is a lot more to the technique - far more than I can explain here. But that is the general idea of it.
    Last edited by VirtualAce; 10-27-2004 at 01:03 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Direct3D10 Sprites Alpha Blending
    By DarkMasterBosel in forum Game Programming
    Replies: 0
    Last Post: 01-17-2009, 07:17 AM
  2. Replies: 23
    Last Post: 07-09-2007, 04:49 AM
  3. 2 questions in DirectX
    By X PaYnE X in forum Game Programming
    Replies: 4
    Last Post: 12-02-2004, 09:38 AM
  4. Alpha blending rocks
    By VirtualAce in forum Game Programming
    Replies: 12
    Last Post: 04-06-2004, 08:08 PM
  5. Alpha blending
    By SMurf in forum Game Programming
    Replies: 3
    Last Post: 08-29-2003, 06:50 PM