shader之——rain
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shader之——rain相关的知识,希望对你有一定的参考价值。
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<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.下雨脚本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<particleNum; i++) { int i4 = i* 4; int i6 = i* 6; position.x = areaSize* (Random.value - 0.5f); position.y = areaHeight* Random.value; position.z = areaSize* (Random.value - 0.5f); float rand = Random.value; float widthWithRandom = particleSize* 0.215f;// + rand * flakeRandom; float heightWithRandom = particleSize + rand* flakeRandom; verts[i4 + 0] = position - cameraRight* widthWithRandom - cameraUp* heightWithRandom; verts[i4 + 1] = position + cameraRight* widthWithRandom - cameraUp* heightWithRandom; verts[i4 + 2] = position + cameraRight* widthWithRandom + cameraUp* heightWithRandom; verts[i4 + 3] = position - cameraRight* widthWithRandom + cameraUp* 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); uvs2[i4 + 0] = new Vector2( Random.Range(-2f,2f)*4.0f, Random.Range(-1f,1f)*1.0f); uvs2[i4 + 1] = new Vector2(uvs2[i4 + 0].x, uvs2[i4 + 0].y); uvs2[i4 + 2] = new Vector2(uvs2[i4 + 0].x, uvs2[i4 + 0].y); uvs2[i4 + 3] = new Vector2(uvs2[i4 + 0].x, uvs2[i4 + 0].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; } }
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<RainManager>() 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<RainsplashManager> (); 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<MeshFilter> (); _mf.sharedMesh = manager.GetPreGennedMesh (); enabled = false; } void OnBecameVisible () { enabled = true; } void OnBecameInvisible () { enabled = false; } void OnDrawGizmos () { if (transform.parent) { manager = transform.parent.GetComponent<RainsplashManager> (); 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) ); } } }
以上是关于shader之——rain的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL 之 Compute Shader(通用计算并行加速)
Cg入门19:Fragment shader - 片段级模型动态变色