Unity3D 海水多线程渲染算法实现

发表于2017-09-20
评论1 4.5k浏览

海水仿真渲染一直是比较麻烦,虽然市面上有了各种海水的渲染算法,但是真正做到仿真渲染的少之又少。大多停留在试验阶段,达到了仿真的要求,但是硬件配置要求高,不利于推广。本篇文章就给大家介绍下关于海水的实施渲染以及通过算法实现船只航行轨迹效果,真实的达到了海水的渲染,海水的网格采用了多个面片网格拼接的方式,网格采用的是LOD处理的,这样就优化了效率。同时将海水的绘制以及算法实现放到C 中进行,这样对于复杂算法的实现效率明显提升。先给读者看几幅效果图:

船在海水中航行的轨迹效果图,轨迹是实时绘制的。再来一副海水到岸边产生的泡沫效果图:


除了岸边的效果图外,船在水中周围也会产生泡沫效果。最后一副效果图如下:


海水的反射折射效果。下面开始给读者介绍实现该海水的原理以及核心代码,最后把整个工程奉献给读者。

第一步:海水网格的实现,海水网格采用的是面片拼接的方式,并且面片采用了LOD运算,其在Unity中的效果如下所示:


从里向外,面片的数量逐步减少,它是根据摄像机的远近处理的,对应的核心代码如下所示: copy

  1. //update the meshes with the final calculated mesh data  
  2. void updateTiles(int a, int b) {  
  3.   
  4.     if(skipLods) {  
  5.         lodSkip ;  
  6.         if(lodSkip >= lodSkipFrames 1) lodSkip=0;  
  7.     }  
  8.   
  9.     for (int L0D=a; L0D<b; L0D ) {  
  10.         //if(L0D>  
  11.         //this will skip one update of the tiles higher then Lod0  
  12.         if(L0D>0 && lodSkip==0 && !ticked && skipLods) { break; }  
  13.         //this will skip one update of the LOD0 tiles because they got updated earlier when they should.  
  14.         if(ticked2 && L0D==0) { ticked2=falsecontinue; }  
  15.  
  16.         #if !NATIVE  
  17.             int den = MyIntPow (2, L0D);  
  18.             int idx = 0;  
  19.   
  20.             for (int y=0; y<g_height; y =den) {  
  21.                 for (int x=0; x<g_width; x =den) {  
  22.                     int idx2 = g_width * y   x;  
  23.                     verticesLOD[L0D] [idx] = vertices [idx2];  
  24.                     //lower the far lods to eliminate gaps in the horizon when having big waves  
  25.                     if(L0D>0) {  
  26.                         if(farLodOffset!=0) {  
  27.                             verticesLOD[L0D] [idx].y  = flodoffset[L0D] * flodFact;  
  28.                         }  
  29.                     }  
  30.                     tangentsLOD[L0D] [idx] = tangents [idx2];  
  31.                     normalsLOD[L0D] [idx ] = normals [idx2];  
  32.                 }             
  33.             }  
  34.         #else  
  35.             uocean._updateTilesA(verticesLOD[L0D], vertices, tangentsLOD[L0D], tangents, normalsLOD[L0D], normals, L0D, farLodOffset, flodoffset, flodFact);  
  36.         #endif  
  37.   
  38.         btiles_LOD[L0D].vertices = verticesLOD[L0D];  
  39.         btiles_LOD[L0D].normals = normalsLOD[L0D];  
  40.         btiles_LOD[L0D].tangents = tangentsLOD[L0D];  
  41.     }  
  42.   
  43.     if(ticked) ticked = false;  
  44. }  
  45.   
  46.       
  47. void GenerateTiles() {  
  48.   
  49.     int chDist, nmaxLod=0; // Chebychev distance  
  50.       
  51.     for (int y=0; y<tiles; y ) {  
  52.         for (int x=0; x<tiles; x ) {  
  53.             chDist = System.Math.Max (System.Math.Abs (tiles / 2 - y), System.Math.Abs (tiles / 2 - x));  
  54.             chDist = chDist > 0 ? chDist - 1 : 0;  
  55.             if(nmaxLod<chDist) nmaxLod = chDist;  
  56.         }  
  57.     }  
  58.     max_LOD = nmaxLod 1;  
  59.   
  60.     flodoffset = new float[max_LOD 1];  
  61.     float ffact = farLodOffset/max_LOD;  
  62.     for(int i=0; i<max_LOD 1; i ) {  
  63.         flodoffset[i] = i*ffact;  
  64.     }  
  65.   
  66.     btiles_LOD = new List<Mesh>();  
  67.     tiles_LOD = new List<List<Mesh>>();  
  68.   
  69.     for (int L0D=0; L0D<max_LOD; L0D ) {  
  70.         btiles_LOD.Add(new Mesh());  
  71.         tiles_LOD.Add (new List<Mesh>());  
  72.     }  
  73.   
  74.     GameObject tile;  
  75.   
  76.     int ntl = LayerMask.NameToLayer ("Water");  
  77.   
  78.     for (int y=0; y<tiles; y ) {  
  79.         for (int x=0; x<tiles; x ) {  
  80.             chDist = System.Math.Max (System.Math.Abs (tiles / 2 - y), System.Math.Abs (tiles / 2 - x));  
  81.             chDist = chDist > 0 ? chDist - 1 : 0;  
  82.             if(nmaxLod<chDist) nmaxLod = chDist;  
  83.             float cy = y - Mathf.Floor(tiles * 0.5f);  
  84.             float cx = x - Mathf.Floor(tiles * 0.5f);  
  85.             tile = new GameObject ("Lod_" chDist.ToString() ":" y.ToString() "x" x.ToString());  
  86.                  
  87.                Vector3 pos=tile.transform.position;  
  88.             pos.x = cx * size.x;  
  89.             pos.y = transform.position.y;  
  90.             pos.z = cy * size.z;  
  91.   
  92.             tile.transform.position=pos;  
  93.             tile.AddComponent <MeshFilter>();  
  94.             tile.AddComponent <MeshRenderer>();  
  95.                Renderer renderer = tile.GetComponent<Renderer>();  
  96.   
  97.             tile.GetComponent<MeshFilter>().mesh = btiles_LOD[chDist];  
  98.             //tile.isStatic = true;  
  99.   
  100.             //shader/material lod (needs improvement)  
  101.             if(useShaderLods && numberLods>1) {  
  102.                 if(numberLods==2) {  
  103.                     if(chDist <= sTilesLod) { if(material) renderer.material = material; }  
  104.                     if(chDist > sTilesLod) { if(material1) renderer.material = material1; }  
  105.                 }else if(numberLods==3){  
  106.                     if(chDist <= sTilesLod ) { if(material) renderer.material = material; }  
  107.                     if(chDist == sTilesLod 1) { if(material1) renderer.material = material1; }  
  108.                     if(chDist > sTilesLod 1) { if(material2) renderer.material = material2; }  
  109.                 }  
  110.             } else {  
  111.                 renderer.material = material;  
  112.             }  
  113.                  
  114.                //Make child of this object, so we don't clutter up the  
  115.                //scene hierarchy more than necessary.  
  116.                tile.transform.parent = transform;  
  117.           
  118.             //Also we don't want these to be drawn while doing refraction/reflection passes,  
  119.             //so we'll add the to the water layer for easy filtering.  
  120.             tile.layer = ntl;  
  121.   
  122.             tiles_LOD[chDist].Add( tile.GetComponent<MeshFilter>().mesh);  
  123.         }   
  124.     }  
  125.   
  126.     //enable/disable the fixed disc  
  127.     initDisc();  
  128. }  
在Unity中生成的效果如下所示:


第二步,海水的渲染Shader,根据不同的LOD等级实行不同的Shader渲染,举个例子,LOD等级2的Shader代码如下所示: copy

  1. Shader "Mobile/OceanL2" {  
  2.     Properties {  
  3.         _SurfaceColor ("SurfaceColor", Color) = (1,1,1,1)  
  4.         _WaterColor ("WaterColor", Color) = (1,1,1,1)  
  5.   
  6.         _Specularity ("Specularity", Range(0.01,1)) = 0.3  
  7.         _SpecPower("Specularity Power", Range(0,1)) = 1  
  8.   
  9.         [HideInInspector] _SunColor ("SunColor", Color) = (1,1,0.901,1)  
  10.   
  11.         _Bump ("Bump (RGB)", 2D) = "bump" {}  
  12.         _Size ("UVSize", Float) = 0.015625//this is the best value (1/64) to have the same uv scales of normal and foam maps on all ocean sizes  
  13.         [HideInInspector] _SunDir ("SunDir", Vector) = (0.3, -0.6, -1, 0)  
  14.   
  15.         _FakeUnderwaterColor ("Water Color LOD1", Color) = (0.196, 0.262, 0.196, 1)  
  16.         _DistanceCancellation ("Distance Cancellation", Float) = 2000  
  17.     }  
  18.       
  19.   
  20. //water bump  
  21.      SubShader {  
  22.         Tags { "RenderType" = "Opaque" "Queue"="Geometry"}  
  23.         LOD 2  
  24.         Pass {  
  25.             CGPROGRAM  
  26.             #pragma vertex vert  
  27.             #pragma fragment frag  
  28.             //#pragma multi_compile_fog  
  29.             #pragma multi_compile FOGON FOGOFF  
  30.             #pragma multi_compile DCON  DCOFF  
  31.  
  32.              
  33.  
  34.             #pragma target 2.0  
  35.             #include "UnityCG.cginc"  
  36.   
  37.             struct v2f {  
  38.                 float4 pos : SV_POSITION;  
  39.                 half3 floatVec : TEXCOORD0;  
  40.                 float2  bumpTexCoord : TEXCOORD1;  
  41.                 //half3  viewDir : TEXCOORD2;  
  42.                 half3  lightDir : TEXCOORD2;  
  43.                 half2 buv : TEXCOORD3;  
  44.                 half3 normViewDir : TEXCOORD4;  
  45.                 //UNITY_FOG_COORDS(7)  
  46.                 #ifdef FOGON  
  47.                 half dist : TEXCOORD5;  
  48.                 #ifdef DCON  
  49.                 half distCancellation : TEXCOORD6;  
  50.                 #endif  
  51.                 #endif  
  52.             };  
  53.   
  54.             half _Size;  
  55.             half4 _SunDir;  
  56.             half4 _FakeUnderwaterColor;  
  57.             #ifdef FOGON  
  58.             uniform half4 unity_FogStart;  
  59.             uniform half4 unity_FogEnd;  
  60.             uniform half4 unity_FogDensity;  
  61.             #ifdef DCON  
  62.             half _DistanceCancellation;  
  63.             #endif  
  64.             #endif  
  65.                          
  66.             v2f vert (appdata_tan v) {  
  67.                 v2f o;  
  68.                 UNITY_INITIALIZE_OUTPUT(v2f, o);  
  69.   
  70.                 o.bumpTexCoord.xy = v.vertex.xz*_Size;///float2(_Size.x, _Size.z)*5;  
  71.                 o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
  72.       
  73.                 half3 objSpaceViewDir = ObjSpaceViewDir(v.vertex);  
  74.                 half3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) );  
  75.                 half3x3 rotation = half3x3( v.tangent.xyz, binormal, v.normal );  
  76.       
  77.                 half3 viewDir = mul(rotation, objSpaceViewDir);  
  78.                 o.lightDir = mul(rotation, half3(_SunDir.xyz));  
  79.   
  80.                 o.buv = float2(o.bumpTexCoord.x   _CosTime.x * 0.2, o.bumpTexCoord.y   _SinTime.x * 0.3);  
  81.   
  82.                 o.normViewDir = normalize(viewDir);  
  83.   
  84.                 o.floatVec = normalize(o.normViewDir - normalize(o.lightDir));  
  85.  
  86.                 #ifdef FOGON  
  87.                 //manual fog  
  88.                 half fogDif = 1.0/(unity_FogEnd.x - unity_FogStart.x);  
  89.                 o.dist = (unity_FogEnd.x - length(o.pos.xyz)) * fogDif;  
  90.                 #ifdef DCON  
  91.                 o.distCancellation = (unity_FogEnd.x - _DistanceCancellation) * fogDif;  
  92.                 #endif  
  93.                 #endif  
  94.   
  95.                 //autofog  
  96.                 //UNITY_TRANSFER_FOG(o, o.pos);  
  97.   
  98.                 return o;  
  99.             }  
  100.   
  101.             sampler2D _Bump;  
  102.             half4 _WaterColor;  
  103.             half4 _SurfaceColor;  
  104.             half _Specularity;  
  105.             half _SpecPower;  
  106.             half4 _SunColor;  
  107.   
  108.             half4 frag (v2f i) : COLOR {  
  109.  
  110.                 #ifdef FOGON  
  111.                 #ifdef DCON  
  112.                 if(i.dist>i.distCancellation){  
  113.                 #endif  
  114.                 #endif  
  115.                     half3 tangentNormal0 = (tex2D(_Bump, i.buv.xy) * 2.0) -1;  
  116.                     half3 tangentNormal = normalize(tangentNormal0);  
  117.   
  118.                     half4 result = half4(0, 0, 0, 1);  
  119.                   
  120.                     //half fresnelLookup = dot(tangentNormal,i. normViewDir);  
  121.                     //float bias = 0.06;  
  122.                     //float power = 4.0;  
  123.                     //half fresnelTerm = 0.06   (1.0-0.06)*pow(1.0 - fresnelLookup, 4.0);  
  124.   
  125.                     half fresnelTerm = 1.0 - saturate(dot (i.normViewDir, tangentNormal0));  
  126.   
  127.                     half specular = pow(max(dot(i.floatVec,  tangentNormal) , 0.0), 250.0 * _Specularity ) * _SpecPower;  
  128.                   
  129.                     result.rgb = lerp(_WaterColor*_FakeUnderwaterColor, _SunColor.rgb*_SurfaceColor*0.85, fresnelTerm*0.6)    specular*_SunColor.rgb;  
  130.   
  131.                     //fog  
  132.                     //UNITY_APPLY_FOG(i.fogCoord, result);   
  133.  
  134.                     #ifdef FOGON  
  135.                     //manual fog (linear) (reduces instructions on d3d9)  
  136.                     float ff = saturate(i.dist);  
  137.                     result.rgb = lerp(unity_FogColor.rgb, result.rgb, ff);  
  138.                     #endif  
  139.   
  140.                     return result;  
  141.                 #ifdef FOGON  
  142.                 #ifdef DCON  
  143.                 }else{  
  144.                     return unity_FogColor;  
  145.                 }  
  146.                 #endif  
  147.                 #endif  
  148.             }  
  149.             ENDCG  
  150.               
  151.   
  152.         }  
  153.     }  
  154.   
  155.       
  156. }  
渲染的效果图如下所示:


远近海水很有层次感效果。

第三步:船只在海水中航行的轨迹效果以及随着海水起伏效果实现代码

  1. using UnityEngine;  
  2. using System.Collections.Generic;  
  3.   
  4. public class Boyancy : MonoBehaviour {  
  5.   
  6.     private Ocean ocean;  
  7.     public int renderQueue;  
  8.   
  9.     public bool useFixedUpdate = false;  
  10.     public bool moreAccurate = false;  
  11.     public float magnitude = 2f;  
  12.     public float ypos = 0.0f;  
  13.     private List<Vector3> blobs;  
  14.     private List<float[]> prevBoya;  
  15.   
  16.     //private bool engine = false;  
  17.     private List<float> sinkForces;  
  18.   
  19.     public float CenterOfMassOffset = -1f;  
  20.     public float dampCoeff = .1f;  
  21.   
  22.     //buoyancy slices. (Cannot be smaller then 2)  
  23.     //Raise these numbers if you want more accurate simulation. However it will add overhead. So keep it as small as possible.  
  24.     public int SlicesX = 2;  
  25.     public int SlicesZ = 2;  
  26.   
  27.     public int interpolation = 3;  
  28.     private int intplt;  
  29.     public bool ChoppynessAffectsPosition = false;  
  30.     public float ChoppynessFactor = 0.2f;  
  31.   
  32.     public bool WindAffectsPosition = false;  
  33.     public float WindFactor = 0.1f;  
  34.   
  35.     public bool xAngleAddsSliding = false;  
  36.     public float slideFactor = 0.1f;  
  37.   
  38.     public bool cvisible, wvisible, svisible;  
  39.     public Renderer _renderer ;  
  40.   
  41.     public bool sink = false;  
  42.     public float sinkForce = 3;  
  43.   
  44.     private float iF;   
  45.     private bool interpolate = false;  
  46.   
  47.     private Rigidbody rrigidbody;  
  48.     private int tick, tack;  
  49.     private Vector3 wpos, cpos;  
  50.     private bool useGravity;  
  51.   
  52.     private float accel;  
  53.     private int prevAngleX, currAngleX;  
  54.   
  55.     private float bbboyancy;  
  56.     private float prevBuoyancy;  
  57.   
  58.   
  59.     void Start () {  
  60.   
  61.         if(!_renderer) {  
  62.             _renderer = GetComponent<Renderer>();  
  63.             if(!_renderer) {  
  64.                 _renderer = GetComponentInChildren<Renderer>();  
  65.             }  
  66.         }  
  67.   
  68.         if(_renderer && renderQueue>0) _renderer.material.renderQueue = renderQueue;  
  69.   
  70.         if(!_renderer) {  
  71.             if(cvisible) { Debug.Log("Renderer to check visibility not assigned."); cvisible = false; }  
  72.             if(wvisible) { Debug.Log("Renderer to check visibility not assigned."); wvisible = false; }  
  73.             if(svisible) { Debug.Log("Renderer to check visibility not assigned."); svisible = false; }  
  74.         }  
  75.   
  76.         if(dampCoeff<0) dampCoeff = Mathf.Abs(dampCoeff);  
  77.   
  78.         rrigidbody =  GetComponent<Rigidbody>();  
  79.   
  80.         useGravity = rrigidbody.useGravity;  
  81.   
  82.         if(interpolation>0) {  
  83.             interpolate = true;  
  84.             iF = 1/(float)interpolation;  
  85.             intplt = interpolation;  
  86.         }  
  87.   
  88.         if(SlicesX<2) SlicesX=2;  
  89.         if(SlicesZ<2) SlicesZ=2;  
  90.   
  91.         ocean = Ocean.Singleton;  
  92.           
  93.         rrigidbody.centerOfMass = new Vector3 (0.0f, CenterOfMassOffset, 0.0f);  
  94.       
  95.         Vector3 bounds = GetComponent<BoxCollider> ().size;  
  96.   
  97.         float length = bounds.z;  
  98.         float width = bounds.x;  
  99.   
  100.         blobs = new List<Vector3> ();  
  101.         prevBoya = new List<float[]>();  
  102.   
  103.         int i = 0;  
  104.         float xstep = 1.0f / ((float)SlicesX - 1f);  
  105.         float ystep = 1.0f / ((float)SlicesZ - 1f);  
  106.       
  107.         sinkForces = new List<float>();  
  108.           
  109.         float totalSink = 0;  
  110.   
  111.         for (int x=0; x<SlicesX; x ) {  
  112.             for (int y=0; y<SlicesX; y ) {        
  113.                 blobs.Add (new Vector3 ((-0.5f   x * xstep) * width, 0.0f, (-0.5f   y * ystep) * length)   Vector3.up * ypos);  
  114.   
  115.                 if(interpolate) { prevBoya.Add(new float[interpolation]); }  
  116.                   
  117.                 float force =  Random.Range(0f,1f);  
  118.                 force = force * force;  
  119.                 totalSink  = force;  
  120.                 sinkForces.Add(force);  
  121.                 i ;  
  122.             }         
  123.         }  
  124.           
  125.         // normalize the sink forces  
  126.         for (int j=0; j< sinkForces.Count; j )  {  
  127.             sinkForces[j] = sinkForces[j] / totalSink * sinkForce;  
  128.         }  
  129.   
  130.     }  
  131.   
  132.     void Update() {  
  133.         if(!useFixedUpdate) update();  
  134.     }  
  135.   
  136.     void FixedUpdate() {  
  137.         if(useFixedUpdate) update();  
  138.     }  
  139.   
  140.   
  141.   
  142.     bool visible, lastvisible;  
  143.     int lastFrame=-15;  
  144.   
  145.     void update() {  
  146.   
  147.         if (ocean != null) {  
  148.   
  149.             visible = _renderer.isVisible;  
  150.   
  151.             //put object on the correct height of the sea surface when it has visibilty checks on and it became visible again.  
  152.             if(visible != lastvisible) {  
  153.                 if(visible && !lastvisible) {  
  154.                     if(Time.frameCount-lastFrame>15) {  
  155.                         float off = ocean.GetChoppyAtLocation(transform.position.x, transform.position.z);  
  156.                         float y = ocean.GetWaterHeightAtLocation2 (transform.position.x-off, transform.position.z);  
  157.                         transform.position = new Vector3(transform.position.x, y, transform.position.z);  
  158.                         lastFrame = Time.frameCount;  
  159.                     }  
  160.                 }  
  161.                 lastvisible = visible;  
  162.             }  
  163.   
  164.             //prevent use of gravity when buoyancy is disabled  
  165.             if(cvisible) {  
  166.                 if(useGravity) {  
  167.                     if(!visible) {  
  168.                             rrigidbody.useGravity=false;  
  169.                             if(wvisible && svisible) return;  
  170.                     } else {  
  171.                             rrigidbody.useGravity = true;  
  172.                         }  
  173.                 }else {  
  174.                     if(!visible) { if(wvisible && svisible) return;}   
  175.                 }  
  176.             }  
  177.   
  178.             float coef = dampCoeff;  
  179.             int index = 0, k=0;  
  180.   
  181.             int ran = (int)Random.Range(0, blobs.Count-1);  
  182.   
  183.   
  184.             for(int j = 0; j<blobs.Count; j ) {  
  185.   
  186.                 wpos = transform.TransformPoint (blobs[j]);  
  187.                 //get a random blob to apply a force with the choppy waves  
  188.                 if(ChoppynessAffectsPosition) { if(j == ran)  cpos = wpos; }  
  189.   
  190.                 if(!cvisible || visible) {  
  191.                     float buyancy = magnitude * (wpos.y);  
  192.   
  193.                     if (ocean.enabled) {  
  194.                         if(ocean.canCheckBuoyancyNow[0]==1) {  
  195.                             float off = 0;  
  196.                                 if(ocean.choppy_scale>0) off = ocean.GetChoppyAtLocation(wpos.x, wpos.z);  
  197.                             if(moreAccurate) {    
  198.                                 buyancy = magnitude * (wpos.y - ocean.GetWaterHeightAtLocation2 (wpos.x-off, wpos.z));  
  199.                             }else {  
  200.                                 buyancy = magnitude * (wpos.y - ocean.GetWaterHeightAtLocation (wpos.x-off, wpos.z));  
  201.                                 buyancy = Lerp(prevBuoyancy, buyancy, 0.5f);  
  202.                                 prevBuoyancy = buyancy;  
  203.                             }  
  204.                             bbboyancy = buyancy;  
  205.                         } else {  
  206.                             buyancy = bbboyancy;  
  207.                         }  
  208.                     }  
  209.   
  210.                     if (sink) { buyancy = System.Math.Max(buyancy, -3)   sinkForces[index ]; }  
  211.   
  212.                     float damp = rrigidbody.GetPointVelocity (wpos).y;  
  213.   
  214.                     float bbuyancy = buyancy;  
  215.   
  216.                     //interpolate last (int interpolation) frames to smooth out the jerkiness  
  217.                     //interpolation will be used only if the renderer is visible  
  218.                     if(interpolate) {  
  219.                         if(visible) {  
  220.                             prevBoya[k][tick] = buyancy;  
  221.                             bbuyancy=0;  
  222.                             for(int i=0; i<intplt; i ) { bbuyancy  = prevBoya[k][i]; }  
  223.                             bbuyancy *= iF;  
  224.                         }  
  225.                     }  
  226.                     rrigidbody.AddForceAtPosition (-Vector3.up * (bbuyancy   coef * damp), wpos);  
  227.                     k ;  
  228.                 }  
  229.             }  
  230.   
  231.             if(interpolate) { tick ; if(tick==intplt) tick=0; }  
  232.   
  233.             tack ; if (tack == (int)Random.Range(2, 9) ) tack=0;  
  234.             if(tack>9) tack =1;  
  235.   
  236.             //if the boat has high speed do not influence it (choppyness and wind)  
  237.             //if it has lower then fact then influence it depending on the speed .  
  238.             float fact = rrigidbody.velocity.magnitude * 0.02f;  
  239.   
  240.             //this code is quick and dirty  
  241.             if(fact<1) {  
  242.                 float fact2 = 1-fact;  
  243.                 //if the object gets its position affected by the force of the choppy waves. Useful for smaller objects).  
  244.                 if(ChoppynessAffectsPosition) {  
  245.                     if(!cvisible || visible) {  
  246.                         if(ocean.choppy_scale>0) {  
  247.                             if(moreAccurate) {  
  248.                                 if(tack==0) rrigidbody.AddForceAtPosition (-Vector3.left * (ocean.GetChoppyAtLocation2Fast() * ChoppynessFactor*Random.Range(0.5f,1.3f))*fact2, cpos);  
  249.                                 else rrigidbody.AddForceAtPosition (-Vector3.left * (ocean.GetChoppyAtLocation2Fast() * ChoppynessFactor*Random.Range(0.5f,1.3f))*fact2, transform.position);  
  250.                             } else {  
  251.                                 if(tack==0) rrigidbody.AddForceAtPosition (-Vector3.left * (ocean.GetChoppyAtLocationFast() * ChoppynessFactor*Random.Range(0.5f,1.3f))*fact2, cpos);  
  252.                                 else rrigidbody.AddForceAtPosition (-Vector3.left * (ocean.GetChoppyAtLocationFast() * ChoppynessFactor*Random.Range(0.5f,1.3f))*fact2, transform.position);  
  253.                             }  
  254.                         }  
  255.                     }  
  256.                 }  
  257.                 //if the object gets its position affected by the wind. Useful for smaller objects).  
  258.                 if(WindAffectsPosition) {  
  259.                     if(!wvisible || visible) {  
  260.                         if(tack==1) rrigidbody.AddForceAtPosition(new Vector3(ocean.pWindx, 0 , ocean.pWindy) * WindFactor*fact2, cpos);  
  261.                         else rrigidbody.AddForceAtPosition(new Vector3(ocean.pWindx, 0 , ocean.pWindy) * WindFactor*fact2, transform.position);  
  262.                     }  
  263.                 }  
  264.             }  
  265.   
  266.             //the object will slide down a steep wave  
  267.             //modify it to your own needs since it is a quick and dirty method.  
  268.             if(xAngleAddsSliding) {  
  269.                 if(!svisible || visible) {  
  270.                     float xangle = transform.localRotation.eulerAngles.x;  
  271.                     currAngleX = (int)xangle;  
  272.   
  273.                     if(prevAngleX != currAngleX) {  
  274.                           
  275.                         float fangle=0f;  
  276.   
  277.                         if(xangle>270 && xangle<355) {  
  278.                             fangle = (360-xangle)*0.1f;  
  279.                             accel -= fangle* slideFactor; if(accel<-20) accel=-20;  
  280.                             }  
  281.   
  282.                         if(xangle>5 && xangle<90) {  
  283.                             fangle = xangle*0.1f;  
  284.                             accel  = fangle* slideFactor;  if(accel>20) accel=20;  
  285.                         }  
  286.   
  287.                         prevAngleX = currAngleX;  
  288.                     }  
  289.                   
  290.                     if((int)accel!=0) rrigidbody.AddRelativeForce (Vector3.forward * accel, ForceMode.Acceleration);  
  291.                     if(accel>0) { accel-= 0.05f; if(accel<0) accel=0; }  
  292.                     if(accel<0) { accel = 0.05f; if(accel>0) accel=0; }  
  293.                 }  
  294.             }  
  295.   
  296.         }  
  297.     }  
  298.   
  299.   
  300.     public void Sink(bool isActive) { sink = isActive; }  
  301.   
  302.     static float Lerp (float from, float to, float value) {  
  303.         if (value < 0.0f) return from;  
  304.         else if (value > 1.0f) return to;  
  305.         return (to - from) * value   from;  
  306.     }  
  307.   
  308. }  


在Unity编辑器中的表现如下所示:


运行效果如下所示:


效果非常绚丽。。。。。。。。

第四步,除了LOD海水网格渲染外,还提供了整个海水平面的渲染,以及可视化的界面操作,效果如下所示:


在该操作界面中有OceanMaterial材质对应的Shader脚本,在这里就不一一列举了。

第五步,多线程渲染主要是用于初始化海水网格以及算法的计算:

  1. uocean.setThreads(2);  
  2.             if(SystemInfo.processorCount == 1) uocean.setThreads(1);  
  3.             //--------------------------------------------------------------------------------------------------------------------------------------------  
  4.             uocean.UoceanInit(width, height, pWindx, pWindy, speed, waveScale, choppy_scale, size.x, size.y, size.z, waveDistanceFactor);  
  5.             uocean._calcComplex(data, t_x, Time.time, 0, height);  
  6.             uocean._fft1(data);  
  7.             uocean._fft2(t_x);  
  8.             uocean._calcPhase3(data, t_x, vertices, baseHeight, normals, tangents, reflectionRefractionEnabled, canCheckBuoyancyNow, waveScale);  

其他的读者可以通过Demo去查看。

代码链接地址:  http://pan.baidu.com/s/1pK91RYV  密码:xdx6

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引