Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correctly render semi-transparent sphere in Unity5

I'm making a space exploration game in Unity and I'm having two problems with semi-transparency.

Each planet is made up of two spheres: One is the combined surface and cloud layer, the other (with a slightly larger radius) depicts the horizon 'glow' by culling front faces and fading alpha toward the outer edge of the sphere. This is MOSTLY working fine, but with the following two problems:

1) In my custom surface shader, when I use the alpha keyword in the #pragma definition, alpha is factored into the rendered sphere, but the 'glow' sphere disappears at a distance of a few thousand units. If I DON'T include the alpha keyword, the sphere does not fade toward the edge, but it renders at distance.

2) Despite trying all RenderType, Queue, ZWrite and ZDepth options, the surface sphere and 'glow' sphere are z-fighting; the game can't seem to decide which polygons are nearer - despite the fact near faces on the glow sphere should be culled. I have even tried pushing the glow sphere away from the player camera and expanding its radius by the same proportion, but I'm STILL, inexplicably, getting the z-fighting between the spheres!

Is there any setting that I'm missing that will enable the 'glow' sphere to be always drawn BEHIND the surface sphere (given that I have tried ALL combinations of ZWrite, ZDepth as detailed above) and is there a way to have an alpha-enabled object NOT disappear at distance?

I cannot seem to figure this out, so any help will be well appreciated!

EDIT
Here's the shader code for my 'glow sphere'. Front faces are culled. I've even tried the Offset keyword to 'push' any drawn polygons further from camera. And I've tried all of the Tag, ZWrite and ZTest options I've been able to find. The shader gets passed a tint Color, an atmosphere density float and a sun direction vector...

Shader "Custom/planet glow" {
    Properties {
        _glowTint ("Glow Tint", Color) = (0.5,0.8,1,1)
        _atmosphereMix ("Atmosphere Mix", float) = 0
        _sunDirection ("Sun Direction", Vector) = (0, 0, 0, 0)
    }
    SubShader {
        Tags { "RenderType" = "Opaque" "Queue" = "Geometry" }
        Cull Front // I want only the far faces to render (behind the actual planet surface)
        Offset 10000, 10000
        ZWrite On // Off also tried
        ZTest LEqual // I have tried various other options here, incombination with changing this setting in the planet surface shader

        CGPROGRAM
        #pragma surface surf Lambert alpha
        #pragma target 4.0

        struct Input {
            float3 viewDir;
        };

        fixed4 _glowTint;
        float _atmosphereMix;
        float4 _sunDirection;   

        void surf (Input IN, inout SurfaceOutput o) {
            _sunDirection = normalize(_sunDirection);
            o.Albedo = _glowTint;
            float cameraNormalDP = saturate(dot( normalize(IN.viewDir), -o.Normal ) * 4.5);
            float sunNormalDP = saturate(dot( normalize(-_sunDirection), -o.Normal ) * 2);
            o.Alpha = _atmosphereMix * sunNormalDP * (cameraNormalDP * cameraNormalDP * cameraNormalDP); // makes the edge fade 'faster'            
            o.Emission = _glowTint;
        }

        ENDCG
    } 
    FallBack "Diffuse"
}
like image 256
moosefetcher Avatar asked Feb 05 '16 13:02

moosefetcher


1 Answers

Have you thought about rendering large objects in a different scale in another camera to create dynamic skybox? That will certainly resolve z-fighting issues. You can have, for example, two cameras - one that renders objects in range 0.1-1000, and other, that ranges from 1000 to 100000.

The additional optimization can include rendering environment from afar to the cube skybox and do that not every frame (except maybe special occasions when you destroy a planet from afar).

There is also another optimization concern - you could render a flat ring around the planet, rotated to face the camera, to avoid overdraw on the actual planet surface at all. But that will require more complex lighting calculations, apparently.

Also, have you tried your transparent shader on a camera that does not have Skybox as clear flags? Check this answer on how to use custom skybox.

like image 114
mcfrei Avatar answered Sep 22 '22 14:09

mcfrei