shader之——rain

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shader之——rain相关的知识,希望对你有一定的参考价值。

技术分享

 

1.地面shader

Shader "baicai/me02" {
    Properties {
        _MainTex ("MainTex", 2D) = "white" {}
        _Bump ("Bump", 2D) = "bump" {}
        _Bump02("Bump02",2D) = "Bump"{}
        _DirectionUv("Wet scroll direction (2 samples)", Vector) = (1.0,1.0, -0.2,-0.2)
        _TexAtlasTiling("Tex atlas tiling", Vector) = (8.0,8.0, 4.0,4.0)
        _water ("water",Range(0.01,5)) = 0.2
        _ref("ref",Range(0,1)) = 0.5
        _ReflectionTex("reflectiontex",2D ) = "black"{}
 

       

    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            Tags {
                "LightMode"="ForwardBase"
            }
            
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #define UNITY_PASS_FORWARDBASE
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0

             float4 _LightColor0;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             sampler2D _Bump; 
             sampler2D _Bump02;
             sampler2D _ReflectionTex;
             float4 _DirectionUv;
             float4 _TexAtlasTiling;
             float _water;
             float _ref;


            


            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
                float2 uv : TEXCOORD0;
            };
            struct v2f {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3x3 tangentTransform:COLOR;
                float4 normalScrollUv:TEXCOORD1;
                float4 screen : TEXCOORD2;
                LIGHTING_COORDS(3,4)

            };
            ///需要把顶点着色器中的切线空间转化为世界空间
            ///或者把世界空间的所有向量转化为切线空间  
            v2f vert (VertexInput v) {
                v2f o ;
                o.pos = UnityObjectToClipPos(v.vertex );
                o.uv =TRANSFORM_TEX(v.uv, _MainTex);
                //求世界法线三件套
                float3 normal =normalize( UnityObjectToWorldNormal(v.normal));
                float3 tangentDir = normalize( mul( unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 ) ).xyz );//切线空间转化为世界空间
                float3 bitangentDir = normalize(cross(normal, tangentDir) * v.tangent.w);//切线 法线 计算副切线

                //得出结合切线的世界法线
                o.tangentTransform = float3x3( tangentDir, bitangentDir, normal); 
                //物体世界坐标
            


                o.normalScrollUv = v.uv.xyxy * _TexAtlasTiling + _Time.xxxx * _DirectionUv;
                o.screen = ComputeScreenPos(o.pos);

                TRANSFER_VERTEX_TO_FRAGMENT(o)
                return o;
            }

                float4 frag(v2f i) : COLOR {
                half3 nrml = UnpackNormal(tex2D(_Bump02, i.normalScrollUv.xy));
                nrml += UnpackNormal(tex2D(_Bump02, i.normalScrollUv.zw));
                nrml.xy *= 0.025;
                 
                float2 uvRef = i.screen.xy / (i.screen.w+0001);
                uvRef.y = 1-uvRef.y;
                fixed4 rtRefl = tex2D (_ReflectionTex, uvRef + nrml.xy *_water);


                float3 BumpMap = UnpackNormal(tex2D(_Bump,i.uv));
                float3 N = normalize(mul( BumpMap, i.tangentTransform )); //根据模型的世界法线 将法线贴图转换为世界空间

                float3 L = normalize(_WorldSpaceLightPos0.xyz);
                float atten = LIGHT_ATTENUATION(i);

                float4 col = tex2D(_MainTex,i.uv+nrml.xy *_water);
                float NdotL = saturate(dot( N, L )); //漫反射强            
                col.rgb= col.rgb * (NdotL *_LightColor0.xyz * atten + UNITY_LIGHTMODEL_AMBIENT.rgb) +rtRefl *_ref ;
                

                return col;
            }
            ENDCG
        }
   }
   FallBack "Diffuse"
}

2.反射脚本 跟河流倒影的脚本相同

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ReflectionSelf : MonoBehaviour {

    private Transform refObject;
    private Camera m_camera;
    public LayerMask reflectionMask;
    private RenderTexture m_texture;
    
    void Start () {
        refObject = this.GetComponent<Transform>();
        GameObject refCramera = new GameObject("refCramera");
        m_camera = refCramera.AddComponent<Camera>();
        m_texture = new RenderTexture(Screen.width,Screen.height,24);
        refCameraSet();
    }
    
    /// <summary>
    /// 相机位置及方向
    /// </summary>
        void cameraTrasform()
    {
        //Position  x z 与mainCamera相同  y 到平面的距离与 mainCamera到平面的距离相等
        Vector3 p_ref;
        Vector3 p_main = Camera.main.transform.position;
        Vector3 p_plan = this.transform.position;
        float y = p_main.y - p_plan.y;

        p_ref.x = p_main.x;
        p_ref.y = p_plan.y - y;
        p_ref.z = p_main.z;
        m_camera.transform.position = p_ref;

        //Rotation
        Vector3 R_ref;
        Vector3 R_main = Camera.main.transform.localEulerAngles;

        R_ref.x = -R_main.x;
        R_ref.y = R_main.y;
        R_ref.z = R_main.z;
        m_camera.transform.localEulerAngles = R_ref;
    }

    /// <summary>
    /// 反射相机的设置
    /// </summary>

        void refCameraSet()
    {
        m_camera.backgroundColor = Color.black;
        m_camera.clearFlags = CameraClearFlags.Skybox; 
        m_camera.cullingMask = reflectionMask; //图层
        m_camera.targetTexture = m_texture;
        this.GetComponent<Renderer>().sharedMaterial.SetTexture("_ReflectionTex", m_camera.targetTexture);
    }

  

    


    void Update () {
        //相机位置要放在这里,因为要随着主相机一直运动
        cameraTrasform();


    }
}

3.下雨脚本1

using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;


public class RainManager : MonoBehaviour {
    public float minYPosition = 0;
    public int numberOfParticles = 400;
    public float areaSize = 40;
    public float areaHeight = 15;
    public float fallingSpeed = 23;
    public float particleSize =10f;
    public float flakeRandom = 0.1f;

    public Mesh[] preGennedMeshes;
    private int preGennedIndex = 0;

    public bool generateNewAssetsOnStart = false;

    void Start () {
#if UNITY_EDITOR
        if (generateNewAssetsOnStart)
        {
            // create & save 3 meshes
            Mesh m1 = CreateMesh();
            Mesh m2  = CreateMesh();
            Mesh m3  = CreateMesh();
            
            AssetDatabase.CreateAsset(m1, "Assets/resourcex/" + gameObject.name + "_LQ0.asset");
            AssetDatabase.CreateAsset(m2, "Assets/resourcex/" + gameObject.name + "_LQ1.asset");
            AssetDatabase.CreateAsset(m3, "Assets/resourcex/" + gameObject.name + "_LQ2.asset");
            //Debug.Log("Created new rain meshes in Assets/Objects/RainFx/");
        }
#endif

    }

    public Mesh GetPreGennedMesh()
    {

        return preGennedMeshes[(preGennedIndex++) % preGennedMeshes.Length];

    }
    void Update () {
        
    }
    private Mesh CreateMesh() {
        Mesh mesh = new Mesh();

        Vector3 cameraRight = Camera.main.transform.right;
        Vector3 cameraUp  = (Vector3.up);
        
        int particleNum  = numberOfParticles / 2;

        Vector3[] verts  = new Vector3[4 * particleNum];
        Vector2[] uvs  = new Vector2[4 * particleNum];
        Vector2[]  uvs2  = new Vector2[4 * particleNum];
        Vector3[] normals = new Vector3[4 * particleNum];

        int[] tris  = new int[2 * 3 * particleNum];

        Vector3 position ;
        for (int i  = 0; i<particleNum; i++)
        {
            int i4  = i* 4;
            int i6  = i* 6;

            position.x = areaSize* (Random.value - 0.5f);
            position.y = areaHeight* Random.value;
    position.z = areaSize* (Random.value - 0.5f);

            float rand = Random.value;
            float widthWithRandom  = particleSize* 0.215f;// + rand * flakeRandom;
            float heightWithRandom  = particleSize + rand* flakeRandom;

    verts[i4 + 0] = position - cameraRight* widthWithRandom - cameraUp* heightWithRandom;
    verts[i4 + 1] = position + cameraRight* widthWithRandom - cameraUp* heightWithRandom;
    verts[i4 + 2] = position + cameraRight* widthWithRandom + cameraUp* heightWithRandom;
    verts[i4 + 3] = position - cameraRight* widthWithRandom + cameraUp* heightWithRandom;

    normals[i4 + 0] = -Camera.main.transform.forward;
            normals[i4 + 1] = -Camera.main.transform.forward;
            normals[i4 + 2] = -Camera.main.transform.forward;
            normals[i4 + 3] = -Camera.main.transform.forward;

            uvs[i4 + 0] = new Vector2(0.0f, 0.0f);
    uvs[i4 + 1] = new Vector2(1.0f, 0.0f);
    uvs[i4 + 2] = new Vector2(1.0f, 1.0f);
    uvs[i4 + 3] = new Vector2(0.0f, 1.0f);

    uvs2[i4 + 0] = new Vector2( Random.Range(-2f,2f)*4.0f, Random.Range(-1f,1f)*1.0f);
            uvs2[i4 + 1] = new Vector2(uvs2[i4 + 0].x, uvs2[i4 + 0].y);
    uvs2[i4 + 2] = new Vector2(uvs2[i4 + 0].x, uvs2[i4 + 0].y);
    uvs2[i4 + 3] = new Vector2(uvs2[i4 + 0].x, uvs2[i4 + 0].y);

    tris[i6 + 0] = i4 + 0;
            tris[i6 + 1] = i4 + 1;
            tris[i6 + 2] = i4 + 2;
            tris[i6 + 3] = i4 + 0;
            tris[i6 + 4] = i4 + 2;
            tris[i6 + 5] = i4 + 3;
        }

mesh.vertices = verts;
        mesh.triangles = tris;
        mesh.normals = normals;
        mesh.uv = uvs;
        mesh.uv2 = uvs2;
        mesh.RecalculateBounds ();
        
        return mesh;
    }    



}

4.下雨脚本2

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RainBox : MonoBehaviour {
    private MeshFilter mf;
    private Vector3 defaultPosition;
    private Bounds bounds;
    private RainManager manager;
    private Transform cachedTransform;
    private float cachedMinY;
    private float cachedAreaHeight;
    private float cachedFallingSpeed;


    void Start () {
        manager = transform.parent.GetComponent< RainManager > ();

        bounds = new Bounds(new Vector3(transform.position.x, manager.minYPosition, transform.position.z),
                           new  Vector3(manager.areaSize * 1.35f, Mathf.Max(manager.areaSize, manager.areaHeight) * 1.35f, manager.areaSize * 1.35f));

        mf = GetComponent< MeshFilter > ();
        mf.sharedMesh = manager.GetPreGennedMesh();

        cachedTransform = transform;
        cachedMinY = manager.minYPosition;
        cachedAreaHeight = manager.areaHeight;
        cachedFallingSpeed = manager.fallingSpeed;

        enabled = false;
    }

    private void OnBecameVisible()
    {
        enabled = true;
    }
    private void OnBecameInvisible()
    {
        enabled = false;
    }

    void Update () {

        cachedTransform.position -= Vector3.up * Time.deltaTime * cachedFallingSpeed;

        if (cachedTransform.position.y + cachedAreaHeight < cachedMinY)
        {
            cachedTransform.position = cachedTransform.position + Vector3.up * cachedAreaHeight * 2.0f;
        }
    }



    private void OnDrawGizmos()
    {
#if UNITY_EDITOR
        // do not display a weird mesh in edit mode
        if (!Application.isPlaying)
        {
            mf = GetComponent< MeshFilter > ();
            mf.sharedMesh = null;
        }
#endif

        if (transform.parent)
        {
            Gizmos.color =new  Color(0.2f, 0.3f, 3.0f, 0.35f);
            RainManager manager  = transform.parent.GetComponent<RainManager>() as RainManager;
            if (manager)
                Gizmos.DrawWireCube(transform.position + transform.up * manager.areaHeight * 0.5f,
                                        new Vector3(manager.areaSize, manager.areaHeight, manager.areaSize));
        }
    }




}

 

5.地面涟漪shader1

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;


public class RainsplashManager : MonoBehaviour {    
    public int numberOfParticles  = 700;
    public float areaSize = 40.0f;
    public float areaHeight = 15.0f;
    public float fallingSpeed = 23.0f;  
    public float flakeWidth   = 0.4f;
    public float flakeHeight = 0.4f;
    public float flakeRandom   = 0.1f;
    
    public Mesh[] preGennedMeshes  ;
    private int preGennedIndex  = 0;
    
    public bool generateNewAssetsOnStart  = false;    
    
    public void Start () {
    #if UNITY_EDITOR
        if (generateNewAssetsOnStart) {
            // create & save 3 meshes
            Mesh m1  = CreateMesh ();        
            Mesh m2  = CreateMesh ();        
            Mesh m3  = CreateMesh ();
            UnityEditor.AssetDatabase.CreateAsset(m1, "Assets/Objects/RainFx/" + gameObject.name + "_LQ0.asset");
            UnityEditor.AssetDatabase.CreateAsset(m2, "Assets/Objects/RainFx/" + gameObject.name + "_LQ1.asset");
            UnityEditor.AssetDatabase.CreateAsset(m3, "Assets/Objects/RainFx/" + gameObject.name + "_LQ2.asset");
            //DebugUtility.Log ("Created new rainsplash meshes in Assets/Objects/RainFx/");        
        }        
    #endif    
    }
    
    public Mesh GetPreGennedMesh ()  {
        return preGennedMeshes[(preGennedIndex++) % preGennedMeshes.Length];
    }
    
    Mesh CreateMesh () {
        Mesh mesh = new Mesh ();
        // we use world space aligned and not camera aligned planes this time
        Vector3 cameraRight = transform.right * UnityEngine.Random.Range(0.1f,2.0f) + transform.forward * UnityEngine.Random.Range(0.1f,2.0f);// Vector3.forward;//Camera.main.transform.right;
        cameraRight = Vector3.Normalize(cameraRight);
        Vector3 cameraUp = Vector3.Cross(cameraRight, Vector3.up);
        cameraUp = Vector3.Normalize(cameraUp);
        
        int particleNum = numberOfParticles / 2;

        Vector3[] verts = new Vector3[4 * particleNum];
        Vector2[] uvs  = new Vector2[4 * particleNum];
        Vector2[] uvs2 = new Vector2[4 * particleNum];
        Vector3[] normals = new Vector3[4 * particleNum];
        
        int[] tris  = new int[2 * 3 * particleNum];
 
        Vector3 position;
        for (int i  = 0; i < particleNum; i++) {
            int i4  = i * 4;
            int i6  = i * 6;

            position.x = areaSize * (UnityEngine.Random.value - 0.5f);
            position.y = 0.0f;
            position.z = areaSize * (UnityEngine.Random.value - 0.5f);
            
            float rand   = UnityEngine.Random.value;
            float widthWithRandom  = flakeWidth + rand * flakeRandom;
            float heightWithRandom  = widthWithRandom;
            
            verts[i4 + 0] = position - cameraRight * widthWithRandom;// - 0.0 * heightWithRandom;
            verts[i4 + 1] = position + cameraRight * widthWithRandom;// - 0.0 * heightWithRandom;
            verts[i4 + 2] = position + cameraRight * widthWithRandom + cameraUp * 2.0f * heightWithRandom;
            verts[i4 + 3] = position - cameraRight * widthWithRandom + cameraUp * 2.0f * heightWithRandom;
            
            normals[i4 + 0] = -Camera.main.transform.forward;
            normals[i4 + 1] = -Camera.main.transform.forward;
            normals[i4 + 2] = -Camera.main.transform.forward;
            normals[i4 + 3] = -Camera.main.transform.forward;

            uvs[i4 + 0] = new Vector2(0.0f, 0.0f);
            uvs[i4 + 1] = new Vector2(1.0f, 0.0f);
            uvs[i4 + 2] = new Vector2(1.0f, 1.0f);
            uvs[i4 + 3] = new Vector2(0.0f, 1.0f);

            Vector2 tc1  = new Vector2(UnityEngine.Random.Range(0.0f, 1.0f), UnityEngine.Random.Range(0.0f, 1.0f));
            uvs2[i4 + 0] = new Vector2(tc1.x,tc1.y);
            uvs2[i4 + 1] = new Vector2(tc1.x,tc1.y);;
            uvs2[i4 + 2] = new Vector2(tc1.x,tc1.y);;
            uvs2[i4 + 3] = new Vector2(tc1.x,tc1.y);;

            tris[i6 + 0] = i4 + 0;
            tris[i6 + 1] = i4 + 1;
            tris[i6 + 2] = i4 + 2;
            tris[i6 + 3] = i4 + 0;
            tris[i6 + 4] = i4 + 2;
            tris[i6 + 5] = i4 + 3;
        }

        mesh.vertices = verts;
        mesh.triangles = tris;
        mesh.normals = normals;
        mesh.uv = uvs;
        mesh.uv2 = uvs2;
        mesh.RecalculateBounds ();
        
        return mesh;
    }    
}

6.地面涟漪脚本2

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;


public class RainsplashBox : MonoBehaviour
{
    private MeshFilter _mf ;    
    private Bounds bounds; 
    
    private RainsplashManager manager ;
    
    public void Start () {
        transform.localRotation = Quaternion.identity;
        
        manager = transform.parent.GetComponent<RainsplashManager> (); 
        bounds = new Bounds (new Vector3 (transform.position.x,0.0f,transform.position.z),
                             new Vector3 (manager.areaSize,Mathf.Max(manager.areaSize,manager.areaHeight),manager.areaSize));    
                                     
        _mf = GetComponent<MeshFilter> ();        
        _mf.sharedMesh = manager.GetPreGennedMesh ();        
        
        enabled = false;
    }
    
    void OnBecameVisible () {
        enabled = true;
    }

    void OnBecameInvisible () {
        enabled = false;
    }
    
    void OnDrawGizmos () {
        if (transform.parent) {
            manager = transform.parent.GetComponent<RainsplashManager> (); 
            Gizmos.color =new Color(0.5f,0.5f,0.65f,0.5f);
            if(manager)
                Gizmos.DrawWireCube (    transform.position + transform.up * manager.areaHeight * 0.5f, 
                                        new Vector3 (manager.areaSize,manager.areaHeight, manager.areaSize) );
        }
    }
}

 

以上是关于shader之——rain的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 之 Compute Shader(通用计算并行加速)

Cg入门19:Fragment shader - 片段级模型动态变色

Cg入门20:Fragment shader - 片段级模型动态变色(实现汽车动态换漆)

Shader2.0的顶点着色器和片段着色器

Shader HLSL片段说明

Cg入门16:Fragment shader - 片段级光照