一,多個WaterProDaytime不要公用material。
原因是:水面material的shader(FXWaterPro.shader)引用了reflectionTexture,而水面1的reflectionTexture是由水面1的reflectionCamera渲染出來的。水面2的reflectionTexture是由水面2的reflectionCamera渲染出來的。由於水面1的reflectionCamera與水面2的reflectionCamera的觀察方向不同,所以必須用兩個不同的camera,所以得到的reflectionTexture也是不同的,那么如果水面1和水面2的material用同一個,它們的shader引用的reflectionTexture就只能是同一個,這與水面1與水面2的reflectionTexture不同相矛盾,所以水面1和水面2必須用不同的matrial。(用refractionTexture來分析也是一樣)。(如果好奇多個水面使用同一個matrial會發生什么,可以做一下試驗,結果就是當攝像機旋轉到某個角度時水面的reflection和refraction效果會發生奇怪的跳變)。
如果我們要在場景中同時添加兩個Water,正確的做法是:
(1)由WaterProDaytime.prefab創建兩個實例Water1和Water2。
(2)將WaterProDaytime.mat復制出兩個副本,WaterProDaytime1.mat和WaterProDaytime2.mat。
(3)用WaterProDaytime1.mat替換Water1原來的material,用WaterProDaytime2.mat替換Water2原來的material。
同理,即使場景中只放一個Water,也應該將WaterProDaytime.mat復制一個副本替換原來的material,以避免原prefab的material被污染。
二,WaterProDaytime在Orthographic相機上的bug。
對於Orthographic相機,如果water在視截體內且water平面與相機視線平行,unity將報出“Screen position out of view frustum”這個error。報錯行是Water.cs腳本中的reflectionCamera.Render(),但經過分析可以確定是reflectionCamera.projectionMatrix = cam.CalculateObliqueMatrix(clipPlane)這一句導致的,更具體地說是unity的Camera.CalculateObliqueMatrix這個API的實現有bug/對Orthographic相機支持不完善/根本就不支持Orthographic?亦或是Camera.CalculateObliqueMatrix正確完成了自己的計算,但Camera.Render()中對於Camera.CalculateObliqueMatrix的特殊情況下的計算結果沒有作出正確的理解。
Camera.CalculateObliqueMatrix(clipPlane)在文檔中的解釋是:
Calculates and returns oblique near-plane projection matrix.
Given a clip plane vector, this function returns camera's projection matrix which has this clip plane set as its near plane.
(關於obliqueMatrix還可以參考:
http://forum.unity3d.com/threads/problem-camera-calculateobliquematrix.252916/
http://www.terathon.com/code/oblique.html
http://aras-p.info/texts/obliqueortho.html
http://www.terathon.com/lengyel/Lengyel-Oblique.pdf)
也就是說,oblique投影矩陣與普通投影矩陣(透視投影矩陣和正交投影矩陣)的差別是:普通投影矩陣所描述的視截體近平面與錐軸垂直,而oblique投影矩陣所描述的視截體近平面是斜的(與錐軸不垂直)。
如下圖所示,左圖中紅色的是透視投影視截體,右圖中紅色的是oblique投影視截體。由於水面是反射面,所以渲染反射圖象時必須以視截體被水面所截的截面作為視口,即“斜視口”,所以必須將反射相機轉化成oblique投影模式。reflectionCamera.projectionMatrix = cam.CalculateObliqueMatrix(clipPlane)就是干這個事兒。
不過對於一些特殊情況,得不到有限的 斜視口 ,如下兩圖:
上面左圖是透視投影下得不到有限斜視口的例子,右圖是正交投影下得不到斜視口的例子。
不過對WaterProDaytime進行測試我發現在其在透視投影相機下總是不會報error的(至少我沒測到反例),這說明Camera.CalculateObliqueMatrix在透視投影下還是工作良好而且Camera.Render能正確理解Camera.CalculateObliqueMatrix的計算結果。但對於正交投影相機,經過測試,如上面右圖所示,當water與錐軸平行且在h1之下或在h2之上時安全,但在h1和h2之間時會報error。
由於這是unity自已API的問題,完美的解決只能等官方修正。
但work around是有的,就是:
(1)把Water.cs中的
reflectionCamera.Render();
改成:
if(cam是正交投影相機&&視線與本水面平行){
reflectionCamera.Render();
}
(2)把Water.cs中的
refractionCamera.Render();
改成:
if(cam是正交投影相機&&視線與本水面平行){
refractionCamera.Render();
}
三,WaterProDaytime不能在cubemap中反射。
如下圖,其中動態cubemap球體用下面日志中的方法做的:http://www.cnblogs.com/wantnon/p/4480727.html
當球體的Camera_cubeMapRealTime的Culling Mask選為“除Water外所有物體”,效果如下:
但是當球體的Camera_cubeMapRealTime的Culling Mask選為Everything,效果變成:
顯然是不正常的。原因我還不清楚。