天空盒及水面渲染

9 篇文章 0 订阅

天空球

防止被相机裁剪

#if UNITY_REVERSED_Z
    o.vertex.z = o.vertex.w * 0.000001f;
#else
    o.vertex.z = o.vertex.w * 0.999999f;
#endif

渲染队列改成1000左右。

水面

水面反射

在平面的反射面建立一个摄像头,将渲染的Texture直接采样到平面上达到映射的效果,通过clipPlaneOffset 修正物体在通过改变反射矩阵修改具体位置。
在这里插入图片描述

开抄
PlanarReflection.cs

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


[ExecuteInEditMode]
public class PlanarReflection : 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.HideAndDontSave;
        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);
    }

}

水面扰动

在这里插入图片描述
在这里插入图片描述
下面的Vertex pos 是为了降低远处波动。
效果
在这里插入图片描述

代码实现
粗糙用代码还原了一下

Shader "WaterCode"
{
    Properties
    {
        _ReflectionTex("ReflectionTex", 2D) = "white" {}
		_WaterNormal("WaterNormal", 2D) = "white" {}
		_WaterSpeed1("WaterSpeed1", Float) = 0.1
		_NormalTilling("NormalTilling", Float) = 8
		_WaterNoise("WaterNoise", Float) = 1
		_Vector0("Vector 0", Vector) = (0,0,0,0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

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

            sampler2D _ReflectionTex;
            float4 _ReflectionTex_ST;
            sampler2D _WaterNormal;
            float _NormalTilling;
            float _WaterSpeed1;
            float4 _Vector0;
            float _WaterNoise;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.worldTangent    =  normalize( mul(unity_ObjectToWorld, v.tangent).xyz);
                o.worldNormal     =  normalize( mul(unity_ObjectToWorld, float4(v.normal,0.0)).xyz);
                o.worldBitangent  = normalize(cross(o.worldNormal,o.worldTangent)*v.tangent.w);
                o.screenPos = ComputeScreenPos(o.pos);
                o.texcoord0 = v.uv;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                half4 screenPos = i.screenPos;
                float3 worldTangent = normalize(i.worldTangent);
				float3 worldNormal = normalize(i.worldNormal);
				float3 worldBitangent = normalize(i.worldBitangent);
                float3 tanToWorld0 = float3( worldTangent.x, worldBitangent.x, worldNormal.x );
				float3 tanToWorld1 = float3( worldTangent.y, worldBitangent.y, worldNormal.y );
				float3 tanToWorld2 = float3( worldTangent.z, worldBitangent.z, worldNormal.z );
                half2 uv1_WaterNormal = i.worldPos.xz/_NormalTilling + _Time*_WaterSpeed1;
                half2 uv2_WaterNormal = i.worldPos.xz/_NormalTilling - _Time*_WaterSpeed1;
                half3 waterNormal = (tex2D(_WaterNormal,uv1_WaterNormal)+tex2D(_WaterNormal,uv2_WaterNormal)).xyz*0.5f;
                waterNormal.z =sqrt( 1.0f- dot( waterNormal.xy,waterNormal.xy));
                //水面波动法线
                waterNormal = float3(dot(tanToWorld0,waterNormal), dot(tanToWorld1,waterNormal), dot(tanToWorld2,waterNormal));

                //screenPos
                screenPos = screenPos / screenPos.w;
				screenPos.z = ( UNITY_NEAR_CLIP_VALUE >= 0 ) ? screenPos.z : screenPos.z * 0.5 + 0.5;

                half2 uv_result_reflection =  screenPos.xy+  (waterNormal.xy/ (i.pos.w+1))*_WaterNoise;

                // sample the texture
                fixed4 col = tex2D(_ReflectionTex,uv_result_reflection);
                // apply fog
                return col;
            }
            ENDCG
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值