已阅读5页,还剩5页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Unity 3D 海水的实现2 折射与反射 离屏相机的渲染接下来的目标是实现海水的折射和反射,书中使用的Unity应该是4.x时代的,Unity自带基础包是5.x的,然后我再在网上看了一个例子,看了下来基本原理都差不多。 还记得移动端简单阴影的实现吧,对,就是添加一个相机把照到的玩家传给Shader后,显示在地上,原理是一样的。 首先获取到玩家的相机,新建相机到玩家当前相机,经过一个反射矩阵的旋转后,截取海平面以上的渲染,然后再将渲染出来的Texture传递给Shader处理;折射更加简单,不用矩阵旋转,当前位置的海平面以下渲染出Texture,再传递给Shader。 下面是代码,生成Mesh的代码,我就去掉了:csharp view plain copy 在CODE上查看代码片派生到我的代码片public class Ocean : MonoBehaviour / 一片区域网格横纵数量 public int width = 32; public int height = 32; int g_height; / 组成网格横纵的线条数量 int g_width; Vector2 sizeInv; / 区域的数量和大小 public int tiles = 2; public Vector3 size = new Vector3(150f, 1f, 150f); / 材质 public Material material; public Shader oceanShader; public Transform player; public Transform sun; public Vector4 SunDir; / 网格相关 Vector3 vertices; /顶点 Vector3 normals; /法线 Vector4 tangents; /三角 Mesh baseMesh; / LOD,越在靠后List的Mesh,网格越少 int maxLOD = 4; ListList tiles_LOD; / 折射反射相关 public bool renderReflection = true; /是否启用反射折射 public int renderTexWidth = 128; public int renderTexHeight = 128; RenderTexture reflectionTexture = null; RenderTexture refractionTexture = null; Camera offscreenCam = null; bool reflectionRefractionEnabled = false; /是否初始化完成 / Use this for initialization void Start() / 折射反射 sizeInv = new Vector2(1f / size.x, 1f / size.z); SetupOffscreenRendering(); / 添加离屏相机 if (!renderReflection) EnableReflection(false); else EnableReflection(true); / 计算线条数量 g_height = height + 1; g_width = width + 1; / LOD,Mesh所在的List的LOD List编号越小,Mesh的网格越多 tiles_LOD = new ListList(); for (int LOD = 0; LOD maxLOD; LOD+) tiles_LOD.Add(new List(); for (int y = 0; y tiles; +y) for (int x = 0; x tiles; +x) Debug.Log(创建了一片水); float cy = y - Mathf.Floor(tiles * 0.5f); float cx = x - Mathf.Floor(tiles * 0.5f); / 创建一片水 GameObject tile = new GameObject(WaterTile); / 坐标以当前节点为中心 tile.transform.parent = transform; tile.transform.localPosition = new Vector3(cx * size.x, 0f, cy * size.z); / 添加Mesh渲染组件 tile.AddComponent(); tile.AddComponent().material = material; tile.layer = LayerMask.NameToLayer(Water); tiles_LOD0.Add(tile.GetComponent().mesh); GenerateHeightmap(); / 设置折射反射 void SetupOffscreenRendering() / 创建折射反射图 RecalculateRenderTextures(); / 创建Camera实现离屏渲染 GameObject cam = new GameObject(); = DeepWaterOffscreenCam; cam.transform.parent = transform; offscreenCam = cam.AddComponent(); offscreenCam.clearFlags = CameraClearFlags.Color; offscreenCam.depth = -1; offscreenCam.enabled = false; / 当设置reflection和refraction被禁用的时候,设置lod为1 void EnableReflection(bool isActive) renderReflection = isActive; if (!isActive) / 关闭反射折射,使用波光粼粼的图片替代 material.SetTexture(_Reflection, null); material.SetTexture(_Refraction, null); oceanShader.maximumLOD = 1; else / 启用反射折射 OnDisable(); oceanShader.maximumLOD = 2; RecalculateRenderTextures(); / 重新生成反射折射的缓存图片 void RecalculateRenderTextures() if (renderReflection) reflectionTexture = new RenderTexture(renderTexWidth, renderTexHeight, 0); refractionTexture = new RenderTexture(renderTexWidth, renderTexHeight, 0); reflectionTexture.wrapMode = TextureWrapMode.Clamp; refractionTexture.wrapMode = TextureWrapMode.Clamp; reflectionTexture.isPowerOfTwo = true; refractionTexture.isPowerOfTwo = true; material.SetTexture(_Reflection, reflectionTexture); material.SetTexture(_Refraction, refractionTexture); material.SetVector(_Size, new Vector4(size.x, size.y, size.z, 0f); / 删除反射折射使用的缓存图片 void OnDisable() if (reflectionTexture != null) DestroyImmediate(reflectionTexture); if (refractionTexture != null) DestroyImmediate(refractionTexture); reflectionTexture = null; refractionTexture = null; / 折射反射渲染物体 void RenderObject() if (Camera.current = offscreenCam) return; if (reflectionTexture = null | refractionTexture = null) return; if (renderReflection) RenderReflectionAndRefraction(); public LayerMask renderLayers = -1; / 具体的渲染,使用第二个相机拷贝当前相机的设置 void RenderReflectionAndRefraction() / 获取当前角色身上的主相机 Camera renderCamera = Camera.main; Matrix4x4 originalWorldToCam = renderCamera.worldToCameraMatrix; / 获取世界到相机的矩阵,如果改变了相机的矩阵就不会再根据原Transform渲染,除非调用ResetWorldToCameraMatrix int cullingMask = (1 4) & renderLayers.value; /剪裁Mask,忽略水本身 / 计算反射矩阵 float d = -transform.position.y; Matrix4x4 lection = Matrix4x4.zero; CameraHelper.CalculateReflectionMatrix(ref reflection, new Vector4(0f, 1f, 0f, d); /这里不明白,总是弄出了反射矩阵 / 根据反射矩阵计算离屏相机位置和矩阵 offscreenCam.backgroundColor = RenderSettings.fogColor; offscreenCam.transform.position = reflection.MultiplyPoint(renderCamera.transform.position); /当前相机置换到反射矩阵中 offscreenCam.transform.rotation = renderCamera.transform.rotation; offscreenCam.worldToCameraMatrix = originalWorldToCam * reflection; offscreenCam.cullingMask = cullingMask; /设置剪裁mask offscreenCam.targetTexture = reflectionTexture; /将反射缓存图片添加到离屏相机里,跟之前阴影是一个原理 / 因为反射截取到的图片是翻转的,所以需要设置翻转 GL.SetRevertBackfacing(true); / 获取剪裁平面,transform.position.y是当前海水的高度,最后两个值的正负表示剪裁的方向 Vector4 cameraSpaceClipPlane = CameraHelper.CameraSpacePlane(offscreenCam, new Vector3(0.0f, transform.position.y, 0.0f), Vector3.up, 1.0f); Matrix4x4 projection = renderCjectionMatrix; /获得渲染相机的投影矩阵 Matrix4x4 obliqueProjection = projection; offscreenCam.fieldOfView = renderCamera.fieldOfView; /设置FOV offscreenCam.aspect = renderCamera.aspect; /设置宽高比 CameraHelper.CalculateObliqueMatrix(ref obliqueProjection, cameraSpaceClipPlane); / 开始真正的渲染 offscreenCjectionMatrix = obliqueProjection; if (!renderReflection) offscreenCam.cullingMask = 0; offscreenCam.Render(); GL.SetRevertBackfacing(false); / 折射渲染 offscreenCam.cullingMask = cullingMask; offscreenCam.targetTexture = refractionTexture; obliqueProjection = projection; / 将渲染相机的各个参数设置给离屏相机 offscreenCam.transform.position = renderCamera.transform.position; offscreenCam.transform.rotation = renderCamera.transform.rotation; offscreenCam.worldToCameraMatrix = originalWorldToCam; / 获取剪裁平面,计算投影矩阵 cameraSpaceClipPlane = CameraHelper.CameraSpacePlane(offscreenCam, new Vector3(0.0f, transform.position.y, 0.0f), Vector3.up, -1.0f); CameraHelper.CalculateObliqueMatrix(ref obliqueProjection, cameraSpaceClipPlane); offscreenCjectionMatrix = obliqueProjection; offscreenCam.Render(); offscreenCjectionMatrix = projection; offscreenCam.targetTexture = null; / 初始化Mesh信息,请参考上一节 void GenerateHeightmap() / 这边应该是Update的,但写在Update中会报GUI Window tries to begin rendering while something else has not ished rendering的错误 void OnGUI() / 设置玩家、太阳角度,并更新反射折射,折射反射是根据玩家视角来计算的 if (player = null) player = GameObject.FindGameObjectWithTag(Player).GetComponent(); if (sun != null) SunDir = sun.transform.forward; material.SetVector(_SunDir, SunDir); if (renderReflection) RenderObject(); 然后是CameraHelper的脚本:csharp view plain copy 在CODE上查看代码片派生到我的代码片public class CameraHelper private static float sgn(float a) if (a 0.0f) return 1.0f; if (a 0.0f) return -1.0f; return 0.0f; public static void CalculateObliqueMatrix(ref Matrix4x4 projection, Vector4 clipPlane) Vector4 q = projection.inverse * new Vector4(sgn(clipPlane.x), sgn(clipPlane.y), 1.0f, 1.0f); Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q); projection2 = c.x - projection3; projection6 = c.y - projection7; projection10 = c.z - projection11; projection14 = c.w - projection15; public static Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign) Vector3 offsetPos = pos + normal * 0.02f; Matrix4x4 m = cam.worldToCameraMatrix; Vector3 cpos = m.MultiplyPoint(offsetPos); Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign; return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal); public static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane) reflectionMat.m00 = (1F - 2F * plane0 * plane0); reflectionMat.m01 = (-2F * plane0 * plane1); reflectionMat.m02 = (-2F * plane0 * plane2); reflectionMat.m03 = (-2F * plane0 * plane3); reflectionMat.m10 = (-2F * plane1 * plane0); reflectionMat.m11 = (1F - 2F * plane1 * plane1); reflectionMat.m12 = (-2F * plane1 * plane2); reflectionMat.m13 = (-2F * plane1 * plane3); reflectionMat.m20 = (-2F * plane2 * plan
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 护理风险防范意识培养
- 产后伤口感染预防
- 浙江理工大学科技与艺术学院《纳米材料与纳米技术》2025-2026学年第一学期期末试卷
- 护理质量控制培训
- 场所消防工作手册
- 面试讲座听课笔记
- 腹部减脂话术
- 销售面试实战技巧
- 药物安全与护理实践
- 2026年年度安全工作计划幼儿园5篇
- 国家开放大学2025年秋《思想道德与法治》终考大作业试卷2参考答案
- 河南省青桐鸣大联考2024-2025学年高二上学期12月月考试题生物含解析
- 2025安徽宣城宁国市面向社会招聘社区工作者25人笔试考试参考试题及答案解析
- 2026年出租汽车驾驶员(区域科目)自测试题及答案
- 球队战术讲解课件
- 2025年6月四级真题
- 2026年锦州师范高等专科学校单招职业适应性测试题库必考题
- 2025急性高甘油三酯血症胰腺炎康复期多学科管理共识解读
- 汽车清洁度检测方法
- 安全注射的课件
- 2024糖尿病足治疗指南
评论
0/150
提交评论