Search Unity

Question Raymarching Alpha Not Applying Correctly

Discussion in 'Shaders' started by Rook1e0ne, Dec 28, 2020.

  1. Rook1e0ne

    Rook1e0ne

    Joined:
    Apr 27, 2018
    Posts:
    4
    Hi ,
    So i have written a raymarching shader and i have the colors , reflections , shadows working but i have a problem with the color smooth alpha value .

    i am using this equation based on a tutorial i watched and confirmed it through wikipedia on how to calculate smooth alpha
    (backround_color * (1.0 - alpha ) + hit_color * alpha , 1.0) -> and i have hit_color = (0,0,0) if it didnt hit .

    the thing is that when i apply it it does the alpha where the object is but doesent render anything behind the object . (see screenshots to better understand ) .
    i dont know how to fix that so any help would be greatly apreciated .


    Screenshot (667)_LI.jpg Screenshot (668)_LI.jpg Screenshot (669)_LI.jpg
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    That would seem to be doing exactly what you're asking it to do. It's showing the background. It's just that the background in this case is a solid blue since the objects behind the sphere are part of the same shader.

    If you're stopping at the first hit, which is presumably the sphere, then you’re never seeing or rendering the plane behind it, so returning the background color just returns the background color.

    You need to keep marching through the scene if you hit something transparent until you hit something fully opaque or run out of things to march through. And you need to keep track of the current color as you march through the shapes.

    The trick is to keep track of the color multiplied by the alpha, and blend each additional surface with the current color with something like:
    Code (csharp):
    1. // total accumulated color
    2. float4 accColor = 0;
    3. // step through until intersecting a surface, calculate surface color & opacity
    4. // accumulate premultiplied color
    5. accColor.rgb += hitColor.rgb * hitColor.a * (1.0 - accColor.a);
    6. // accumulate opacity
    7. accColor.a += hitColor.a * (1.0 - accColor.a);
    8. // check if accumulated opacity is 1.0, or at least very close to it
    9. if (accColor.a >= (1.0 - epsilon)) // a value of 0.5 / 255.0 is probably a good epsilon here
    10. {
    11.   accColor.a = 1.0;
    12.   // stop marching if opaque enough
    13.   return accColor;
    14. }
    If you want this to “blend” with a predetermined solid background color, then do the same accumulation math as shown above at the end with that color, using an alpha of 1.0 for the background color. If you want this to be able to work with traditionally rasterized objects in the scene, use
    Blend One OneMinusSrcAlpha
    and just return the accumulated color.
     
  3. Rook1e0ne

    Rook1e0ne

    Joined:
    Apr 27, 2018
    Posts:
    4
    yeah ok i believe i understand that . So i tried to apply your code but the result i got was as shown in the pictures.
    (the index of the floor is 0 , the green shpere is 1 , the yellow shpere is 2 , and the red cube is 3 .)


    Screenshot (675).png Screenshot (676).png Screenshot (677).png

    Code (CSharp):
    1.   switch(_objectAtributes.meshCombinationType)
    2.                     {
    3.                         case 0:
    4.                                 resultNext = opU(result.w , object);
    5.                             break;
    6.                         case 1:
    7.                                 resultNext = opUS(result.w , object , blendingAmmount);
    8.                             break;
    9.                     }
    10.                     result.w = resultNext;
    11.  
    12.                     float4 hitColor = _objectAtributes.objColor;
    13.                     //intersection with surface
    14.                     if(resultNext <= raymarchAccuracy)
    15.                     {
    16.                         //culculate color and opacity
    17.                         // accumulate premultiplied color
    18.                         //accColor.rgb += hitColor.rgb * hitColor.a * (1.0 - accColor.a);//same as bellow
    19.                         accColor.rgb = hitColor.rgb * hitColor.a + accColor * (1.0 - accColor.a);
    20.                         // accumulate opacity
    21.                         accColor.a += hitColor.a * (1.0 - accColor.a);
    22.                         // check if accumulated opacity is 1.0, or at least very close to it
    23.                         if (accColor.a >= (1.0 - EPSILON)) // a value of 0.5 / 255.0 is probably a good epsilon here
    24.                         {
    25.                             accColor.a = 1.0;
    26.                             // stop marching if opaque enough
    27.                             result.xyz = accColor.xyz;
    28.                             break;
    29.                         }
    30.                     }
    as a result this code returns a float4 . xyz is for the color and w is for the distance . (the shadows , ambient occl , reflections still work correct i just turned them of here)

    EDIT: All this happens inside a for loop that each time assigned the object i want to the _objectAtributes .
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    I mean, it kind of looks like it's working. Not sure how you're applying the smin() function, as I would expect the color of the yellow sphere to also blend to the color of the red cube between the surface blend. The fact it doesn't and when you fade out the yellow sphere it leaves a red sphere behind makes me think there's a bug with how you're handling blended objects.

    Also from how you changed the accumulation function the ray is marching from far to near?
     
  5. Rook1e0ne

    Rook1e0ne

    Joined:
    Apr 27, 2018
    Posts:
    4
    if i change back to what i had before , the color culculation was :
    Code (CSharp):
    1.  
    2.                     float4 hitColor = _objectAtributes.objColor;
    3.                     if(result.w > object)
    4.                         result.xyz = hitColor.xyz;
    5.                     result.w = resultNext;
    and that returned :
    Screenshot (678).png

    so the color blending here worked correctly .

    Btw : you ask if it was backwards checking . i am not sure is the answer . i mean i just loop all the objects i want to render as the object . in the order that they are assigned not in the order that the ray hits them . i dont know how to do that
    EDIT : actualy : i though some more . in reality i do forward checking . i check for each posision from the camera to a distance . the distance to all objects if it is <raymarch_accuracy . so that might be the problem . is it possible that the problem is that the ray checks serialy all objects but for the blending spaces more than one object is within thay raymarch_accuracy ?
     
    Last edited: Dec 30, 2020