Unity3d Shader God Ray the light of the Lord

Source: Internet
Author: User
Tags mul

another post-process effect, God Ray, the light of God, is the needle-like glow of a circle around the sun when we look at the sun again.
First put the group effect, the scene resources of this article are from the light ink God, the effect of this article shader effect




added the previous HDR and bloom effects: Links




The code of this article is from a great God in the unity Holy Scriptures, the blogger made a small improvement link
And then to do the next explanation, a total of two shader, a responsible for the production of Ray, a responsible and original screen image mix, on the original screen image mixing is simple, is simply the two image of the color overlay, control Ray's weight,
Next, we'll focus on making Ray's shader.
is a fragement shader
A total of 4 external variables
_screenlightpos the position of the light on the screen, this needs to be calculated and sent out in the C # script, which will be explained later
_density density
_decay Attenuation
_exposure exposure, used to control brightness, we all know, in the camera, the longer the exposure time, the brighter the image

First look at vertex shader
v2f Vert (v2in v) {v2f O;o.pos = Mul (UNITY_MATRIX_MVP, V.vertex); Half2 Texcoord = v.texcoord;half2 Deltatexcoord = TexCoord -_screenlightpos.xy;deltatexcoord *= 1.0F/8 * _density;texcoord-= Deltatexcoord;o.uv0 = TexCoord;texCoord-= DeltaTexC Oord;o.uv1 = Texcoord;texcoord-= Deltatexcoord;o.uv2 = Texcoord;texcoord-= Deltatexcoord;o.uv3 = TexCoord;texCoord-= de LTATEXCOORD;O.UV4 = Texcoord;texcoord-= DELTATEXCOORD;O.UV5 = Texcoord;texcoord-= DELTATEXCOORD;O.UV6 = TexCoord; Texcoord-= Deltatexcoord;o.uv7 = Texcoord;return o;}

V.texcoord the coordinates of the current point

Deltatexcoord is the inverse vector of the current point to the light point, and the length is two points between the distance

The greater the density, the greater the Deltatexcoord, and the more 8,deltatexcoord is always a fraction.
The first sample point is the original location
The sampling point is gradually connected to the light source.
_density Larger sample point spacing
From 0 to 7, the position of the point is getting closer from the light source and farther away from here.
Look at our v2f structure, how many coordinate points are saved?
struct V2F {float4 pos:position;float2 uv0:texcoord0;float2 uv1:texcoord1;float2 uv2:texcoord2;float2 Uv3:texcoo RD3;FLOAT2 uv4:texcoord4;float2 uv5:texcoord5;float2 uv6:texcoord6;float2 Uv7:texcoord7;};

struct-body v2in for incoming values

struct v2in {float4 vertex:position;float2 texcoord:texcoord0;};


we get the coordinates of the eight points in a straight line from the current point to the light source point, for fragement shader color mixing
Of course this step can also be done in fragement shader, but the efficiency is not vertex shader good, because each pixel is not sampled, but each vertex sampling is good

and see Fragement Shader.


    Half4 Frag (v2f i): COLOR    {        half illuminationdecay = 1.0f;        Half4 color = tex2d (_maintex, i.uv0) *illuminationdecay;        Illuminationdecay *= _decay;        Color + = tex2d (_maintex, I.uv1) *illuminationdecay;        Illuminationdecay *= _decay;        Color + = tex2d (_maintex, I.uv2) *illuminationdecay;        Illuminationdecay *= _decay;        Color + = tex2d (_maintex, I.uv3) *illuminationdecay;        Illuminationdecay *= _decay;        Color + = tex2d (_maintex, i.uv4) *illuminationdecay;        Illuminationdecay *= _decay;        Color + = tex2d (_maintex, i.uv5) *illuminationdecay;        Illuminationdecay *= _decay;        Color + = tex2d (_maintex, i.uv6) *illuminationdecay;        Illuminationdecay *= _decay;        Color + = tex2d (_maintex, i.uv7) *illuminationdecay;        Color/= 8;        Return Half4 (COLOR.XYZ * _exposure, 1);    }

Illuminationdecay light Attenuation, _decay is our externally controllable attenuation

_exposure Increase Brightness

adjust the proportion of pixels from here the farther away that is, the closer the attenuation from the light source, one might ask, why? Because we still want to retain most of the color for this point, if the other pixel weights too large, it will cause the point color is inaccurate, or even bad blur effect.
Then is the process of color, the basic principle is to make countless rays from the light source, well, you can understand.

Ray we made it, and then we need to mix Ray Ray and the original screen image, this step is relatively simple, just give the source code, you have the tacit.

shader "Custom/god Ray 2 Blend" {Properties{_maintex ("Base (RGB)", 2D) = "" "{}_godraytex (" G OD (RGB) ", 2D) =" "{}_alpha (" _alpha ", Float) = 0.5}//Shader code pasted into all further cgprogram Blockscginclude#includ E "Unitycg.cginc" struct v2in {float4 vertex:position;float2 texcoord:texcoord0;}; struct V2F {float4 pos:position;float2 uv:texcoord0;}; sampler2d _maintex;sampler2d _godraytex;uniform float _alpha;v2f vert (v2in v) {v2f O;o.pos = Mul (UNITY_MATRIX_MVP, V.vertex); o.uv = V.texcoord;return o;} Half4 Frag (v2f i): Color{half4 color = tex2d (_maintex, I.UV) + tex2d (_godraytex, i.uv) *_alpha;//half4 COLOR = tex2d (_main Tex, I.UV); return color;} endcgsubshader{tags{"Queue" = "Transparent"}pass{zwrite offbindchannels{bind "Vertex", Vertexbind "Texcoord", Texcoord0bind "Texcoord1", texcoord1}fog{Mode off}cgprogram#pragma fragmentoption arb_precision_hint_fastest #pragma Vertex vert#pragma fragment Fragendcg}}fallback off}//Shader 



And then the final step, and a very important step, is to get it on the screen through a script,
The point here is to ask for the position of the light source in the screen,
There is a function in the camera class to convert world coordinates to screen coordinates
Camera.worldtoscreenpoint (position)
The official website is described below
Transforms position from the world space into the screen space.
Convert position from world coordinates to screen coordinates
Screenspace is defined in pixels. The bottom-left of the screen is (0,0); The Right-top is (pixelwidth,pixelheight). The z position is on world units from the camera.
The lower left corner is the origin of the screen coordinate system, the upper right corner is the maximum range of the screen, the light source beyond this range we do not do God ray rendering, as a judgment, otherwise will be wrong rendering, the screen is still flashing beyond the range of light.

We pass the transport of the light source into the script and test the position of the light source
It is also important to judge the light source in front of the camera or in the back, if only to determine whether in the screen, the camera will be rendered behind the light source of God Ray, the solution here, the Z-value returned by Worldtoscreenpoint is the distance between the light source and the camera in world space, vector, So we can use Z-value plus or minus to judge before and after, for the regular light source in front of the camera can render God ray, a negative light source after the camera does not render God Ray
if (lightscreenpos.z > 0 && lightscreenpos.x > 0 && lightscreenpos.x < camera.pixelwidth &AMP;&A mp Lightscreenpos.y >0 && Lightscreenpos.y < Camera.pixelheight)

In fact, so the rendering can be, but the effect is not good, God Ray became "God Point", the reason just analyzed, shader principle is to take points to the light source of eight points, the result of the rendering is a lot of points, the level is very clear, because of the confusion and the 8 times, The solution is to render it multiple times, and it becomes a line.
We want to make it a little more effective.
Set up two rendertexure Temprta and TEMPRTB to pass value to each other

Graphics.blit (sourcetexture, Temprta, material);
The first filter result exists Temprta
Upload to next render do _maintex
Graphics.blit (Temprta, TEMPRTB, material);
Again out TEMPRTB to the third render, and then out Temprta ...
Graphics.blit (TEMPRTB, Temprta, material);
Graphics.blit (Temprta, TEMPRTB, material);
Graphics.blit (TEMPRTB, Temprta, material);
Finally make a mix and spread ray texture to blend shader as Godraytex. And get the final result.
Materialblend.settexture ("_godraytex", Temprta);
Graphics.blit (Sourcetexture, Desttexture, materialblend, 0);

The code is as follows:

Using unityengine;using System.Collections;    [Executeineditmode]public class godray2:monobehaviour{public Transform lightpos;    Public Shader Curshader;    Public Shader Curshaderblend;    Private Material curmaterial;    Private Material curmateriablend;    Public Vector4 Screenlightpos = new Vector4 (0, 0, 0, 0);    public float Density = 0.01f;    public float Decay = 0.5f;    public float Exposure = 0.5f;    public float Alpha = 1;    Public rendertexture Temprta = null;    Public rendertexture TEMPRTB = null;    Private Vector3 Lightscreenpos;                #region Properties Material Material {get {if (curmaterial = = null) {                curmaterial = new Material (Curshader);            Curmaterial.hideflags = Hideflags.hideanddontsave;        } return curmaterial;                }} Material Materialblend {get {if (curmateriablend = = null) { Curmateriablend = new MaterIal (Curshaderblend);            Curmateriablend.hideflags = Hideflags.hideanddontsave;        } return curmateriablend; }} #endregion void Start () {if (!            systeminfo.supportsimageeffects) {enabled = false;        Return        } if (!curshader &&!curshader.issupported) {enabled = false;        }} void Onrenderimage (Rendertexture sourcetexture, rendertexture desttexture) {if (Curshader! = null)            {Lightscreenpos = Camera.main.WorldToScreenPoint (lightpos.position); if (lightscreenpos.z > 0 && lightscreenpos.x > 0 && lightscreenpos.x < camera.pixelwidth &AMP;&A mp Lightscreenpos.y > 0 && lightscreenpos.y < camera.pixelheight) {material. Setvector ("Screenlightpos", New Vector4 (Lightscreenpos.x/camera.pixelwidth, lightscreenpos.y/camera.pixelheight, 0                , 0)); //   Material.                Setvector ("Screenlightpos", Screenlightpos); Material.                SetFloat ("Density", Density); Material.                SetFloat ("Decay", Decay); Material.                SetFloat ("Exposure", Exposure);                Materialblend.setfloat ("Alpha", Alpha);                Createbuffers ();                Graphics.blit (sourcetexture, Temprta, material);                Graphics.blit (Temprta, TEMPRTB, material);                Graphics.blit (TEMPRTB, Temprta, material);                Graphics.blit (Temprta, TEMPRTB, material);                Graphics.blit (TEMPRTB, Temprta, material);                Materialblend.settexture ("_godraytex", Temprta);                Graphics.blit (Sourcetexture, Desttexture, materialblend, 0);            Graphics.blit (Temprta, desttexture, material, 0);            } else {graphics.blit (sourcetexture, desttexture); }} else {graphics.blit (sourcetexture, Desttexture);  }} void Createbuffers () {if (!temprta) {Temprta = new Rendertexture (SCREEN.WIDTH/4,            SCREEN.HEIGHT/4, 0);        Temprta.hideflags = Hideflags.dontsave;            } if (!TEMPRTB) {TEMPRTB = new Rendertexture (SCREEN.WIDTH/4, SCREEN.HEIGHT/4, 0);        Temprtb.hideflags = Hideflags.dontsave;        }} void Ondisable () {if (curmaterial) {destroyimmediate (curmaterial); }    }}




This shader has several shortcomings, in the relatively dark scene do not use, because the light source is not bright, so the effect is not good, ray quality is not high, from the example can be seen, Ray is not clear, here can be compared with unity Imageeffect sun shafts

Put two sets of effects on the end



The shining light in the forest





------by wolf96 http://blog.csdn.net/wolf96


Unity3d Shader God Ray the light of the Lord

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.