shader效果之 水天相接

(1)效果图:(录屏效果惨不忍睹)

在这里插入图片描述在这里插入图片描述

请添加图片描述

请添加图片描述

(2)思路图:
步骤1
步骤2
代码逻辑如下:
注释在代码中

Shader "Water_Code"
{
    
    
	Properties
	{
    
    
		_WaterNormal ("_WaterNormal", 2D) = "white" {
    
    }
		_ReflectionTex("ReflectionTex",2D) = "white"{
    
    }
		_NormalTilling("_NormalTilling",float) = 8
		_NoiseIntensity("_NoiseIntensity",float) = 1
		_WaterSpeed("_WaterSpeed",float) = 6
		_WaterNoise("_WaterNoise",float) = 1

		_SpecTint("_SpecTint",color) = (1,1,1,1)
		_SpecSmoothness("_SpecSmoothness",range(0,1)) = 0.01		
		_SpecIntensity("_SpecIntensity",float) = 1		

		_SpecStart("_SpecStart",float) = 200
		_SpecEnd("_SpecEnd",float) = 0
		_UnderWaterTex("_UnderWaterTex",2D) = "white"{
    
    }
		_UnderWaterTilling("_UnderWaterTilling",float) = 4
		_WaterDepth("_WaterDepth",float) = 1
	}
	SubShader
	{
    
    
		Tags {
    
     "RenderType"="Opaque" }
		LOD 100

		Pass
		{
    
    
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"
			// #include "UnityShaderVariables.cginc"
			// #include "UnityStandardUtils.cginc"

			struct appdata
			{
    
    
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
			};

			struct v2f
			{
    
    
				float2 uv : TEXCOORD0;
				float4 pos : SV_POSITION;
				float3 worldPos : TEXCOORD1;
				float3 worldTangent : TEXCOORD2;
				float3 worldBinormal : TEXCOORD3;
				float3 worldNormal : TEXCOORD4;
				float4 screenPos : TEXCOORD5;
			};

			sampler2D _WaterNormal,_ReflectionTex,_UnderWaterTex;
			
			float _WaterSpeed,_NormalTilling,_NoiseIntensity, _WaterNoise;
			float _SpecSmoothness,_SpecIntensity;
			float4 _SpecTint;
			float _SpecEnd,_SpecStart;
			float _UnderWaterTilling,_WaterDepth;
			v2f vert (appdata v)
			{
    
    
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.worldPos = mul(unity_ObjectToWorld,v.vertex);
				o.worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
				o.worldTangent = normalize(UnityObjectToWorldNormal(v.tangent));
				o.worldBinormal =normalize(cross(o.worldTangent,o.worldNormal) * v.tangent.w);
				o.screenPos = ComputeScreenPos(o.pos);
				return o;
			}

			fixed4 frag (v2f i) : SV_Target
			{
    
    

				/// 计算出法线相关的数据, 最后采样同一张normalMap 两次 ,混合 得到新的法线
				float3 worldPos = i.worldPos;
				float2 uv = worldPos.xz / _NormalTilling + (_Time.y * 0.1f * _WaterSpeed);
				float2 uv1 = worldPos.xz / _NormalTilling * 1.5f + (_Time.y * 0.1f * _WaterSpeed * -1.0);
				//float3 worldNormal = UnpackScaleNormal( tex2D(_WaterNormal,uv),_NoiseIntensity);						
				float3 worldNormal = UnpackNormal( tex2D(_WaterNormal,uv));						
				worldNormal.xy  *= _NoiseIntensity;
				worldNormal.z = sqrt(1.0 - dot(worldNormal.xy,worldNormal.xy));
				float3 worldNormal1 = UnpackNormal( tex2D(_WaterNormal,uv1));						
				worldNormal1 *= _NoiseIntensity;
				worldNormal1.z = sqrt(1.0 - dot(worldNormal1.xy,worldNormal1.xy));
				worldNormal += worldNormal1;
				worldNormal *= 0.5;
				worldNormal.z = sqrt(1.0 - dot(worldNormal.xy,worldNormal.xy));				
				worldNormal = normalize(mul(float3x3(i.worldTangent,i.worldBinormal,i.worldNormal),worldNormal));


				  用法线扰动 计算反射的效果   后面除以裁剪空间坐标的w: 点到相机的距离;  距离越远 法线的效果越弱, 远处的波动越小
				float2 UVOffset_reflectTex = worldNormal.xz / (i.pos.w + 1) * _WaterNoise;
				float4 screenPos = i.screenPos;
				float4 tempPos = screenPos / screenPos.w;
				float4 reflectColor = tex2D( _ReflectionTex, tempPos.xy + UVOffset_reflectTex);

			
				 计算高光颜色
				float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
				float3 worldLightDir = normalize(UnityWorldSpaceLightDir(worldPos));
				float3 halfDir = normalize(worldLightDir + worldViewDir);
				float ndoth = dot(halfDir,worldNormal);
				float specTerm = pow(saturate(ndoth),_SpecSmoothness * 256.0);
				float4 specColor = specTerm * _SpecTint * _SpecIntensity;
				// 高光的颜色  随着离摄像机的远近 做强度控制 近处强  , 远处弱
				float3 worldCameraPos = _WorldSpaceCameraPos;
				float dis = distance(worldPos,worldCameraPos);
				float specReflectIntensityMask = (_SpecEnd - dis) / (_SpecEnd - _SpecStart); 
				float specMask = saturate(specReflectIntensityMask);
				specColor = specColor * specMask;


				float3 tangentViewDir = mul(worldViewDir,float3x3(i.worldTangent,i.worldBinormal,i.worldNormal));
				/ 水下的处理
				float2 paralaxOffset = ParallaxOffset( 0 , _WaterDepth , tangentViewDir );
				float2 uv_UnderWater = worldPos.xz / _UnderWaterTilling + (worldNormal.xy * 0.1)  + paralaxOffset;
				float4 underWaterColor = tex2D(_UnderWaterTex,uv_UnderWater);
				

				/ 用菲涅尔 控制反射和折射的比率
				float fresnal = 1 - saturate(dot(worldNormal,worldViewDir));
				float4 refCol = lerp(underWaterColor,reflectColor,fresnal); 
				float4 endCol = refCol + specColor;
				return endCol;
				
				
				
			}
			ENDCG
		}
	}
}

PlanarReflection的逻辑,后面加入了模糊处理, 用commandBuffer实现的, 没有用后处理

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


[ExecuteInEditMode]
public class PlanarReflection_16 : MonoBehaviour {
    
    
    public LayerMask _reflectionMask = -1;
    public bool _reflectSkybox = false;
    public float _clipPlaneOffset = 0.07F;
    //反射图属性名
    const string _reflectionTex = "_ReflectionTex";
    Camera _reflectionCamera;
    Vector3 _oldpos;
    RenderTexture _bluredReflectionTexture;
    Material _sharedMaterial;
    //模糊效果相关参数
    public bool _blurOn = true;
    [Range(0.0f, 5.0f)]
    public float _blurSize = 1;
    [Range(0, 10)]
    public int _blurIterations = 2;
    [Range(1.0f, 4.0f)]
    public float _downsample = 1;
    //记录上述模糊参数,用于判断参数是否发生变化   
    private bool _oldBlurOn;
    private float _oldBlurSize;
    private int _oldBlurIterations;
    private float _oldDownsample;
    //模糊shader
    private Shader _blurShader;
    private Material _blurMaterial;
    //用来判断当前是否正在渲染反射图
    private static bool _insideRendering;

    Material BlurMaterial {
    
    
        get {
    
    
            if (_blurMaterial == null) {
    
    
                _blurMaterial = new Material(_blurShader);
                return _blurMaterial;
            }
            return _blurMaterial;
        }
    }

    void Awake() {
    
    
        _oldBlurOn = _blurOn;
        _oldBlurSize = _blurSize;
        _oldBlurIterations = _blurIterations;
        _oldDownsample = _downsample;
    }

    void Start() {
    
    
        _sharedMaterial = GetComponent<MeshRenderer>().sharedMaterial;
        _blurShader = Shader.Find("Hidden/KawaseBlur");
        if (_blurShader == null)
            Debug.LogError("缺少Hidden/KawaseBlur Shader");
    }

    bool _blurParamChanged;
    void Update()
    {
    
    
        if (_blurParamChanged)
        {
    
    
            _oldBlurOn = _blurOn;
            _oldBlurSize = _blurSize;
            _oldBlurIterations = _blurIterations;
            _oldDownsample = _downsample;
        }

        if (_blurOn != _oldBlurOn || _blurSize != _oldBlurSize || _blurIterations != _oldBlurIterations || _downsample!= _oldDownsample)
        {
    
    
            _blurParamChanged = true;
        }
    }

    //创建反射用的摄像机
    Camera CreateReflectionCamera(Camera cam) {
    
    
        //生成Camera
        String reflName = gameObject.name + "Reflection" + cam.name; 
        GameObject go = new GameObject(reflName);
        go.hideFlags = HideFlags.DontSave;
        //go.hideFlags = HideFlags.HideAndDontSave;
        Camera reflectCamera = go.AddComponent<Camera>();
        //设置反射相机的参数
        HoldCameraSettings(reflectCamera);
        //创建RT并绑定Camera
        if (!reflectCamera.targetTexture) {
    
    
            reflectCamera.targetTexture = CreateTexture(cam);
        }

        return reflectCamera;
    }
    //设置反射相机的参数
    void HoldCameraSettings(Camera heplerCam)
    {
    
    
        heplerCam.backgroundColor = Color.black;
        heplerCam.clearFlags = _reflectSkybox ? CameraClearFlags.Skybox : CameraClearFlags.SolidColor;
        heplerCam.renderingPath = RenderingPath.Forward;
        heplerCam.cullingMask = _reflectionMask;
        heplerCam.allowMSAA = false;
        heplerCam.enabled = false;
    }
    //创建RT 
    RenderTexture CreateTexture(Camera sourceCam) {
    
    
        int width = Mathf.RoundToInt(Screen.width / _downsample);
        int height = Mathf.RoundToInt(Screen.height / _downsample);
        RenderTextureFormat formatRT = sourceCam.allowHDR ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.Default;
        RenderTexture rt = new RenderTexture(width, height, 24, formatRT);
        rt.hideFlags = HideFlags.DontSave;
        return rt;
    }
    //内置回调函数,物体渲染之前会先调用该函数
    void OnWillRenderObject() {
    
    
        Camera currentCam = Camera.current;
        if (currentCam == null) {
    
    
            return;
        }

#if !UNITY_EDITOR
        if (!currentCam.gameObject.CompareTag("MainCamera"))
            return;
#endif

        if (_insideRendering) {
    
    
            return;
        }
        _insideRendering = true;

        if (_reflectionCamera == null) {
    
    
            _reflectionCamera = CreateReflectionCamera(currentCam);
        }

        //渲染反射图
        RenderReflection(currentCam, _reflectionCamera);

        //是否对反射图进行模糊
        if (_reflectionCamera && _sharedMaterial) {
    
    
            if (_blurOn) {
    
    
                if (_bluredReflectionTexture == null)
                    _bluredReflectionTexture = CreateTexture(currentCam);
                PostProcessTexture(currentCam, _reflectionCamera.targetTexture, _bluredReflectionTexture);
                _sharedMaterial.SetTexture(_reflectionTex, _bluredReflectionTexture);
            }
            else {
    
    
                _sharedMaterial.SetTexture(_reflectionTex, _reflectionCamera.targetTexture);
            }
        }

        _insideRendering = false;
    }

    //调用反射相机,渲染反射图
    void RenderReflection(Camera currentCam, Camera reflectCamera) {
    
    
        if (reflectCamera == null) {
    
    
            Debug.LogError("反射Camera无效");
            return;
        }
        if (_sharedMaterial && !_sharedMaterial.HasProperty(_reflectionTex))
        {
    
    
            Debug.LogError("Shader中缺少_ReflectionTex属性");
            return;
        }
        //保持反射相机的参数
        HoldCameraSettings(reflectCamera);

        if (_reflectSkybox) {
    
    
            if (currentCam.gameObject.GetComponent(typeof(Skybox))) {
    
    
                Skybox sb = (Skybox)reflectCamera.gameObject.GetComponent(typeof(Skybox));
                if (!sb) {
    
    
                    sb = (Skybox)reflectCamera.gameObject.AddComponent(typeof(Skybox));
                }
                sb.material = ((Skybox)currentCam.GetComponent(typeof(Skybox))).material;
            }
        }

        bool isInvertCulling = GL.invertCulling;
        GL.invertCulling = true;

        Transform reflectiveSurface = this.transform; //waterHeight;

        Vector3 eulerA = currentCam.transform.eulerAngles;

        reflectCamera.transform.eulerAngles = new Vector3(-eulerA.x, eulerA.y, eulerA.z);
        reflectCamera.transform.position = currentCam.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 = currentCam.transform.position;
        Vector3 newpos = reflection.MultiplyPoint(_oldpos);

        reflectCamera.worldToCameraMatrix = currentCam.worldToCameraMatrix * reflection;

        Vector4 clipPlane = CameraSpacePlane(reflectCamera, pos, normal, 1.0f);

        Matrix4x4 projection = currentCam.projectionMatrix;
        projection = CalculateObliqueMatrix(projection, clipPlane);
        reflectCamera.projectionMatrix = projection;

        reflectCamera.transform.position = newpos;
        Vector3 euler = currentCam.transform.eulerAngles;
        reflectCamera.transform.eulerAngles = new Vector3(-euler.x, euler.y, euler.z);

        reflectCamera.Render();

        GL.invertCulling = isInvertCulling;
    }

    static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane) {
    
    
        Vector4 q = projection.inverse * new Vector4(
            Mathf.Sign(clipPlane.x),
            Mathf.Sign(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;
    }

    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;
    }

    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));
    }

    //对反射图进行图像处理(利用command buffer实现)
    private Dictionary<Camera, CommandBuffer> _cameras = new Dictionary<Camera, CommandBuffer>();
    void PostProcessTexture(Camera cam, RenderTexture source, RenderTexture dest)
    {
    
    
        //参数有变化需要刷新commandbuffer
        if (_blurParamChanged)
        {
    
    
            if (_cameras.ContainsKey(cam))
                cam.RemoveCommandBuffer(CameraEvent.BeforeForwardOpaque, _cameras[cam]);
            _cameras.Remove(cam);
        }
        //已经设置了commandbuffer就不用再执行了
        if (_cameras.ContainsKey(cam))
            return;

        CommandBuffer buf = new CommandBuffer();
        buf.name = "Blur Reflection Texture";
        _cameras[cam] = buf;
        float width = source.width;
        float height = source.height;
        int rtW = Mathf.RoundToInt(width / _downsample);
        int rtH = Mathf.RoundToInt(height / _downsample);

        int blurredID = Shader.PropertyToID("_Temp1");
        int blurredID2 = Shader.PropertyToID("_Temp2");
        buf.GetTemporaryRT(blurredID, rtW, rtH, 0, FilterMode.Bilinear, source.format);
        buf.GetTemporaryRT(blurredID2, rtW, rtH, 0, FilterMode.Bilinear, source.format);

        buf.Blit((Texture)source, blurredID);
        for (int i = 0; i < _blurIterations; i++)
        {
    
    
            float iterationOffs = (i * 1.0f);
            buf.SetGlobalFloat("_Offset", iterationOffs / _downsample + _blurSize);
            buf.Blit(blurredID, blurredID2, BlurMaterial, 0);
            buf.Blit(blurredID2, blurredID, BlurMaterial, 0);
        }
        buf.Blit(blurredID, dest);

        buf.ReleaseTemporaryRT(blurredID);
        buf.ReleaseTemporaryRT(blurredID2);

        cam.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, buf);
    }

}

猜你喜欢

转载自blog.csdn.net/js0907/article/details/119428142
今日推荐