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

时间:2022-02-15 04:10:04

先上图

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