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();
GameObject refCramera = new GameObject("refCramera");
m_camera = refCramera.AddComponent();
m_texture = new RenderTexture(Screen.width,Screen.height,24);
refCameraSet();
}
///
/// 相机位置及方向
///
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;
}
///
/// 反射相机的设置
///
void refCameraSet()
{
m_camera.backgroundColor = Color.black;
m_camera.clearFlags = CameraClearFlags.Skybox;
m_camera.cullingMask = reflectionMask; //图层
m_camera.targetTexture = m_texture;
this.GetComponent().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
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() 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 ();
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 ();
_mf.sharedMesh = manager.GetPreGennedMesh ();
enabled = false;
}
void OnBecameVisible () {
enabled = true;
}
void OnBecameInvisible () {
enabled = false;
}
void OnDrawGizmos () {
if (transform.parent) {
manager = transform.parent.GetComponent ();
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) );
}
}
}
亲,如果您觉得本文不错,愿意给我一些动力的话,请用手机扫描二维码即可向我打赏