3
\$\begingroup\$

I'm trying to learn writing shaders. And I've pieced together something that is kinda working. I want to create a transparent glow around a sphere. The problem I have is that I can't seem to alter the transparency of the glow. I tried experimenting with ZWrite off but that doesn't give me the desired results.

The red part around the sphere is the glow. But I'm unable to change its alpha. I'd would also like to change the "blurriness" of the glow. How would I do that?

EDIT

so I did some more tinkering. I've changed the blending to
Blend SrcAlpha OneMinusSrcAlpha and enabled ZWrite off. This allows me to change the alpha. The problem with this is that the inside of the object is also colored by the glow. I just want the glow around the circle. not inside.

enter image description here

Shader "Custom/HoleShader" {
Properties {
    _holeColor ("Color", Color) = (1,1,1,1)
    _glowColor ("Glow Color", Color) = (1,1,1,1)
    _glowSize ("Glow Size", Range (0.0,5)) = 1.0
    _glowOpacity ("Glow Opacity", Range(0,1)) = 1
}
SubShader {
Tags { "LightMode" = "ForwardBase" }
    Pass {
        CGPROGRAM
        #pragma vertex vert 
        #pragma fragment frag
        uniform float4 _holeColor;
        uniform float4 _glowColor;

        struct appData {
            float4 normal : NORMAL;
            float4 vertex : POSITION;
        };

        struct v2f {
            float4 pos : SV_POSITION;
            float4 col : COLOR;
        };

        v2f vert (appData v) {
            v2f o;
            o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
            return o;   
        }

        float4 frag(v2f i) : COLOR {
            return _holeColor;
        }
        ENDCG
    }
    Tags { "LightMode" = "ForwardBase" "Queue" = "Transparent" "RenderType" = "Transparent"}
    Pass {
        ZWrite Off
        //Blend One OneMinusSrcColor
        Blend SrcAlpha OneMinusSrcAlpha
        CGPROGRAM
        #pragma vertex vert 
        #pragma fragment frag
        uniform float4 _holeColor;
        uniform float4 _glowColor;
        uniform float _strength;
        uniform float _glowSize;
        uniform float _glowOpacity;

        struct appData {
            float4 normal : NORMAL;
            float4 vertex : POSITION;
        };

        struct v2f {
            float4 pos : SV_POSITION;
            float4 col : COLOR;
            float3 viewDirection;
            float3 normalDirection;
        };

        v2f vert (appData v) {
            v2f o;
            float4 pos = v.vertex + (v.normal * _glowSize);
            o.pos = mul(UNITY_MATRIX_MVP,pos);
            return o;   
        }

        float4 frag(v2f i) : COLOR {
            return float4(_glowColor.rgb, _glowOpacity);
        }
        ENDCG
    } 
}
}
\$\endgroup\$
3
  • \$\begingroup\$ To clarify: You want the glow to be around the whole sphere including over the middle part and not just from the edges? \$\endgroup\$
    – Tim
    Dec 8, 2015 at 16:32
  • \$\begingroup\$ I want it just around the edges and not the middle part. you could say that it should be like a blurred stroke almost. \$\endgroup\$ Dec 8, 2015 at 23:03
  • \$\begingroup\$ That changes things immensely, I've updated my answer to reflect that, hopefully it might somewhat tell you what you need. \$\endgroup\$
    – Tim
    Dec 9, 2015 at 8:51

1 Answer 1

5
\$\begingroup\$

In my opinion the best way to generate a glow around an arbitrary object is by using the geometry shader to detect edges and extrude new faces, there are no doubt other ways that work as well or even better and you can google around for those, but I'll cover my way doing edges.

Full disclosure: I don't know Unity or glsl so I can't give direct code but I'll try to explain in a general manner.

Geometry Shaders

A geometry shader is a part of the graphics pipeline similar to the pixel(fragment) & vertex-shaders. Unlike those two though the geometry shader operates once on each primitive, a primitive being triangles lines or points.

The geometry shader doesn't just use primitives as input it can also output up to a defined max of new primitives, this is the true power of a geomotry shader, it can be used to cull primitives and/or expand them.

Edge Detection

I said earlier that the geometry shader works on primitives such as triangles lines or points, this was not a definite list and there is one primitive that is of particular intrest to us:

The Triangle adjecant

https://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx

The triangle adjecant provides not only data for the triangle but for all neighbouring triangles. If the main triangle faces the camera and an adjecant triangle does not then the triangle lies on the edge and we can proceed.

To check if a triangle is backfacing calculate it's normal and dot product it with the cameras normal. I'll leave the details of the calculation as an exercise to the reader, it's not hard.

Face Extrusion

Now we come to the tricky part, start by drawing a line from the camera to an arbitrary point on the edge and use the cross product of this line and the edge to get the direction of where to extrude the new face, we'll call this e, make sure to normalize it.

Create two new points x distance from the edge points in the direction of e, x here being a glow amount. From these two new points and the edge we can output a new face in the geometry shader and create a glow around the object.

But wait!

This will only work if the edge is completly straight or concave*, if the edge is convex we'll have a gap.

enter image description here

To solve this first project the edge point normals on the vector e this creates two new vectors n1 and n2, make sure to normalize these too.

Like before create two new points x distance from the edge points in the direction of n1 and n2 and create new faces from these points, this will create a more robust glow.

enter image description here

But wait again!

Like I alluded earlier this only works sort of on a concave edge there will be coverage but you're probably gonna get wierd results. To solve this check if an edge is concave and in that case skip extruding in the direction e and just extrude in the direction of v1 or v2.

enter image description here

Now we're done

Hopefully I might have somewhat answered your question or at the very least given you a direction to head in, I'll try to update this later with better images and explanations and hopefully someone more knowledgeable in opengl or Unity can give a more detailed answer.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .