自动生成的水面

水面最开始是美术制作的,一个大的面片来实现,对于湖泊多的场景,这个面片甚至场景那么大,我觉得这种做法不是很好,虽然只有4个顶点,2个三角面,但是由于很大,像素填充率惊人,效率自然也不够好.后来要处理一些水面岸边渐变的效果,我觉得程序实现一个自动化的,不再让美术去操心这个事情.

    我想尽可能地让这个水面完美,所以尝试做了以下一些技术

1.自动生成水面网格

       美术把这个水面摆到某个地方,然后水面根据摆的位置的高度,就自动生成一个适配地形的水面网格.这个技术我以前提到过,就是种子填充算法,从水面一个点逐渐往8个方向的点扩散,直到遇到比他高的地形.

[csharp]  view plain  copy
  1. // 八方向的边界填充算法  
  2. void WaterBoundaryFill8(int x, int z, float boundaryHeight)  
  3. {  
  4.     int index = x + z * (m_GridNumX + 1);  
  5.     if (m_VerticesFlag[index])  
  6.         return;  
  7.   
  8.     float height = GetHeight(x, z);  
  9.     if (height <= boundaryHeight)  
  10.     {  
  11.         m_VerticesFlag[index] = true;  
  12.         float difference = Mathf.Clamp(boundaryHeight - height, 0, maxWaterDepth);  
  13.         m_VerticesAlpha[index] = Mathf.Clamp01(difference / maxWaterDepth);  
  14.   
  15.         if (x + 1 < m_GridNumX + 1 && x - 1 >= 0 && z + 1 < m_GridNumZ + 1 && z - 1 >= 0)  
  16.         {  
  17.             WaterBoundaryFill8(x + 1, z, boundaryHeight);  
  18.             WaterBoundaryFill8(x - 1, z, boundaryHeight);  
  19.             WaterBoundaryFill8(x, z + 1, boundaryHeight);  
  20.             WaterBoundaryFill8(x, z - 1, boundaryHeight);  
  21.   
  22.             WaterBoundaryFill8(x - 1, z - 1, boundaryHeight);  
  23.             WaterBoundaryFill8(x + 1, z - 1, boundaryHeight);  
  24.             WaterBoundaryFill8(x - 1, z + 1, boundaryHeight);  
  25.             WaterBoundaryFill8(x + 1, z + 1, boundaryHeight);  
  26.         }  
  27.     }  
  28. }  
  29.   
  30. float GetHeight(int x, int z)  
  31. {  
  32.     float height = float.MinValue;  
  33.     Vector3 centerOffset = new Vector3(-m_GridNumX * 0.5f, 0, -m_GridNumZ * 0.5f);  
  34.     Vector3 worldPos = GetVertexLocalPos(x, z, centerOffset) + transform.position;  
  35.     worldPos.y += 100.0f;  
  36.     RaycastHit hit;  
  37.     if (Physics.Raycast(worldPos, -Vector3.up, out hit, 200.0f))  
  38.     {  
  39.         height = hit.point.y;  
  40.     }  
  41.     else  
  42.     {  
  43.         //LogSystem.DebugLog("Physics.Raycast失败,请检查是否有Collider. x:{0} z:{0}", x, z);  
  44.     }  
  45.       
  46.     return height;  
  47. }  


2.水面和岸边的alpha过渡

       如果不处理水面和岸边的alpha过渡.那么相交的地方会有一条很明显的线.

       水面的过渡处理,如果有场景的深度图,那么处理起来就特别方便,因为你就知道了场景中每个像素点的深度,和水平面一比较就知道了这个alpha过渡值.深度数据的获取,如果是延迟渲染,就从G-Buffer,前向渲染,就得自己渲染深度图(pre-z).但是对于手游,自己额外渲染深度图会有一定开销.如果抛弃这种处理方式,那么我们该怎么办呢?

        一般有两种办法,一种是用额外一张alpha贴图来逐像素地保存这个alpha值,缺点是,如果水面大,这个alpha图就得很大,而且得美术来制作,修改起来也很麻烦.另外一种就是用水面网格顶点颜色来保存这个alpha值,这个alpha值,程序自动计算,不需要美术去处理.缺点是过渡效果是逐顶点的,和网格的密度有关系.毫无疑问,我选择第二种.


3.岸边自动生成动态海浪

       我们首先需要一个Foam的纹理来模拟浪花.其次需要一个梯度图来实现一层一层的浪花的运动.再次我们需要知道浪花的运动方向,这个可以通过水的深浅决定,因为浪花总是从水深的地方移动到水浅的地方.


4.水面的倒影和折射

       水面的实时倒影和折射,也支持,后来还是没用到,因为开销大了点,我用环境贴图反射来代替水面实时倒影,效率高很多,效果也还可以,适合手游.

[cpp]  view plain  copy
  1.             // reflection  
  2. #if _RUNTIME_REFLECTIVE  
  3.             float4 uv1 = i.uvProjector; uv1.xy += noise.xy * 0.25;  
  4.             fixed4 refl = tex2Dproj(_ReflectionTex, UNITY_PROJ_COORD(uv1)) * _ReflectionColor;  
  5. #else         
  6.             half3 worldReflectionVector = normalize(reflect(-viewDir, normalNoise));  
  7.             fixed4 refl = texCUBE(_ReflectionCubeMap, worldReflectionVector) * _ReflectionColor;              
  8. #endif  
5.法线和高光

         水面法线贴图来实现扰动,在太阳或者月亮的方向产生高光.


6.互动的水波纹

         如果角色走进水面,应该产生波纹的.实现原理就是先渲染一张水波纹扰动图片,然后水面再根据这个图来扰动水面.

------------------------------------------------------------------------------------------------------------------

以上6大功能实现后,这个水面看起来相对完美了,基本满足了我这个强迫症患者的需求.其实还有些地方没处理的,比如水面的LOD,

水面的减面等等.

整个水面shader的编辑界面:


水面生成工具:

[csharp]  view plain  copy
  1. // 2016.5.22 luoyinan 自动生成水面  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.IO;  
  5. using System.Text;  
  6. using UnityEngine;  
  7. using UnityEngine.SceneManagement;  
  8.   
  9. namespace Luoyinan  
  10. {  
  11.     public enum MeshType  
  12.     {  
  13.         Gizmos_FullMesh,  
  14.         Gizmos_WaterMesh,  
  15.         WaterMesh,  
  16.     }  
  17.   
  18.     public class WaterGenerateTool : MonoBehaviour  
  19.     {  
  20.         [Range(1, 200)]  
  21.         public int halfWidth = 20;  
  22.         [Range(1, 200)]  
  23.         public int halfHeight = 20;  
  24.         public float gridSize = 2.0f;  
  25.         public float maxWaterDepth = 4.0f;  
  26.         public Material material;  
  27.   
  28.         string m_ShaderName = "Luoyinan/Scene/Water/WaterStandard";  
  29.         Mesh m_GizmosMesh;  
  30.         Vector3 m_LocalPos;  
  31.         int m_GridNumX;  
  32.         int m_GridNumZ;  
  33.   
  34.         bool[] m_VerticesFlag;  
  35.         float[] m_VerticesAlpha;  
  36.         Vector3[] m_Vertices;  
  37.         int[] m_Triangles;  
  38.         List<Vector3> m_VerticesList = new List<Vector3>();  
  39.         List<Color> m_ColorsList = new List<Color>();  
  40.         List<Vector2> m_UvList = new List<Vector2>();  
  41.         List<int> m_TrianglesList = new List<int>();  
  42.   
  43.         void OnDrawGizmosSelected()  
  44.         {  
  45.             // 水面指示器  
  46.             Gizmos.matrix = transform.localToWorldMatrix;  
  47.             if (m_GizmosMesh != null)  
  48.                 UnityEngine.Object.DestroyImmediate(m_GizmosMesh);  
  49.             m_GizmosMesh = CreateMesh(MeshType.Gizmos_WaterMesh);  
  50.             Gizmos.DrawWireMesh(m_GizmosMesh);  
  51.         }  
  52.   
  53.         public void GenerateWater()  
  54.         {  
  55.             Mesh mesh = CreateMesh(MeshType.WaterMesh);  
  56.   
  57.             // 渲染水面  
  58.             foreach (Transform child in transform)  
  59.             {  
  60.                 DestroyImmediate(child.gameObject);  
  61.             }  
  62.             string name = string.Format("{0}_{1}_{2}", SceneManager.GetActiveScene().name, transform.name, transform.position);   
  63.             mesh.name = name;  
  64.             GameObject go = new GameObject(name);  
  65.             go.transform.parent = transform;  
  66.             go.transform.localPosition = m_LocalPos;  
  67.             go.layer = LayerMask.NameToLayer("Water");  
  68.             MeshFilter mf = go.AddComponent<MeshFilter>();  
  69.             MeshRenderer mr = go.AddComponent<MeshRenderer>();  
  70.             if (material == null)  
  71.                 material = new Material(Shader.Find(m_ShaderName));  
  72.             mr.sharedMaterial = material;  
  73.             mf.sharedMesh = mesh;   
  74.   
  75.             // obj模型不支持顶点颜色,所以暂时不导出了.  
  76.             // 导出obj模型  
  77.             //MeshToFile(mf, "Assets/" + name + ".obj");  
  78.         }  
  79.   
  80.         Mesh CreateMesh(MeshType type)  
  81.         {  
  82.             Mesh mesh = new Mesh();  
  83.             mesh.MarkDynamic();  
  84.             m_GridNumX = halfWidth * 2;  
  85.             m_GridNumZ = halfHeight * 2;  
  86.             Vector3 centerOffset = new Vector3(-halfWidth, 0, -halfHeight);  
  87.   
  88.             if (type == MeshType.Gizmos_FullMesh)  
  89.             {  
  90.                 int vectices_num = m_GridNumX * m_GridNumZ * 4;  
  91.                 int triangles_num = m_GridNumX * m_GridNumZ * 6;  
  92.                 m_Vertices = new Vector3[vectices_num];  
  93.                 m_Triangles = new int[triangles_num];  
  94.               
  95.                 // 从左下角开始创建,三角形索引顺时针是正面.  
  96.                 // 2 3  
  97.                 // 0 1  
  98.                 for (int z = 0; z < m_GridNumZ; ++z)  
  99.                 {  
  100.                     for (int x = 0; x < m_GridNumX; ++x)  
  101.                     {  
  102.                         int index = x + z * m_GridNumX;  
  103.                         int i = index * 4;  
  104.                         int j = index * 6;  
  105.   
  106.                         m_Vertices[i] = GetVertexLocalPos(x, z, centerOffset);  
  107.                         m_Vertices[i + 1] = GetVertexLocalPos(x + 1, z, centerOffset);  
  108.                         m_Vertices[i + 2] = GetVertexLocalPos(x, z + 1, centerOffset);  
  109.                         m_Vertices[i + 3] = GetVertexLocalPos(x + 1, z + 1, centerOffset);  
  110.   
  111.                         m_Triangles[j] = i;  
  112.                         m_Triangles[j + 1] = i + 2;  
  113.                         m_Triangles[j + 2] = i + 3;  
  114.                         m_Triangles[j + 3] = i + 3;  
  115.                         m_Triangles[j + 4] = i + 1;  
  116.                         m_Triangles[j + 5] = i;  
  117.                     }  
  118.                 }  
  119.   
  120.                 mesh.vertices = m_Vertices;  
  121.                 mesh.triangles = m_Triangles;  
  122.                 mesh.RecalculateNormals();  
  123.                 mesh.RecalculateBounds();  
  124.             }  
  125.             else if (type == MeshType.Gizmos_WaterMesh)  
  126.             {  
  127.                 CalcWaterMesh();  
  128.   
  129.                 m_VerticesList.Clear();  
  130.                 m_ColorsList.Clear();  
  131.                 m_TrianglesList.Clear();  
  132.                 int counter = 0;  
  133.   
  134.                 // 从左下角开始创建,三角形索引顺时针是正面.  
  135.                 // 2 3  
  136.                 // 0 1  
  137.                 for (int z = 0; z < m_GridNumZ; ++z)  
  138.                 {  
  139.                     for (int x = 0; x < m_GridNumX; ++x)  
  140.                     {  
  141.                         if (!IsValidGrid(x, z))  
  142.                             continue;  
  143.   
  144.                         int i = counter * 4;  
  145.   
  146.                         m_VerticesList.Add(GetVertexLocalPos(x, z, centerOffset));  
  147.                         m_VerticesList.Add(GetVertexLocalPos(x + 1, z, centerOffset));  
  148.                         m_VerticesList.Add(GetVertexLocalPos(x, z + 1, centerOffset));  
  149.                         m_VerticesList.Add(GetVertexLocalPos(x + 1, z + 1, centerOffset));  
  150.   
  151.                         m_TrianglesList.Add(i);  
  152.                         m_TrianglesList.Add(i + 2);  
  153.                         m_TrianglesList.Add(i + 3);  
  154.                         m_TrianglesList.Add(i + 3);  
  155.                         m_TrianglesList.Add(i + 1);  
  156.                         m_TrianglesList.Add(i);  
  157.   
  158.                         ++counter;  
  159.                     }  
  160.                 }  
  161.   
  162.                 // 忘记添加collider了?  
  163.                 if (m_VerticesList.Count == 0)  
  164.                     return CreateMesh(MeshType.Gizmos_FullMesh);  
  165.   
  166.                 mesh.vertices = m_VerticesList.ToArray();  
  167.                 mesh.triangles = m_TrianglesList.ToArray();  
  168.                 mesh.RecalculateNormals();  
  169.                 mesh.RecalculateBounds();  
  170.             }  
  171.             else if (type == MeshType.WaterMesh)  
  172.             {  
  173.                 CalcWaterMesh();  
  174.   
  175.                 m_VerticesList.Clear();  
  176.                 m_ColorsList.Clear();  
  177.                 m_UvList.Clear();  
  178.                 m_TrianglesList.Clear();  
  179.                 int counter = 0;  
  180.   
  181.                 // 先循环一次,找出最小最大的格子,让UV计算更精确.  
  182.                 int minX = m_GridNumX - 1;  
  183.                 int minZ = m_GridNumZ - 1;  
  184.                 int maxX = 0;  
  185.                 int maxZ = 0;  
  186.                 for (int z = 0; z < m_GridNumZ; ++z)  
  187.                 {  
  188.                     for (int x = 0; x < m_GridNumX; ++x)  
  189.                     {  
  190.                         if (!IsValidGrid(x, z))  
  191.                             continue;  
  192.   
  193.                         minX = (x < minX) ? x : minX;  
  194.                         minZ = (z < minZ) ? z : minZ;  
  195.                         maxX = (x > maxX) ? x : maxX;  
  196.                         maxZ = (z > maxZ) ? z : maxZ;  
  197.                     }  
  198.                 }  
  199.                 int newGridNumX = maxX - minX + 1;  
  200.                 int newGridNumZ = maxZ - minZ + 1;  
  201.   
  202.                 // 创建的水面模型应该做原点矫正,以自己形状的中心为原点,这样好支持水波纹的计算.详见WaterRippleGenerateTool  
  203.                 float halfGridNumX = (float)newGridNumX * 0.5f;  
  204.                 float halfGridNumZ = (float)newGridNumZ * 0.5f;  
  205.                 Vector3 offsetAdjust = new Vector3(-(float)minX - halfGridNumX, 0, -(float)minZ - halfGridNumZ);  
  206.                 m_LocalPos = (centerOffset - offsetAdjust) * gridSize;  
  207.                 centerOffset = offsetAdjust;                                 
  208.                       
  209.                 // TODO: 水面中心某些alpha为1的顶点其实可以去掉,需要一个自动减面算法.  
  210.   
  211.                 // 从左下角开始创建,三角形索引顺时针是正面.  
  212.                 // 2 3  
  213.                 // 0 1  
  214.                 for (int z = 0; z < m_GridNumZ; ++z)  
  215.                 {  
  216.                     for (int x = 0; x < m_GridNumX; ++x)  
  217.                     {  
  218.                         if (!IsValidGrid(x, z))  
  219.                             continue;  
  220.   
  221.                         int i = counter * 4;  
  222.                         int newX = x - minX;  
  223.                         int newZ = z - minZ;  
  224.   
  225.                         m_VerticesList.Add(GetVertexLocalPos(x, z, centerOffset));  
  226.                         m_VerticesList.Add(GetVertexLocalPos(x + 1, z, centerOffset));  
  227.                         m_VerticesList.Add(GetVertexLocalPos(x, z + 1, centerOffset));  
  228.                         m_VerticesList.Add(GetVertexLocalPos(x + 1, z + 1, centerOffset));  
  229.   
  230.                         m_ColorsList.Add(new Color(1.0f, 1.0f, 1.0f, GetVertexAlpha(x, z)));  
  231.                         m_ColorsList.Add(new Color(1.0f, 1.0f, 1.0f, GetVertexAlpha(x + 1, z)));  
  232.                         m_ColorsList.Add(new Color(1.0f, 1.0f, 1.0f, GetVertexAlpha(x, z + 1)));  
  233.                         m_ColorsList.Add(new Color(1.0f, 1.0f, 1.0f, GetVertexAlpha(x + 1, z + 1)));  
  234.   
  235.                         m_UvList.Add(new Vector2((float)(newX) / (float)newGridNumX, (float)newZ / (float)newGridNumZ));  
  236.                         m_UvList.Add(new Vector2((float)(newX + 1) / (float)newGridNumX, (float)newZ / (float)newGridNumZ));  
  237.                         m_UvList.Add(new Vector2((float)newX / (float)newGridNumX, (float)(newZ + 1) / (float)newGridNumZ));  
  238.                         m_UvList.Add(new Vector2((float)(newX + 1) / (float)newGridNumX, (float)(newZ + 1) / (float)newGridNumZ));  
  239.   
  240.                         m_TrianglesList.Add(i);  
  241.                         m_TrianglesList.Add(i + 2);  
  242.                         m_TrianglesList.Add(i + 3);  
  243.                         m_TrianglesList.Add(i + 3);  
  244.                         m_TrianglesList.Add(i + 1);  
  245.                         m_TrianglesList.Add(i);  
  246.   
  247.                         ++counter;  
  248.                     }  
  249.                 }  
  250.   
  251.                 mesh.vertices = m_VerticesList.ToArray();  
  252.                 mesh.colors = m_ColorsList.ToArray();  
  253.                 mesh.uv = m_UvList.ToArray();  
  254.                 mesh.triangles = m_TrianglesList.ToArray();  
  255.                 mesh.RecalculateNormals();  
  256.                 mesh.RecalculateBounds();  
  257.             }  
  258.   
  259.             return mesh;  
  260.         }  
  261.   
  262.         void CalcWaterMesh()  
  263.         {  
  264.             int VerticesNum = (m_GridNumX + 1) * (m_GridNumZ + 1);  
  265.             m_VerticesFlag = new bool[VerticesNum];  
  266.             m_VerticesAlpha = new float[VerticesNum];  
  267.   
  268.             WaterBoundaryFill8(halfWidth, halfHeight, transform.position.y);  
  269.         }  
  270.   
  271.         // 八方向的边界填充算法  
  272.         void WaterBoundaryFill8(int x, int z, float boundaryHeight)  
  273.         {  
  274.             int index = x + z * (m_GridNumX + 1);  
  275.             if (m_VerticesFlag[index])  
  276.                 return;  
  277.   
  278.             float height = GetHeight(x, z);  
  279.             if (height <= boundaryHeight)  
  280.             {  
  281.                 m_VerticesFlag[index] = true;  
  282.                 float difference = Mathf.Clamp(boundaryHeight - height, 0, maxWaterDepth);  
  283.                 m_VerticesAlpha[index] = Mathf.Clamp01(difference / maxWaterDepth);  
  284.   
  285.                 if (x + 1 < m_GridNumX + 1 && x - 1 >= 0 && z + 1 < m_GridNumZ + 1 && z - 1 >= 0)  
  286.                 {  
  287.                     WaterBoundaryFill8(x + 1, z, boundaryHeight);  
  288.                     WaterBoundaryFill8(x - 1, z, boundaryHeight);  
  289.                     WaterBoundaryFill8(x, z + 1, boundaryHeight);  
  290.                     WaterBoundaryFill8(x, z - 1, boundaryHeight);  
  291.   
  292.                     WaterBoundaryFill8(x - 1, z - 1, boundaryHeight);  
  293.                     WaterBoundaryFill8(x + 1, z - 1, boundaryHeight);  
  294.                     WaterBoundaryFill8(x - 1, z + 1, boundaryHeight);  
  295.                     WaterBoundaryFill8(x + 1, z + 1, boundaryHeight);  
  296.                 }  
  297.             }  
  298.         }  
  299.   
  300.         float GetHeight(int x, int z)  
  301.         {  
  302.             float height = float.MinValue;  
  303.             Vector3 centerOffset = new Vector3(-m_GridNumX * 0.5f, 0, -m_GridNumZ * 0.5f);  
  304.             Vector3 worldPos = GetVertexLocalPos(x, z, centerOffset) + transform.position;  
  305.             worldPos.y += 100.0f;  
  306.             RaycastHit hit;  
  307.             if (Physics.Raycast(worldPos, -Vector3.up, out hit, 200.0f))  
  308.             {  
  309.                 height = hit.point.y;  
  310.             }  
  311.             else  
  312.             {  
  313.                 //LogSystem.DebugLog("Physics.Raycast失败,请检查是否有Collider. x:{0} z:{0}", x, z);  
  314.             }  
  315.               
  316.             return height;  
  317.         }  
  318.   
  319.         bool IsValidGrid(int x, int z)  
  320.         {  
  321.             // 4个顶点只要有一个合法,就算合法.  
  322.             if (isValidVertex(x, z))  
  323.                 return true;  
  324.             if (isValidVertex(x + 1, z))  
  325.                 return true;  
  326.             if (isValidVertex(x, z + 1))  
  327.                 return true;  
  328.             if (isValidVertex(x + 1, z + 1))  
  329.                 return true;  
  330.   
  331.             return false;  
  332.         }  
  333.   
  334.         bool isValidVertex(int x, int z)  
  335.         {  
  336.             int index = x + z * (m_GridNumX + 1);  
  337.             return m_VerticesFlag[index];  
  338.         }  
  339.   
  340.         float GetVertexAlpha(int x, int z)  
  341.         {  
  342.             int index = x + z * (m_GridNumX + 1);  
  343.             return m_VerticesAlpha[index];  
  344.         }  
  345.         Vector3 GetVertexLocalPos(int x, int z, Vector3 centerOffset)  
  346.         {  
  347.             return new Vector3((x + centerOffset.x) * gridSize, 0, (z + centerOffset.z) * gridSize);  
  348.         }  
  349.         // 暂时没用到  
  350.         bool IsNearbyBoundary(int x, int z, float boundaryHeight)  
  351.         {  
  352.             float height = GetHeight(x + 1, z);  
  353.             if (height > boundaryHeight)  
  354.                 return true;  
  355.             height = GetHeight(x - 1, z);  
  356.             if (height > boundaryHeight)  
  357.                 return true;  
  358.             height = GetHeight(x, z + 1);  
  359.             if (height > boundaryHeight)  
  360.                 return true;  
  361.             height = GetHeight(x, z - 1);  
  362.             if (height > boundaryHeight)  
  363.                 return true;  
  364.   
  365.             return false;  
  366.         }  
  367.   
  368.         public void MeshToFile(MeshFilter mf, string filename)  
  369.         {  
  370.             using (StreamWriter sw = new StreamWriter(filename))  
  371.             {  
  372.                 sw.Write(MeshToString(mf));  
  373.             }  
  374.         }  
  375.   
  376.         public string MeshToString(MeshFilter mf)  
  377.         {  
  378.             Mesh m = mf.sharedMesh;  
  379.             Material[] mats = mf.GetComponent<Renderer>().sharedMaterials;  
  380.   
  381.             StringBuilder sb = new StringBuilder();  
  382.   
  383.             sb.Append("g ").Append(mf.name).Append("\n");  
  384.             foreach (Vector3 v in m.vertices)  
  385.             {  
  386.                 sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z));  
  387.             }  
  388.             sb.Append("\n");  
  389.             foreach (Vector3 v in m.normals)  
  390.             {  
  391.                 sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z));  
  392.             }  
  393.             sb.Append("\n");  
  394.             foreach (Vector3 v in m.uv)  
  395.             {  
  396.                 sb.Append(string.Format("vt {0} {1}\n", v.x, v.y));  
  397.             }  
  398.             for (int material = 0; material < m.subMeshCount; material++)  
  399.             {  
  400.                 sb.Append("\n");  
  401.                 sb.Append("usemtl ").Append(mats[material].name).Append("\n");  
  402.                 sb.Append("usemap ").Append(mats[material].name).Append("\n");  
  403.   
  404.                 int[] triangles = m.GetTriangles(material);  
  405.                 for (int i = 0; i < triangles.Length; i += 3)  
  406.                 {  
  407.                     sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n",  
  408.                         triangles[i] + 1, triangles[i + 1] + 1, triangles[i + 2] + 1));  
  409.                 }  
  410.             }  
  411.             return sb.ToString();  
  412.         }  
  413.     }  
  414. }  

水波纹产生工具:

[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using System.Collections.Generic;  
  4.   
  5. public class WaterRippleGenerateTool : EffectTool  
  6. {  
  7.     public RenderTexture _rt;  
  8.   
  9.     public int RT_SIZE_SCALE = 2;  
  10.     private Material _mat;  
  11.   
  12.     public float frequency = 2.5f;  
  13.     public float scale = 0.1f;  
  14.     public float power = 2;  
  15.     public float centralized = 0.25f;  
  16.     public float falloff = 3;  
  17.   
  18.     public Renderer waterRenderer;  
  19.   
  20.     private List<Vector4> _list = new List<Vector4>();  
  21.   
  22.   
  23.     public bool demo;  
  24.     public override void restart()  
  25.     {  
  26.         float aspectRatio = 1.0f;  
  27.   
  28.         if (_rt == null)  
  29.         {  
  30.             if (waterRenderer == null)  
  31.                 waterRenderer = GetComponent<MeshRenderer>();  
  32.   
  33.             if (waterRenderer != null)  
  34.             {             
  35.                 if (GetComponent<MeshCollider>() == null)  
  36.                     gameObject.AddComponent<MeshCollider>();  
  37.   
  38.                 int w = (int)waterRenderer.bounds.size.x * RT_SIZE_SCALE;  
  39.                 int h = (int)waterRenderer.bounds.size.z * RT_SIZE_SCALE;  
  40.                 _rt = new RenderTexture(w, h, 0);  
  41.                 waterRenderer.sharedMaterial.SetTexture("_RippleTex", _rt);  
  42.   
  43.                 aspectRatio = (float)w / (float)h;  
  44.             }               
  45.         }  
  46.         if (_mat == null)  
  47.         {  
  48.             _mat = new Material(Shader.Find("Luoyinan/Scene/Water/WaterRipple"));  
  49.             _mat.SetVector("_RippleData"new Vector4(frequency, scale, centralized, falloff));  
  50.             _mat.SetFloat("_AspectRatio", aspectRatio);  
  51.         }  
  52.     }  
  53.   
  54.     public void setDrop(Vector3 pos)  
  55.     {  
  56.         Vector3 rel = pos - transform.position;  
  57.         float width = waterRenderer.bounds.size.x;  
  58.         float height = waterRenderer.bounds.size.z;  
  59.         Vector4 dd = new Vector4(rel.x / width + 0.5f, rel.z / height + 0.5f, 0, power); // MVP空间位置[0, 1]  
  60.         _list.Add(dd);  
  61.     }  
  62.   
  63.     void Update()  
  64.     {  
  65.         int count = _list.Count;  
  66.         float deltaTime = Time.deltaTime;  
  67.         RenderTexture oldRT = RenderTexture.active;  
  68.         Graphics.SetRenderTarget(_rt);  
  69.         GL.Clear(falsetrue, Color.black);  
  70.   
  71.         if (count > 0)  
  72.         {  
  73.             _mat.SetVector("_RippleData"new Vector4(frequency, scale, centralized, falloff));  
  74.         }  
  75.   
  76.         for (int i = count - 1; i >= 0; i--)  
  77.         {  
  78.             Vector4 drop = _list[i];  
  79.             drop.z = drop.z + deltaTime;  
  80.   
  81.             if (drop.z > 3)  
  82.             {  
  83.                 _list.RemoveAt(i);  
  84.                 continue;  
  85.             }  
  86.             else  
  87.             {  
  88.                 _list[i] = drop;  
  89.             }  
  90.   
  91.             GL.PushMatrix();  
  92.             _mat.SetPass(0);  
  93.             _mat.SetVector("_Drop1", drop);  
  94.             GL.LoadOrtho();  
  95.             GL.Begin(GL.QUADS);  
  96.             GL.Vertex3(0, 1, 0);  
  97.             GL.Vertex3(1, 1, 0);  
  98.             GL.Vertex3(1, 0, 0);  
  99.             GL.Vertex3(0, 0, 0);  
  100.             GL.End();  
  101.             GL.PopMatrix();  
  102.         }  
  103.         RenderTexture.active = oldRT;  
  104.   
  105.         if (demo)  
  106.         {  
  107.             if (Input.GetKeyDown(KeyCode.Space))  
  108.             {  
  109.                 setDrop(transform.position);  
  110.             }  
  111.         }  
  112.     }  
  113.   
  114.     public override void end()  
  115.     {  
  116.         if (_rt != null)  
  117.         {  
  118.             _rt.Release();  
  119.         }  
  120.         _rt = null;  
  121.     }  
  122. }  

水面脚本:

[csharp]  view plain  copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using UnityEngine;  
  4.   
  5. namespace Luoyinan  
  6. {  
  7.     [ExecuteInEditMode]   
  8.     public class WaterStandard : MonoBehaviour  
  9.     {  
  10.         public bool runtimeReflective = false;  
  11.         public bool runtimeRefractive = true;  
  12.         public int textureSize = 256;  
  13.         public float clipPlaneOffset = 0.07f;  
  14.         public LayerMask reflectLayers = -1;  
  15.         public LayerMask refractLayers = -1;  
  16.   
  17.         private Dictionary<Camera, Camera> m_ReflectionCameras = new Dictionary<Camera, Camera>();   
  18.         private Dictionary<Camera, Camera> m_RefractionCameras = new Dictionary<Camera, Camera>();  
  19.         public RenderTexture m_ReflectionTexture;  
  20.         public RenderTexture m_RefractionTexture;  
  21.         private int m_OldReflectionTextureSize;  
  22.         private int m_OldRefractionTextureSize;  
  23.         private static bool s_InsideWater;  
  24.   
  25.         public void OnWillRenderObject()  
  26.         {  
  27.             if (!FindHardwareWaterSupport())  
  28.             {  
  29.                 enabled = false;  
  30.                 return;  
  31.             }             
  32.   
  33.             if (!enabled || !GetComponent<Renderer>()   
  34.                 || !GetComponent<Renderer>().sharedMaterial   
  35.                 || !GetComponent<Renderer>().enabled)  
  36.             {  
  37.                 return;  
  38.             }  
  39.   
  40.             Camera cam = Camera.current;  
  41.             if (!cam)  
  42.                 return;  
  43.   
  44.             // 防止递归调用  
  45.             if (s_InsideWater)  
  46.                 return;  
  47.             s_InsideWater = true;  
  48.   
  49.             // 创建摄像机和渲染纹理  
  50.             Camera reflectionCamera, refractionCamera;  
  51.             CreateWaterObjects(cam, out reflectionCamera, out refractionCamera);  
  52.               
  53.             Vector3 pos = transform.position;  
  54.             Vector3 normal = transform.up;  
  55.             if (runtimeReflective)  
  56.             {  
  57.                 UpdateCameraModes(cam, reflectionCamera);  
  58.   
  59.                 // 水平面作为反射平面  
  60.                 float d = -Vector3.Dot(normal, pos) - clipPlaneOffset;  
  61.                 Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);  
  62.   
  63.                 // 反射矩阵  
  64.                 Matrix4x4 reflection = Matrix4x4.zero;  
  65.                 CalculateReflectionMatrix(ref reflection, reflectionPlane);  
  66.                 Vector3 oldpos = cam.transform.position;  
  67.                 Vector3 newpos = reflection.MultiplyPoint(oldpos);  
  68.                 reflectionCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;  
  69.   
  70.                 // 反射平面作为摄像机近截面,这样可以自动裁剪水面或者水下.  
  71.                 Vector4 clipPlane = CameraSpacePlane(reflectionCamera, pos, normal, 1.0f);  
  72.                 reflectionCamera.projectionMatrix = cam.CalculateObliqueMatrix(clipPlane);  
  73.                 reflectionCamera.cullingMatrix = cam.projectionMatrix * cam.worldToCameraMatrix;  
  74.   
  75.                 reflectionCamera.cullingMask = ~(1 << LayerMask.NameToLayer("Water")) & reflectLayers.value; // 不要渲染水面本身  
  76.                 reflectionCamera.targetTexture = m_ReflectionTexture;  
  77.                 bool oldCulling = GL.invertCulling; // 渲染背面  
  78.                 GL.invertCulling = !oldCulling;  
  79.                 reflectionCamera.transform.position = newpos;  
  80.                 Vector3 euler = cam.transform.eulerAngles;  
  81.                 reflectionCamera.transform.eulerAngles = new Vector3(-euler.x, euler.y, euler.z);  
  82.                 reflectionCamera.Render();  
  83.                 reflectionCamera.transform.position = oldpos;  
  84.                 GL.invertCulling = oldCulling;  
  85.                 GetComponent<Renderer>().sharedMaterial.SetTexture("_ReflectionTex", m_ReflectionTexture);  
  86.             }  
  87.   
  88.             if (runtimeRefractive)  
  89.             {  
  90.                 UpdateCameraModes(cam, refractionCamera);  
  91.   
  92.                 refractionCamera.worldToCameraMatrix = cam.worldToCameraMatrix;  
  93.   
  94.                 // 反射平面作为摄像机近截面,这样可以自动裁剪水面或者水下.  
  95.                 Vector4 clipPlane = CameraSpacePlane(refractionCamera, pos, normal, -1.0f);  
  96.                 refractionCamera.projectionMatrix = cam.CalculateObliqueMatrix(clipPlane);  
  97.                 refractionCamera.cullingMatrix = cam.projectionMatrix * cam.worldToCameraMatrix;  
  98.   
  99.                 refractionCamera.cullingMask = ~(1 << LayerMask.NameToLayer("Water")) & refractLayers.value; // 不要渲染水面本身  
  100.                 refractionCamera.targetTexture = m_RefractionTexture;  
  101.                 refractionCamera.transform.position = cam.transform.position;  
  102.                 refractionCamera.transform.rotation = cam.transform.rotation;  
  103.                 refractionCamera.Render();  
  104.                 GetComponent<Renderer>().sharedMaterial.SetTexture("_RefractionTex", m_RefractionTexture);  
  105.             }  
  106.   
  107.             // keyword  
  108.             if (runtimeReflective)  
  109.                 Shader.EnableKeyword("_RUNTIME_REFLECTIVE");  
  110.             else  
  111.                 Shader.DisableKeyword("_RUNTIME_REFLECTIVE");  
  112.   
  113.             if (runtimeRefractive)  
  114.                 Shader.EnableKeyword("_RUNTIME_REFRACTIVE");  
  115.             else  
  116.                 Shader.DisableKeyword("_RUNTIME_REFRACTIVE");  
  117.   
  118.             s_InsideWater = false;  
  119.         }  
  120.   
  121.         void OnDisable()  
  122.         {  
  123.             if (m_ReflectionTexture)  
  124.             {  
  125.                 DestroyImmediate(m_ReflectionTexture);  
  126.                 m_ReflectionTexture = null;  
  127.             }  
  128.             if (m_RefractionTexture)  
  129.             {  
  130.                 DestroyImmediate(m_RefractionTexture);  
  131.                 m_RefractionTexture = null;  
  132.             }  
  133.             foreach (var kvp in m_ReflectionCameras)  
  134.             {  
  135.                 DestroyImmediate((kvp.Value).gameObject);  
  136.             }  
  137.             m_ReflectionCameras.Clear();  
  138.             foreach (var kvp in m_RefractionCameras)  
  139.             {  
  140.                 DestroyImmediate((kvp.Value).gameObject);  
  141.             }  
  142.             m_RefractionCameras.Clear();  
  143.         }  
  144.   
  145.         void UpdateCameraModes(Camera src, Camera dest)  
  146.         {  
  147.             if (dest == null)  
  148.                 return;  
  149.   
  150.             dest.clearFlags = src.clearFlags;  
  151.             dest.backgroundColor = src.backgroundColor;  
  152.             if (src.clearFlags == CameraClearFlags.Skybox)  
  153.             {  
  154.                 Skybox sky = src.GetComponent<Skybox>();  
  155.                 Skybox mysky = dest.GetComponent<Skybox>();  
  156.                 if (!sky || !sky.material)  
  157.                 {  
  158.                     mysky.enabled = false;  
  159.                 }  
  160.                 else  
  161.                 {  
  162.                     mysky.enabled = true;  
  163.                     mysky.material = sky.material;  
  164.                 }  
  165.             }  
  166.   
  167.             dest.farClipPlane = src.farClipPlane;  
  168.             dest.nearClipPlane = src.nearClipPlane;  
  169.             dest.orthographic = src.orthographic;  
  170.             dest.fieldOfView = src.fieldOfView;  
  171.             dest.aspect = src.aspect;  
  172.             dest.orthographicSize = src.orthographicSize;  
  173.         }  
  174.   
  175.         void CreateWaterObjects(Camera currentCamera, out Camera reflectionCamera, out Camera refractionCamera)  
  176.         {  
  177.             reflectionCamera = null;  
  178.             refractionCamera = null;  
  179.   
  180.             if (runtimeReflective)  
  181.             {  
  182.                 if (!m_ReflectionTexture || m_OldReflectionTextureSize != textureSize)  
  183.                 {  
  184.                     if (m_ReflectionTexture)  
  185.                     {  
  186.                         DestroyImmediate(m_ReflectionTexture);  
  187.                     }  
  188.                     m_ReflectionTexture = new RenderTexture(textureSize, textureSize, 16);  
  189.                     m_ReflectionTexture.name = "__WaterReflection" + GetInstanceID();  
  190.                     m_ReflectionTexture.isPowerOfTwo = true;  
  191.                     m_ReflectionTexture.hideFlags = HideFlags.DontSave;  
  192.                     m_OldReflectionTextureSize = textureSize;  
  193.                 }  
  194.   
  195.                 m_ReflectionCameras.TryGetValue(currentCamera, out reflectionCamera);  
  196.                 if (!reflectionCamera)   
  197.                 {  
  198.                     GameObject go = new GameObject("Water Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox));  
  199.                     reflectionCamera = go.GetComponent<Camera>();  
  200.                     reflectionCamera.enabled = false;  
  201.                     reflectionCamera.transform.position = transform.position;  
  202.                     reflectionCamera.transform.rotation = transform.rotation;  
  203.                     reflectionCamera.gameObject.AddComponent<FlareLayer>();  
  204.                     go.hideFlags = HideFlags.HideAndDontSave;  
  205.                     m_ReflectionCameras[currentCamera] = reflectionCamera;  
  206.                 }  
  207.             }  
  208.   
  209.             if (runtimeRefractive)  
  210.             {  
  211.                 if (!m_RefractionTexture || m_OldRefractionTextureSize != textureSize)  
  212.                 {  
  213.                     if (m_RefractionTexture)  
  214.                     {  
  215.                         DestroyImmediate(m_RefractionTexture);  
  216.                     }  
  217.                     m_RefractionTexture = new RenderTexture(textureSize, textureSize, 16);  
  218.                     m_RefractionTexture.name = "__WaterRefraction" + GetInstanceID();  
  219.                     m_RefractionTexture.isPowerOfTwo = true;  
  220.                     m_RefractionTexture.hideFlags = HideFlags.DontSave;  
  221.                     m_OldRefractionTextureSize = textureSize;  
  222.                 }  
  223.   
  224.                 m_RefractionCameras.TryGetValue(currentCamera, out refractionCamera);  
  225.                 if (!refractionCamera)   
  226.                 {  
  227.                     GameObject go =  
  228.                         new GameObject("Water Refr Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(),  
  229.                             typeof(Camera), typeof(Skybox));  
  230.                     refractionCamera = go.GetComponent<Camera>();  
  231.                     refractionCamera.enabled = false;  
  232.                     refractionCamera.transform.position = transform.position;  
  233.                     refractionCamera.transform.rotation = transform.rotation;  
  234.                     refractionCamera.gameObject.AddComponent<FlareLayer>();  
  235.                     go.hideFlags = HideFlags.HideAndDontSave;  
  236.                     m_RefractionCameras[currentCamera] = refractionCamera;  
  237.                 }  
  238.             }  
  239.         }  
  240.   
  241.         bool FindHardwareWaterSupport()  
  242.         {  
  243.             if (!SystemInfo.supportsRenderTextures || !GetComponent<Renderer>())  
  244.                 return false;  
  245.   
  246.             return true;  
  247.         }  
  248.   
  249.         Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)  
  250.         {  
  251.             Vector3 offsetPos = pos + normal * clipPlaneOffset;  
  252.             Matrix4x4 m = cam.worldToCameraMatrix;  
  253.             Vector3 cpos = m.MultiplyPoint(offsetPos);  
  254.             Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;  
  255.             return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));  
  256.         }  
  257.   
  258.         static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane)  
  259.         {  
  260.             reflectionMat.m00 = (1F - 2F * plane[0] * plane[0]);  
  261.             reflectionMat.m01 = (-2F * plane[0] * plane[1]);  
  262.             reflectionMat.m02 = (-2F * plane[0] * plane[2]);  
  263.             reflectionMat.m03 = (-2F * plane[3] * plane[0]);  
  264.   
  265.             reflectionMat.m10 = (-2F * plane[1] * plane[0]);  
  266.             reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);  
  267.             reflectionMat.m12 = (-2F * plane[1] * plane[2]);  
  268.             reflectionMat.m13 = (-2F * plane[3] * plane[1]);  
  269.   
  270.             reflectionMat.m20 = (-2F * plane[2] * plane[0]);  
  271.             reflectionMat.m21 = (-2F * plane[2] * plane[1]);  
  272.             reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);  
  273.             reflectionMat.m23 = (-2F * plane[3] * plane[2]);  
  274.   
  275.             reflectionMat.m30 = 0F;  
  276.             reflectionMat.m31 = 0F;  
  277.             reflectionMat.m32 = 0F;  
  278.             reflectionMat.m33 = 1F;  
  279.         }  
  280.     }  
  281. }  

水面shader:

[cpp]  view plain  copy
  1. Shader "Luoyinan/Scene/Water/WaterStandard"   
  2. {  
  3.     Properties   
  4.     {  
  5.         _ReflectionCubeMap("Reflection CubeMap",Cube) = ""{}  
  6.         _BumpMap("Normal Map", 2D) = "bump" {}  
  7.         _FoamTex ("Foam Texture ", 2D) = "black" {}  
  8.         _FoamGradientTex("Foam Gradient Texture ", 2D) = "white" {}  
  9.         _MainColor("Main Color", Color) = (0.3, 0.4, 0.7, 1.0)  
  10.         _ReflectionColor("Reflection Color", Color) = (1.0, 1.0, 1.0, 1.0)  
  11.         _SpecularIntensity("Specular Intensity", Range (0, 2)) = 1  
  12.         _SpecularSharp("Specular Sharp", Float) = 96  
  13.         _WaveIntensity("Wave Intensity", Range(0, 1)) = 1.0  
  14.         _FoamIntensity("Foam Intensity", Range (0, 1.0)) = 0.75  
  15.         _FoamSpeed("Foam Speed", Range (0, 1.0)) = 0.25  
  16.         _FoamFadeDepth("Foam Fade Depth", Range (0, 1.0)) = 0.4  
  17.         _FoamBrightness("Foam Brightness", Range (0, 2.0)) = 0  
  18.         _Force("Wave Speed&Direction", Vector) = (0.5, 0.5, -0.5, -0.5)  
  19.     }  
  20.   
  21.     SubShader   
  22.     {  
  23.         Tags  
  24.         {   
  25.             "Queue" = "Geometry+100"   
  26.             "IgnoreProjector" = "True"  
  27.         }  
  28.   
  29.         Pass   
  30.         {   
  31.             Lighting Off  
  32.             //ColorMask RGB  
  33.             Blend SrcAlpha OneMinusSrcAlpha  
  34.             CGPROGRAM  
  35.   
  36.             #include "UnityCG.cginc"  
  37.             #pragma multi_compile_fog  
  38.             #pragma vertex vert  
  39.             #pragma fragment frag  
  40.             #pragma fragmentoption ARB_precision_hint_fastest  
  41.               
  42.             #pragma shader_feature _FOAM_ON  
  43.             #pragma shader_feature _RUNTIME_REFLECTIVE  
  44.             #pragma shader_feature _RUNTIME_REFRACTIVE  
  45.             #pragma multi_compile __ _FANCY_STUFF  
  46.   
  47.             struct appdata_water   
  48.             {  
  49.                 float4 vertex : POSITION;  
  50.                 float2 texcoord : TEXCOORD0;  
  51.                 fixed4 color : COLOR;  
  52.             };  
  53.   
  54.             struct v2f   
  55.             {  
  56.                 float4 pos : POSITION;  
  57.                 fixed4 color : COLOR;  
  58.                 float2 uv0 : TEXCOORD0;  
  59.                 UNITY_FOG_COORDS(1)  
  60. #if _FANCY_STUFF  
  61.                 float2 uvNoise : TEXCOORD2;  
  62.                 float3 posWorld : TEXCOORD3;  
  63.                 half3 normal : TEXCOORD4;  
  64.     #if _FOAM_ON  
  65.                 float2 uvFoam : TEXCOORD5;    
  66.     #endif        
  67.     #if _RUNTIME_REFLECTIVE || _RUNTIME_REFRACTIVE  
  68.                 float4 uvProjector : TEXCOORD6;  
  69.     #endif  
  70. #endif  
  71.             };  
  72.           
  73.             uniform fixed4 _MainColor;  
  74. #if _FANCY_STUFF  
  75.             uniform fixed4 _Force;  
  76.             uniform sampler2D _BumpMap;  
  77.             float4 _BumpMap_ST;  
  78.             uniform fixed _WaveIntensity;  
  79.             uniform fixed4 _ReflectionColor;  
  80.             uniform fixed _SpecularIntensity;  
  81.             uniform half _SpecularSharp;  
  82.             half4 _GlobalMainLightDir;  
  83.             fixed4 _GlobalMainLightColor;  
  84.   
  85.     #if _FOAM_ON  
  86.             uniform sampler2D _FoamTex;  
  87.             uniform sampler2D _FoamGradientTex;  
  88.             float4 _FoamTex_ST;  
  89.             uniform fixed _FoamIntensity;  
  90.             uniform fixed _FoamSpeed;  
  91.             uniform fixed _FoamFadeDepth;  
  92.             uniform fixed _FoamBrightness;  
  93.     #endif  
  94.   
  95.     #if _RUNTIME_REFLECTIVE  
  96.             uniform sampler2D _ReflectionTex;  
  97.     #else  
  98.             uniform samplerCUBE _ReflectionCubeMap;  
  99.     #endif  
  100.   
  101.     #if _RUNTIME_REFRACTIVE  
  102.             uniform sampler2D _RefractionTex;  
  103.     #endif  
  104.   
  105.             uniform sampler2D _RippleTex;  
  106. #endif  
  107.             v2f vert (appdata_water v)  
  108.             {  
  109.                 v2f o;  
  110.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  111.                 o.color = v.color;  
  112.                 o.uv0 = v.texcoord;  
  113. #if _FANCY_STUFF  
  114.                 o.uvNoise = TRANSFORM_TEX(v.texcoord, _BumpMap);  
  115.                 o.posWorld = mul(unity_ObjectToWorld, v.vertex).xyz;  
  116.                 o.normal = half3(0, 1 - _WaveIntensity, 0);   
  117.     #if _FOAM_ON  
  118.                 o.uvFoam = TRANSFORM_TEX(v.texcoord, _FoamTex);  
  119.     #endif  
  120.   
  121.     #if _RUNTIME_REFLECTIVE || _RUNTIME_REFRACTIVE  
  122.                 o.uvProjector = ComputeScreenPos(o.pos);  
  123.     #endif  
  124. #endif  
  125.                 UNITY_TRANSFER_FOG(o, o.pos);  
  126.                 return o;  
  127.             }  
  128.               
  129.             fixed4 frag (v2f i) : COLOR  
  130.             {  
  131.                 fixed waterDepth = i.color.a;  
  132. #if _FANCY_STUFF  
  133.                 // noise  
  134.                 half3 noise = UnpackNormal(tex2D(_BumpMap, i.uvNoise + _Time.xx * _Force.xy));  
  135.                 noise += UnpackNormal(tex2D(_BumpMap, i.uvNoise + _Time.xx * _Force.zw));  
  136.                 noise = normalize(noise.xzy) * _WaveIntensity; // 在水平面扰动.  
  137.   
  138.                 // ripple  
  139.                 fixed4 ripple = tex2D(_RippleTex, i.uv0) * 2;  
  140.                 half3 normalNoise = normalize(i.normal + noise + ripple.xyz);  
  141.   
  142.                 // fresnel  
  143.                 half3 viewDir = normalize(_WorldSpaceCameraPos - i.posWorld);  
  144.                 half fresnel = 1 - saturate(dot(viewDir, normalNoise));  
  145.                 fresnel = 0.25 + fresnel * 0.75;  
  146.   
  147.                 // reflection  
  148.     #if _RUNTIME_REFLECTIVE  
  149.                 float4 uv1 = i.uvProjector; uv1.xy += noise.xy * 0.25;  
  150.                 fixed4 refl = tex2Dproj(_ReflectionTex, UNITY_PROJ_COORD(uv1)) * _ReflectionColor;  
  151.     #else         
  152.                 half3 worldReflectionVector = normalize(reflect(-viewDir, normalNoise));  
  153.                 fixed4 refl = texCUBE(_ReflectionCubeMap, worldReflectionVector) * _ReflectionColor;              
  154.     #endif  
  155.                 // refractive  
  156.     #if _RUNTIME_REFRACTIVE  
  157.                 float4 uv2 = i.uvProjector; uv2.xy += noise.xy * 0.5;  
  158.                 fixed4 refr = tex2Dproj(_RefractionTex, UNITY_PROJ_COORD(uv2));  
  159.     #else  
  160.                 fixed4 refr = _MainColor;  
  161.     #endif  
  162.   
  163.                 fixed4 finalColor = lerp(refr, refl, fresnel);  
  164.   
  165.     #if _FOAM_ON  
  166.                 // foam  
  167.                 half foamFactor = 1 - saturate(waterDepth / _FoamIntensity);   
  168.                 half foamGradient = 1 - tex2D(_FoamGradientTex, half2(foamFactor - _Time.y * _FoamSpeed, 0) + normalNoise.xy).r;  
  169.                 foamFactor *= foamGradient;  
  170.                 half4 foam = tex2D(_FoamTex, i.uvFoam + normalNoise.xy);  
  171.                 finalColor += foam * foamFactor;   
  172.     #endif  
  173.                 // specular  
  174.                 half3 h = normalize(_GlobalMainLightDir.xyz + viewDir);  
  175.                 half nh = saturate(dot(noise, h));  
  176.                 nh = pow(nh, _SpecularSharp);  
  177.                 finalColor += _GlobalMainLightColor * nh * _SpecularIntensity;  
  178.   
  179.                 // alpha  
  180.     #if _FOAM_ON  
  181.                 half factor = step(_FoamFadeDepth, waterDepth);  
  182.                 half newDepth = waterDepth / _FoamFadeDepth;  
  183.                 finalColor.a = _MainColor.a * waterDepth + foamFactor * _FoamBrightness * (factor +  newDepth * (1 - factor));  
  184.     #else  
  185.                 finalColor.a = _MainColor.a * waterDepth;  
  186.     #endif  
  187. #else  
  188.                 fixed4  finalColor = _MainColor;  
  189.                 finalColor.a *= waterDepth;  
  190. #endif  
  191.           
  192.                 UNITY_APPLY_FOG(i.fogCoord, finalColor);  
  193.                 return finalColor;  
  194.             }  
  195.   
  196.             ENDCG  
  197.         }   
  198.   
  199.         // 没用Unity自带的阴影,只是用来来渲染_CameraDepthsTexture.  
  200.         Pass  
  201.         {  
  202.             Tags { "LightMode" = "ShadowCaster" }  
  203.   
  204.             Fog { Mode Off }  
  205.             ZWrite On   
  206.             Offset 1, 1  
  207.   
  208.             CGPROGRAM  
  209.   
  210.             #pragma vertex vert  
  211.             #pragma fragment frag  
  212.             #pragma multi_compile_shadowcaster  
  213.             #pragma fragmentoption ARB_precision_hint_fastest  
  214.             #include "UnityCG.cginc"  
  215.   
  216.             struct v2f  
  217.             {  
  218.                 V2F_SHADOW_CASTER;  
  219.             };  
  220.   
  221.             v2f vert(appdata_base v)  
  222.             {  
  223.                 v2f o;  
  224.                 TRANSFER_SHADOW_CASTER(o)  
  225.                 return o;  
  226.             }  
  227.   
  228.             fixed4 frag(v2f i) : COLOR  
  229.             {  
  230.                 SHADOW_CASTER_FRAGMENT(i)  
  231.             }  
  232.   
  233.             ENDCG  
  234.         }  
  235.     }  
  236.   
  237.     Fallback off  
  238.     CustomEditor "WaterStandard_ShaderGUI"  
  239. }  

水波纹shader:

[cpp]  view plain  copy
  1. Shader "Luoyinan/Scene/Water/WaterRipple"   
  2. {  
  3.     Properties  
  4.     {  
  5.         _RippleData("frequency, scale, centralized, falloff", Vector) = (1,1,1,1)  
  6.         _AspectRatio("AspectRatio", Float) = 1  
  7.     }  
  8.   
  9.     SubShader  
  10.     {  
  11.         Pass   
  12.         {  
  13.             Blend One One  
  14.   
  15.             CGPROGRAM  
  16.             #pragma vertex vert  
  17.             #pragma fragment frag  
  18.             #pragma fragmentoption ARB_precision_hint_fastest  
  19.             #include "UnityCG.cginc"  
  20.   
  21.             struct appdata_t   
  22.             {  
  23.                 fixed4 vertex : POSITION;  
  24.             };  
  25.   
  26.             struct v2f   
  27.             {  
  28.                 fixed4 vertex : POSITION;  
  29.                 fixed3 pos : TEXCOORD0;  
  30.             };  
  31.   
  32.               
  33.             uniform fixed _AspectRatio;  
  34.             uniform fixed4 _RippleData; // Vector4(frequency, scale, centralized, falloff));  
  35.             fixed4 _Drop1;              // Vector4(origin.x, origin.z, time, power));  
  36.             static const half pi = 3.1415927;  
  37.   
  38.             fixed4 ripple(fixed2 position, fixed2 origin, fixed time, fixed power)  
  39.             {  
  40.                 fixed2 vec = position - origin;  
  41.                 vec.x *= _AspectRatio; // 做个矫正,让非正方形水面也适用.  
  42.                 fixed len = length(vec);  
  43.                 vec = normalize(vec);  
  44.   
  45.                 //fixed center = time * frequency * scale;  
  46.                 fixed center = time * _RippleData.y * _RippleData.x;  
  47.   
  48.                 // fixed phase = 2 * pi * ( time * frequency - len / scale);  
  49.                 fixed phase = 2 * pi * time * _RippleData.x - 2 * pi * len / _RippleData.y;  
  50.                 fixed intens = max(0, 0.1 - abs(center - len) * _RippleData.z) * power;  
  51.                 fixed fallOff = max(0, 1 - len * _RippleData.w);  
  52.                 fixed cut = step(0, phase);  
  53.                 return fixed4(vec.x, 1, vec.y, 0) * sin(phase) * intens * fallOff * cut;  
  54.             }  
  55.   
  56.             v2f vert(appdata_t v)  
  57.             {  
  58.                 v2f o;  
  59.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);  
  60.                 o.pos = v.vertex.xyz;  
  61.                 return o;  
  62.             }  
  63.   
  64.             fixed4 frag(v2f i) : COLOR  
  65.             {  
  66.                 fixed4 rip = ripple(i.pos, _Drop1.xy, _Drop1.z, _Drop1.w);  
  67.                 return rip;  
  68.             }  
  69.             ENDCG  
  70.         }  
  71.     }  
  72.   
  73.     Fallback Off  
  74. }  
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值