shader之——湖水(河流倒影)

先上图

1.水shader

Shader "Game_XXX/whater" {
    Properties {
        _WaterTex ("Normal Map (RGB), Foam (A)", 2D) = "white" {}
        _WaterTex2 ("Normal Map (RGB), Foam (B)", 2D) = "white" {}

        _Tiling ("Wave Scale", Range(0.00025, 0.1)) = 0.25
        _WaveSpeed("Wave Speed", Float) = 0.4

        _SpecularRatio ("Specular Ratio", Range(10,500)) = 200

        _BottomColor("Bottom Color",Color) = (0,0,0,0)
        _TopColor("Top Color",Color) = (0,0,0,0)
        _Alpha("Alpha",Range(0,1)) = 1

        _ReflectionTex("_ReflectionTex", 2D) = "black" {}
        _ReflectionLight("ReflectionLight",Range(0,1)) = 0.3

        _LightColorSelf ("LightColorSelf",Color) = (1,1,1,1)
        _LightDir ("LightDir",vector) = (0,1,0,0)

    }

    SubShader {
        Tags {
            "Queue"="Transparent-200"
            "RenderType"="Transparent"
            "IgnoreProjector" = "True"
            "LightMode" = "ForwardBase"
        }
        LOD 250
        Pass{
            Lighting On
            ZWrite On
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM

            #pragma vertex Vert
            #pragma fragment Frag
            #include "UnityCG.cginc"

             float _Tiling;
             float _WaveSpeed;
             float _SpecularRatio;
             sampler2D _WaterTex;
             sampler2D _WaterTex2;
             sampler2D _ReflectionTex;
             float4 _LightColorSelf;
             float4 _LightDir;
             float4 _BottomColor;
             float4 _TopColor;
             float _Alpha;
             float _ReflectionLight;

            struct v2f
            {
             float4 position  : POSITION;
             float3 worldPos  : TEXCOORD0;
             float3 tilingAndOffset:TEXCOORD2;
             float4 screen:TEXCOORD3;
             float4 VertColor :TEXCOORD4;

            };

            v2f Vert(appdata_full v)
            {
             v2f o;
             o.worldPos = mul(unity_ObjectToWorld, v.vertex);
             o.position = UnityObjectToClipPos(v.vertex);
             //uv动画
             o.tilingAndOffset.z =frac( _Time.x * _WaveSpeed);
             o.tilingAndOffset.xy = o.worldPos.xz*_Tiling;
             o.screen = ComputeScreenPos(o.position);
             o.VertColor = v.color;
             return o;
            }

            float4 Frag(v2f i):COLOR
            {
              float3 lightColor=_LightColorSelf.rgb*2;
              //世界视向量
              float3 worldView = -normalize(i.worldPos - _WorldSpaceCameraPos);
              float2 tiling = i.tilingAndOffset.xy;
              //法线采样
              float4 N1 = tex2D(_WaterTex, tiling.yx +float2(i.tilingAndOffset.z,0));
              float4 N2 = tex2D(_WaterTex2, tiling.yx -float2(i.tilingAndOffset.z,0));
              //两个法线相加,转世界空间,这里没有unpack,所以法线贴图不需要转normal  法线贴图为0-1 两张加起来为0-2 将其x2-2,转换为-2 --2然后将其normalize,变成-1到1
              //在遇到两张法线的情况下 ,一般将法线相加 再normalize
              float3 worldNormal  = normalize((N1.xyz+N2.xyz)*2-2);
              //以垂直的方向代替灯光 跟法线做点积 得到漫反射强度
              float LdotN = dot(worldNormal, float3(0,1,0));
              fixed2 uv = i.screen.xy/(i.screen.w+0.0001);
              uv.y = 1-uv.y;

              fixed4 refTex = tex2D (_ReflectionTex,uv + worldNormal.xy*0.02 );

              //这个变量一般在Forward渲染路径下使用,存储的是重要的pixel光源方向,没错,的确是使用w来判断这个光源的类型的,一般和_LightColor0配合使用
              //float3 LView=_WorldSpaceLightPos0.xyz;
              float3 LView = _LightDir.xyz;

                 //if(_WorldSpaceLightPos0.w == 0.0){
                    // L = normalize(_WorldSpaceLightPos0.xyz);
                    // }
                    // else{
                    // L = normalize(_WorldSpaceLightPos0.xyz - i.worldPos);
                    // } 

                //根据世界法线 ,世界视向量+光向量  得出高光 系数
                float dotSpecular = dot(worldNormal,  normalize( worldView+LView));
                //控制高光的范围
                float3 specularReflection = pow(saturate(dotSpecular), _SpecularRatio);

              float4 col;
              float fresnel = 0.5*LdotN+0.5;
              //根据法线的强度 来确定两种颜色之间的混合 ????
              col.rgb  = lerp(_BottomColor.xyz, _TopColor.xyz, fresnel);

              col.rgb = saturate (LdotN) *col.rgb;

              //加上高光
              col.rgb += specularReflection;
              col.rgb = lerp (col.rgb,refTex.rgb*_ReflectionLight,0.7);
              //col.rgb +=refTex.rgb*_ReflectionLight;
              //加上灯光颜色
              col.rgb*=lightColor;
              col.rgb *= i.VertColor.rgb;
              //控制透明度

              col.a =i.VertColor.a * _Alpha;
              return col;
            }

        ENDCG
        }  

    }

    FallBack "Diffuse"
}

2.c# 反射

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
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.曾经在官方的demo里看到反射相机的写法 比较复杂 在此也贴出来 用这个脚本的话 需要把水的shader里面屏幕UV的y方向变为正方向

using UnityEngine;
using System.Collections.Generic;
//[ExecuteInEditMode]
public class ReflectionFx : MonoBehaviour
{
    public Transform[] reflectiveObjects;
    public LayerMask reflectionMask;
    public Material[] reflectiveMaterials;
    private Transform reflectiveSurfaceHeight;
    public Shader replacementShader;
    private bool highQuality = false;
    public Color clearColor = Color.black;
    public System.String reflectionSampler = "_ReflectionTex";

    public float clipPlaneOffset = 0.07F;
    private Vector3 oldpos = Vector3.zero;
    //反射相机
    private Camera reflectionCamera;
    private Dictionary<Camera, bool> helperCameras = null;
    private Texture[] initialReflectionTextures;
    public void Start()
    {
        initialReflectionTextures = new Texture2D[reflectiveMaterials.Length];
        for (int i = 0; i < reflectiveMaterials.Length; i++)
        {
            initialReflectionTextures[i] = reflectiveMaterials[i].GetTexture(reflectionSampler);
        }

            this.enabled = true;
    }
    public void OnDisable()
    {
        if (initialReflectionTextures == null)
            return;
        // restore initial reflection textures
        for (int i = 0; i < reflectiveMaterials.Length; i++)
        {
            reflectiveMaterials[i].SetTexture(reflectionSampler, initialReflectionTextures[i]);
        }
    }
    //创建新相机
    private Camera CreateReflectionCameraFor(Camera cam)
    {
        //将string类初始化,挂脚本的物体名 + “Reflection” + 输入的cam名字
        System.String reflName = gameObject.name + "Reflection" + cam.name;
        //Debug.Log("AngryBots: created internal reflection camera " + reflName);
        //找到这个名字的物体,并将go 实例化
        GameObject go = GameObject.Find(reflName);

        if (!go) //如果这个物体不存在
            go = new GameObject(reflName, typeof(Camera)); //再重新创建一个新的物体,给他赋上名字和类型
        if (!go.GetComponent(typeof(Camera))) //这个物体没有Camera组件
            go.AddComponent(typeof(Camera));//给它加上Camera组件
        Camera reflectCamera = go.GetComponent<Camera>(); //reflectCamera实例化为这个物体(go)的相机组件
        reflectCamera.backgroundColor = clearColor; //相机的背景颜色 把背景色设置为clearColor 就不会遮盖住背后的视图

        reflectCamera.clearFlags = CameraClearFlags.Skybox;//清楚标记,SolidColor:屏幕上的任何空的部分将显示当前相机的背景颜色
        SetStandardCameraParameter(reflectCamera, reflectionMask);//设置渲染图层

        if (!reflectCamera.targetTexture) //如果反射相机没有targetTexture
            reflectCamera.targetTexture = CreateTextureFor(cam); //用这个方法创建targetTexture赋给相机的targetTexture
        return reflectCamera;
    }
    public void HighQuality()
    {
        highQuality = true;
    }

    //设置反射相机的渲染图层
    private void SetStandardCameraParameter(Camera cam, LayerMask mask)
    {
        cam.backgroundColor = Color.black; //背景色为黑色
        cam.enabled = true; //cam为false状态?
        cam.cullingMask = reflectionMask; //设置渲染图层
    }
    //给相机赋上targetTexture
    private RenderTexture CreateTextureFor(Camera cam)
    {
        RenderTextureFormat rtFormat = RenderTextureFormat.RGB565;
        if (!SystemInfo.SupportsRenderTextureFormat(rtFormat))
            rtFormat = RenderTextureFormat.Default;
        float rtSizeMul = highQuality ? 0.75f : 0.5f;
        RenderTexture rt = new RenderTexture(Mathf.FloorToInt(cam.pixelWidth * rtSizeMul), Mathf.FloorToInt(cam.pixelHeight * rtSizeMul), 24, rtFormat);
        rt.hideFlags = HideFlags.DontSave;

        return rt;
    }
    public void RenderHelpCameras(Camera currentCam)
    {
        if (null == helperCameras)
            helperCameras = new Dictionary<Camera, bool>();
        if (!helperCameras.ContainsKey(currentCam))
        {
            helperCameras.Add(currentCam, false);
        }
        if (helperCameras[currentCam])
        {
            return;
        }
        if (!reflectionCamera)
        {
            reflectionCamera = CreateReflectionCameraFor(currentCam);
            foreach (Material m in reflectiveMaterials)
            {
                m.SetTexture(reflectionSampler, reflectionCamera.targetTexture);
            }
        }
        RenderReflectionFor(currentCam, reflectionCamera);
        helperCameras[currentCam] = true;
    }
    public void LateUpdate()
    {
        // find the closest reflective surface and use that as our
        // reference for reflection height etc.
        //找到最接近的反射面并将其作为我们的
        //参考高度等。
        Transform closest = null;
        float closestDist = Mathf.Infinity;
        Vector3 pos = Camera.main.transform.position;
        foreach (Transform t in reflectiveObjects)
        {
            if (t.GetComponent<Renderer>().isVisible)
            {
                float dist = (pos - t.position).sqrMagnitude;
                if (dist < closestDist)
                {
                    closestDist = dist;
                    closest = t;
                }
            }
        }
        if (!closest)
            return;
        ObjectBeingRendered(closest, Camera.main);
        if (null != helperCameras)
            helperCameras.Clear();
    }
    private void ObjectBeingRendered(Transform tr, Camera currentCam)
    {
        if (null == tr)
            return;
        reflectiveSurfaceHeight = tr;
        RenderHelpCameras(currentCam);
    }
    private void RenderReflectionFor(Camera cam, Camera reflectCamera)
    {
        if (!reflectCamera)
            return;
        SaneCameraSettings(reflectCamera);
        reflectCamera.backgroundColor = clearColor;
        //GL.SetRevertBackfacing(true);
        GL.invertCulling = true;
        Transform reflectiveSurface = reflectiveSurfaceHeight;
        Vector3 eulerA = cam.transform.eulerAngles;
        reflectCamera.transform.eulerAngles = new Vector3(-eulerA.x, eulerA.y, eulerA.z);
        reflectCamera.transform.position = cam.transform.position;
        Vector3 pos = reflectiveSurface.transform.position;
        pos.y = reflectiveSurface.position.y;
        Vector3 normal = reflectiveSurface.transform.up;
        float d = -Vector3.Dot(normal, pos) - clipPlaneOffset;
        Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);
        Matrix4x4 reflection = Matrix4x4.zero;
        reflection = CalculateReflectionMatrix(reflection, reflectionPlane);
        oldpos = cam.transform.position;
        Vector3 newpos = reflection.MultiplyPoint(oldpos);
        reflectCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;
        Vector4 clipPlane = CameraSpacePlane(reflectCamera, pos, normal, 1.0f);
        Matrix4x4 projection = cam.projectionMatrix;
        projection = CalculateObliqueMatrix(projection, clipPlane);
        reflectCamera.projectionMatrix = projection;
        reflectCamera.transform.position = newpos;
        Vector3 euler = cam.transform.eulerAngles;
        reflectCamera.transform.eulerAngles = new Vector3(-euler.x, euler.y, euler.z);

        reflectCamera.RenderWithShader(replacementShader, "Reflection");
        //GL.SetRevertBackfacing(false);
        GL.invertCulling = false;
    }
    private void SaneCameraSettings(Camera helperCam)
    {
        helperCam.depthTextureMode = DepthTextureMode.None;
        helperCam.backgroundColor = Color.black;
        helperCam.clearFlags = CameraClearFlags.Skybox;
        helperCam.renderingPath = RenderingPath.Forward;
    }
    static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane)
    {
        Vector4 q = projection.inverse * new Vector4(
        sgn(clipPlane.x),
        sgn(clipPlane.y),
        1.0F,
        1.0F
        );
        Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
        // third row = clip plane - fourth row
        projection[2] = c.x - projection[3];
        projection[6] = c.y - projection[7];
        projection[10] = c.z - projection[11];
        projection[14] = c.w - projection[15];
        return projection;
    }

    // Helper function for getting the reflection matrix that will be multiplied with camera matrix
    //用摄像机矩阵来得到反射矩阵的辅助函数
    static Matrix4x4 CalculateReflectionMatrix(Matrix4x4 reflectionMat, Vector4 plane)
    {
        reflectionMat.m00 = (1.0F - 2.0F * plane[0] * plane[0]);
        reflectionMat.m01 = (-2.0F * plane[0] * plane[1]);
        reflectionMat.m02 = (-2.0F * plane[0] * plane[2]);
        reflectionMat.m03 = (-2.0F * plane[3] * plane[0]);
        reflectionMat.m10 = (-2.0F * plane[1] * plane[0]);
        reflectionMat.m11 = (1.0F - 2.0F * plane[1] * plane[1]);
        reflectionMat.m12 = (-2.0F * plane[1] * plane[2]);
        reflectionMat.m13 = (-2.0F * plane[3] * plane[1]);
        reflectionMat.m20 = (-2.0F * plane[2] * plane[0]);
        reflectionMat.m21 = (-2.0F * plane[2] * plane[1]);
        reflectionMat.m22 = (1.0F - 2.0F * plane[2] * plane[2]);
        reflectionMat.m23 = (-2.0F * plane[3] * plane[2]);
        reflectionMat.m30 = 0.0F;
        reflectionMat.m31 = 0.0F;
        reflectionMat.m32 = 0.0F;
        reflectionMat.m33 = 1.0F;

        return reflectionMat;
    }
    // Extended sign: returns -1, 0 or 1 based on sign of a
    //扩展符号:返回-1、0或1,基于a的符号
    static float sgn(float a)
    {
        if (a > 0.0F) return 1.0F;
        if (a < 0.0F) return -1.0F;
        return 0.0F;
    }
    // Given position/normal of the plane, calculates plane in camera space.
    //给定平面的正/正态,在相机空间计算平面
    private Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)
    {
        Vector3 offsetPos = pos + normal * clipPlaneOffset;
        Matrix4x4 m = cam.worldToCameraMatrix;
        Vector3 cpos = m.MultiplyPoint(offsetPos);
        Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
        return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
    }
}
时间: 2024-10-24 20:14:31

shader之——湖水(河流倒影)的相关文章

shader之——rain

1.地面shader Shader "baicai/me02" { Properties { _MainTex ("MainTex", 2D) = "white" {} _Bump ("Bump", 2D) = "bump" {} _Bump02("Bump02",2D) = "Bump"{} _DirectionUv("Wet scroll directi

河流Shader

原地址:http://www.unity蛮牛.com/blog-2321-336.html Shader "Custom/TextureEffect" { Properties { _MainTint("Diffuse Tint",Color) = (1,1,1,1) _MainTex ("Base (RGB)", 2D) = "white" {} _ScrollXSpeed("X Scroll Speed"

Unity3D for VR 学习(8): Unity Shader概述

从西安到北京高铁上,一位VR老外团队的华人leader对VR技术做了画龙点睛: “3D游戏的核心部分在Render, 国内很多团队美术.程序中间缺失严重.所以3d游戏做不好. VR这块更是至关重要.” 故,欲VR,先Shader吧. 1 CG规范: 计算机图形学(英语:computer graphics) 在Windows下图像渲染是DirectX: 在Linux下图形渲染是OpenGL:在苹果下新出的Metal渲染.而作为Unity3D程序,跨平台的特性则无须对这些平台一一掌握,仅需要从CG规

水流雨渍shader

战神斯巴达之魂的雨渍做的很逼真,尝试了下,似乎是差不多了,整体欠缺不少 普通平面: 环形流动: 河流: shader实现,3层加上一个偏移层 圆形的雨渍流动和河流要重新展一下UV

通过渲染器Shader实现图像变换效果

在上一篇文章中,一起学习了通过设定画笔风格来实现图形变换,没读过的朋友可以点击下面链接: http://www.cnblogs.com/fuly550871915/p/4886455.html 是不是觉得自己学到的知识更多了呢?那么再多学一点总没坏处.在本篇文章中,将会一起学习通过给画笔设定Shader属性,实现图形变换.并带领读者一起实现两个实际例子,图片渲染器和线性渲染器.有没有发现我们的画笔特别强大呢??确实,我们曾经给它设置过颜色矩阵属性,设置过xfermode风格属性,现在又来设定Sh

【译】Unity3D Shader 新手教程(1/6)

刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D Shader编程望而却步.该系列教程的第一篇文章(译者注:即本文,后续还有5篇文章)详细介绍了Unity3D中的表面着色器(Surface Shader)的,为学习更复杂的Shader编程打下基础. 动机 如果你是刚刚接触Shader编程的新手,你可能不知道从何开始踏出Shader编程的第一步.本教程将带你一步步完成一个表面着色器(Surface Shader)和片段着色器(Fra

Untiy Shader - 纹理贴图滚动

滚动纹理,可以实现一些如瀑布,河流,熔岩流等效果,本质上就是UV坐标的偏移,在Unity中新建一个Shader,然后修改成下面代码的样子,新建一个材质,选择此shader,赋予一张贴图,然后将材质应用于一个mesh上,运行即可看到效果 Shader "Custom/UVOffset" { Properties { _MainTint("Diffuse Tine",Color) = (1,1,1,1) _MainTex("Base (RGB)",2

【我的书】Unity Shader的书 — 目录(2015.09.04更新)

写在前面 感谢所有点进来看的朋友.没错,我目前打算写一本关于Unity Shader的书. 出书的目的有下面几个: 总结我接触Unity Shader以来的历程,给其他人一个借鉴.我非常明白学Shader的艰难,在群里也见了很多人提出的问题.我觉得学习Shader还是一件有规律可循的事情,但问题是中文资料难觅,而大家又不愿意去看英文...这对我有什么好处呢?强迫我对知识进行梳理,对细节问题把握更清楚. 第二个原因你懂的. 关于本书的定位问题: 面向Unity Shader初学者,但要: 有一定的

【我的书】Unity Shader的书 — 目录(2016.1.29更新)

写在前面 感谢所有点进来看的朋友.没错,我目前打算写一本关于Unity Shader的书. 出书的目的有下面几个: 总结我接触Unity Shader以来的历程,给其他人一个借鉴.我非常明白学Shader的艰难,在群里也见了很多人提出的问题.我觉得学习Shader还是一件有规律可循的事情,但问题是中文资料难觅,而大家又不愿意去看英文...这对我有什么好处呢?强迫我对知识进行梳理,对细节问题把握更清楚. 第二个原因你懂的. 关于本书的定位问题: 面向Unity Shader初学者,但要: 有一定的