1.Unity3D 冲锋效果.角色拖尾效果
2.Unity使用ProfilerRecorder来记录DrawCall等渲染信息
3.Unity PostProcess的最新整理使用
4.Unity开发:tolua升级Lua5.3后编译打包指南
5.关于Unity中的UnityWebRequest
6.不用找,你想要的源源码场景Unity3D模型素材都在这里!
Unity3D 冲锋效果.角色拖尾效果
《魔兽世界》,最新整理本人最喜欢的源源码网络游戏,如果你玩过战士,最新整理你一定对战士的源源码stringvalueof方法源码冲锋非常熟悉,现在接触 Unity3D,最新整理因为最近用到了刀光、源源码拖尾特效,最新整理所以就想做一个类似战士的源源码冲锋效果,在本场景用到的最新整理拖尾效果可以查看我的另一篇文章,里面有详细的源源码介绍,刀光效果来自 Unity3D Assets 商店,最新整理只是源源码把原作者的例子代码整理了一下,变得非常简单实用的最新整理类。
最终效果如下:
先来搭建我们的场景,如图:
然后给角色的模型添加一个空对象,并且加上 MeshRender,并且设置好材质为 WeaponTrail,另外给这个空对象添加 WeaponTrail.cs 对象,设置好相关属性,如图:
下面的代码是修改另一篇文章的 TrailsBladeMaster.cs 类,新的代码如下:
复制代码
代码如下:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[AddComponentMenu("PocketRPG/Blade Master")]
public class TrailsBladeMaster : MonoBehaviour
{
/// summary
/// 拖尾效果
/// /summary
public WeaponTrail weaponSwipe;
public AnimationClip idleClip;
public AnimationClip runClip;
/// summary
/// 移动速度
/// /summary
public float speed = .0f;
public Camera mainCamera;
private Animation animation;
protected TrailsAnimationController animationController;
protected CharacterController characterController;
/// summary
/// 运行状态
/// /summary
private bool isMoving = false;
/// summary
/// 目标位置
/// /summary
private Vector3 targetPosition;
/// summary
/// 移动向量
/// /summary
private Vector3 moveDirection;
protected void Awake ()
{
this.animation = this.GetComponentAnimation ();
this.animationController = this.GetComponentTrailsAnimationController ();
this.characterController = this.GetComponentCharacterController ();
this.animation.CrossFade (this.idleClip.name);
}
protected void Start ()
{
if (this.weaponSwipe != null) this.animationController.AddTrail (this.weaponSwipe);
}
protected void Update ()
{
if (!this.isMoving Input.GetMouseButtonDown(0))
{
this.targetPosition = this.GetWorldPosition();
if(this.targetPosition != Vector3.zero)
{
this.isMoving = true;
this.moveDirection = (this.targetPosition - this.transform.position).normalized * this.speed;
this.transform.rotation = Quaternion.LookRotation(new Vector3(this.moveDirection.x, 0f, this.moveDirection.z));
this.animation.CrossFade(this.runClip.name);
if(this.weaponSwipe != null) this.weaponSwipe.StartTrail(1f, 0f);
}
}
if (this.isMoving)
{
if(!this.IsArrivePosition())
{
this.characterController.Move(this.moveDirection * Time.deltaTime);
}
else
{
this.animation.CrossFade(this.idleClip.name);
if(this.weaponSwipe != null) this.weaponSwipe.ClearTrail();
this.transform.position = this.targetPosition;
this.isMoving = false;
}
}
}
/// summary
/// 验证是否到达目标地点
/// /summary
/// returnsctrue/c if this instance is arrive position; otherwise, cfalse/c./returns
private bool IsArrivePosition()
{
Vector3 currentDirection = (this.targetPosition - this.transform.position).normalized;
if (this.CalculateNormalized (currentDirection) == this.CalculateNormalized (this.moveDirection) * -1)
{
return true;
}
return false;
}
/// summary
/// 规范化比较向量
/// /summary
/// returnsThe normalized./returns
/// param name="direction"Direction./param
private Vector3 CalculateNormalized(Vector3 direction)
{
Vector3 value = Vector3.zero;
value.x = direction.x 0 ? 1 : -1;
value.z = direction.z 0 ? 1 : -1;
return value;
}
/// summary
/// 获取世界位置
/// /summary
/// returnsThe world position./returns
private Vector3 GetWorldPosition()
{
Ray ray = this.mainCamera.ScreenPointToRay(Input.mousePosition);
RaycastHit raycastHit;
if(Physics.Raycast(ray, out raycastHit))
{
if(raycastHit.collider.gameObject.name == "Terrain")
{
return raycastHit.point;
}
}
return Vector3.zero;
}
}
最后给角色对象挂载 TrailsAnimationController.cs 组件以及 TrailsBladeMaster.cs 组件,同时还需要添加一个角色控制器(CharacterController),因为我们用这个来驱动角色移动,如图:
最后运行可以查看效果,点击地形,角色向目标点移动,并带有拖尾效果。
百度网盘下载地下:/s/1hqeiREO 密码: tj
Unity使用ProfilerRecorder来记录DrawCall等渲染信息
在探索Unity中用于记录渲染信息的工具时,我发现中文互联网上似乎缺乏相应的教程,大部分信息来自英文网站。因此,我整理了以下代码片段,希望对各位开发者有所帮助。
为了记录特定的渲染信息,如“Draw Calls Count”,我们需创建对应的ProfilerRecorder。每个记录器对应一种信息类型,字符串与记录内容一一对应,代码中并未列出全部关系。在记录信息时,使用BeginSample方法开始,EndSample方法结束。
记录完成后,获取结果的代码也相当直观。这涉及到调用特定的API,从Unity内部获取记录数据并进行解析或展示。在进行项目分析和优化时,这些记录数据显得尤为重要。
Unity PostProcess的使用
终于完成了在移动平台下使用Unity引擎开发游戏项目的效果向的三个总结,包括光照、线性空间、后期处理。掌握了这些知识点可以更好地帮助项目实现更好的美术效果、制定技术规范、优化制作流程。 关于光照的文档详细介绍了Unity移动平台下的光照烘焙及优化,以及如何从Gamma转Linear颜色空间的经验分享。 本文将聚焦于Unity的后期处理效果的使用,主要从Unity官方文档及Unreal Engine的参考资料中整理资料。概述了在项目中应用后处理效果的整体规划。官方文档
Post Process是基于屏幕的后期处理技术,通过在缓冲区中应用滤镜和效果,然后再显示出来,棋牌源码博客以模拟物理摄像机和**特效。安装
对于Unity .1及更高版本,可通过Package Manager安装和更新PostProcessing。对于低于Unity 但高于Unity .1的版本,可从GitHub下载并放置在Assts目录下使用。 当前版本为Post-processing v2,适用于Build-in Render Pipeline和LWRP,HDRP则不需要从package安装,有更高级的解决方案。基本使用
通过挂载Post Process Layer脚本在Camera上或空物体上,并通过Trigger控制Camera应用后期效果。Layer用于管理Post Process Volume。 对Post Process Volume设置Layer,仅当Layer处于激活状态时,指定的后期效果才会生效。HDRP内置Post-process,无需Layer,直接通过Volume System控制。 Anti-aliasing(抗锯齿)移到了Camera上管理。Anti-aliasing
Anti-aliasing是一种通过图像处理方式减少锯齿效果的算法,不依赖硬件设备。Dithering
Dithering使用8-bit dithering像素点抖动技术来消除色阶问题。NaNs
NaNs自动使用黑色像素替换Shader中的NaN(非法操作)或Inf(浮点值溢出或除0),对性能有轻微影响,仅在遇到不能解决的NaN问题时使用。Post Process Volume
通过添加Post-process Volume组件到GameObject来控制后期效果区域。在HDRP中,Volume脚本用于管理后期效果。 主要参数包括:是否全局使用、混合多个Volume的权重值、优先级、后期效果配置文件等。Post Process Profile
在Project窗口创建Post-processing Profile来定义后期效果的配置文件。HDRP使用Volume Profile。 Volume统一管理后期、环境设置、光照设置、自定义功能等,对应的Profile功能更细,可针对项目制定使用规范。 通过Add Effect / Add Override添加后期效果。Effects
Ambient Occlusion
Unity引擎的两种AO方案,以Unreal Engine的效果示例进行对比。Auto Exposure
Auto Exposure调整图像亮度范围,通过直方图调整找到平均亮度值。 主要参数包括:直方图范围、平均亮度最小值、最大值、曝光值理解、曝光补偿值、曝光调整速度等。Bloom
Bloom效果从图像的明亮区域扩散柔光,要求支持Shader Model 3。 性能影响参数包括:扩散程度、变形比例、快模式。降低Diffusion值可减少性能开销,Anamorphic Ratio的绝对值越小,性能开销越小。在移动平台或低端设备上开启Fast Mode以减少性能开销。Chromatic Aberration
模拟相机镜头的颜色偏移,要求支持Shader Model 3。 性能影响参数包括:强度、快模式。pgp java 源码Intensity值越大,采样的次数越多,对性能影响越大。开启Fast Mode可减少性能开销,但效果不那么平滑。Color Grading
后期校色调整画面色调,Unity引擎提供三种方案。 主要参数包括:中性映射、ACES调色、自定义设置。自定义设置调整曲线,如Tone Strength、Shoulder Strength等。Depth of Field
模拟相机变焦镜头的效果,要求支持Depth texture和Shader Model 3.5。 主要参数包括:焦距、光圈、焦距长度、最大模糊大小等。Grain
颗粒效果模拟相机胶片中的颗粒感,要求支持Shader Model 3。 主要参数包括:带颜色的噪点、强度、颗粒大小、亮度贡献值。Lens Distortion
模拟镜头扭曲效果,要求支持Shader Model 3。 主要参数包括:扭曲强度、X轴影响、Y轴影响、中心位置、缩放等。Motion Blur
运动模糊效果,要求支持Motion vectors、Depth texture、Shader Model 3。 主要参数包括:旋转快门角度、采样点数量。Screen Space Reflections
屏幕空间反射效果,模拟表面反射,要求支持Compute shader、Motion vectors、Deferred rendering path、Shader Model 5.0。 主要参数包括:预设质量、最大迭代次数、厚度、分辨率、最大追踪距离、衰减距离、暗角等。Vignette
暗角效果将画面边缘压暗,要求支持Shader Model 3。 主要参数包括:暗角颜色、中心点、强度、平滑度、圆度、圆形勾选。Camera Physical Settings
Camera物理属性模拟真实相机,包括光圈、快门、感光度等参数。 主要参数包括:传感器类型、微小网源码尺寸、ISO、快门速度、Gate Fit、焦距、光圈、镜头偏移等。后期效果在项目中的使用
在项目中使用后期效果时,需制定规范,包括Volume、Profile、效果使用和优化方案。以Unity Build-in渲染管线为例,简述项目中后期效果的整体应用。 确定项目中一定需要使用的后期效果,规划每个效果的使用场景,确保整体效果的统一和优化。 通过在MainCamera上挂载Post Process Layer或Volume组件控制场景整体和单个场景的后期效果。全局和局部控制后期效果的开关,以及参数调整。 单个场景中的后期效果通过Prefab和Profile文件管理,确保主效果优先,避免重叠。 整合UI界面来接入后期效果的控制,并理顺与参数调节之间的逻辑关系。 综上所述,掌握Unity的后期处理技术,结合项目需求制定规范,可以显著提升美术效果和优化制作流程,为游戏项目带来更出色的表现。Unity开发:tolua升级Lua5.3后编译打包指南
一、源起
老项目使用tolua,因新增需求支持int,升级至lua5.3。打包过程中遇到多平台问题,特别关注了Android和Mac平台。文章旨在整理打包过程中遇到的坑点,以及不同平台打包时的环境配置和关键资源。
打包环境采用msys2,模拟Linux环境,使用.sh脚本完成打包流程。重点关注msys2版本调整,需使用android ndk re版本进行编译。
二、打包环境安装
1、msys2安装与环境配置
下载msys2,选择对应系统版本进行安装。安装完成后在msys文件夹中找到mingw.exe和mingw.exe,它们分别用于处理位和位库编译。需注意不同位数的库会自动放置在相应的文件夹中。安装gcc和make使用pacman指令进行,确保所有依赖包均已安装。
三、各平台打包
1、Windows DLL
使用vs项目直接编译,或通过.sh文件和makefile进行编译配置。确保makefile设置正确,必要时可调整文件内容。
2、Android arm和arm
依赖jni/Android.mk文件进行编译,生成的文件主要位于obj文件夹内。编译脚本需cd至jni目录下执行,确保mk文件中的目录与文件路径正确。
3、linux发行源码iOS
通过xcodeproj文件进行编译。对于mac用户,需注意以下坑点:
I、 修改Loslib.c和Pbc-lua.c文件,确保代码兼容。
II、 遇到Xcode路径错误时,使用指定路径调用xcodebuild命令。
III、 .bash_profile文件配置确保环境变量正确设置。
IV、 处理文件系统不兼容问题,确保.sh文件在mac下正确编译。
V、 避免使用svn管理build文件夹,防止关键文件被意外删除。
关于Unity中的UnityWebRequest
HTTP Webrequest unity:
Unity中的UnityWebRequest是一款功能强大的API,用于开发者与Web服务和API进行交互。
无论是下载数据、发送HTTP请求还是上传内容,UnityWebRequest都提供了一种灵活且功能丰富的解决方案。
近期项目中有涉及,整理并留存UnityWebRequest基础知识及其各种组件的使用方法。
UnityWebRequest基础知识:
Unity中的UnityWebRequest是处理HTTP请求的内置系统,支持各种HTTP方法如GET、POST、PUT、DELETE等,与Web服务器和服务通信。
1. 创建一个简单的GET请求:
示例:向一个URL发出GET请求。
在协程中通过UnityWebRequest创建请求,并使用SendWebRequest发送请求,等待完成。
笔记:C#中的using语句确保资源正确清理,不再需要时释放其关联资源。它将创建和实现IDisposable的对象代码封装在try-finally块中,即使发生异常,Dispose方法仍将被调用。
此行声明一个名为www的UnityWebRequest对象,使用对特定URL的GET请求初始化它。using语句确保当括号内的块退出时调用www的Dispose方法。
2. 处理POST请求:
UnityWebRequest允许在POST请求中发送数据。
3. 下载处理:
UnityWebRequest使用DownloadHandler来管理下载内容,默认为DownloadHandlerBuffer,也可使用其他值,如DownloadHandlerTexture用于图像。
DownloadHandlerTexture检索下载的纹理,并将其存储在texture变量中。
4. 上传处理:
上传数据时,UnityWebRequest利用UploadHandler来管理发送的内容。
通过Encoding.UTF8.GetBytes将字符串转换为byte数组,再通过UnityWebRequest创建访问定向URL的POST请求发送。
将上传处理程序分配给UnityWebRequest对象。
不用找,你想要的场景Unity3D模型素材都在这里!
在寻找Unity3D模型素材的道路上,我偶然发现了一个宝藏网站。这个网站不仅资源丰富,而且质量上乘,成为了我日常工作的得力助手。它的界面设计简洁明了,提供从场景Unity3D模型到各种其他类型资源,堪称一个全品类的素材库。有了它,就像是拥有了一个百宝箱,满足了我对各种素材的需求。
我整理了一份Unity3D模型-场景Unity3D模型合集,希望能帮助大家更快地找到所需资源。只需按照以下步骤操作:
搜索爱给网或访问aigei点com,进入网站后,点击“游戏”-“Unity3D”-“Unity3D模型”,然后在分类中选择“场景”,即可找到丰富的资源。
以下是我收集的一些场景Unity3D模型,希望能激发您的灵感,探索更多其他资源:
1. 现代城市建筑模型(Big City 1.0 unity)
2. 卡通风格的森林、沙漠、岛屿和雪地场景(Lowpoly Style Ultra Pack 1.2)
3. 四季自然场景模型(AZURE Nature 1.1.1)
4. 科技感十足的未来城市模型(Dark City2-Cyberpunk Pack 1.2)
5. 医院和实验室的室内场景(Hospital Laboratory 1.0)
6. 工厂工业厂房的3D游戏场景资源
7. 武侠类游戏中的山水亭台场景
8. 日本学校教室的室内场景(Japanese School Classroom 2.0)
9. 现实主义风格的森林场景模型(Realistic Forest Pack 0.1 unity3d)
. 唯美的森林山谷草地场景(Unity3D唯美森林山谷草地场景风景自然环境花草树木石头灌木u3d模型)
. 低边形风格的室内场景(Easily Interiors Full Packs VR AR low-poly 3d mode)
. 高质量的日本街道小巷子场景模型(Unity3D Japanese Street 1.2)
. 扁平风格的卡通模块拼搭梦幻场景(Isometric Pack 3d 1. unity3d)
以上就是我今天分享的资源集合,希望它们能为您的项目注入新鲜的创意元素。如果您觉得这份分享对您有所帮助,不妨点赞支持一下,让我们共享这份宝贵的创作经验吧!
Unity 关于安卓和各平台读写本地json文件,WWW读取本地文件,Unity各路径API目前较完整的详解
关键点:
使用C# API和Unity API读写本地json文件
Unity API包括JsonUtility.fromjson和JsonUtility.tojson,以及WWW方法
UnityAPI提供的路径参考:
Application.dataPath, Application.streamingAssetsPath, Application.persistentDataPath
txt格式的json文本文件,编码(UTF-8、Unicode、Ascii),Bom字符问题
研究背景:在安卓游戏应用中读取和写入本地json文件,如武器信息、人物属性、得分结算。通过研究和实践,整理出Unity下不同平台读写本地json文件的方法。
教程使用的是windows系统,安卓真机测试,Mac/Linux/IOS未测试。
使用Unity自带API,无需额外插件,JsonUtility类方便进行json操作。
JsonUtility.fromjson将json字符串转换为对象,JsonUtility.tojson将对象转换为json字符串。
在编辑器模式下,使用StreamReader和StreamWriter读写本地文件,Unity的WWW方法用于从网络下载文件。
注意不同平台路径差异,如Resources、StreamingAssets、persistentDataPath。
Resources文件夹用于资源管理,加载资源、模型,可以使用Resources.Load方法。
StreamingAssets文件夹存储资源,只读不写,路径在不同平台有所变化。
Application.persistentDataPath用于保存运行时数据,支持读写。
使用示例代码展示不同文件夹的路径和读写操作。
说明Bom字符问题,Windows默认在txt文件开头添加Bom字符,影响json解析。
解决方法:使用StreamReader时需要忽略Bom字符,或者在读取json字符串前移除Bom字符。
总结,通过详细介绍Unity下的json文件读写方法,提供不同文件夹的路径和解决Bom字符问题的策略,帮助开发者在不同平台下顺利完成json文件操作。
Unity3d FootIK写一个最简单的IK(1)
前言:
历经无数次尝试与调整,终于找到了在Unity环境中实现FootIK的基本方法。整个过程虽然充满了挑战,但学习到的知识与技巧却让我感到收获满满。
预备设置:
为了使用Unity内部的IK系统,我们需要进行以下步骤的设置。
1. 为FBX模型设置Humanoid Avatar,确保在Avatar设置界面中正确绑定骨骼。
2. 创建并配置AnimatorController,激活特定层级的IK Pass功能。
3. 编写脚本,声明OnAnimatorIK方法,用于处理IK解算。
创建FootIK脚本:
1. 定义脚本中的变量,这些变量将用于后续算法的执行。
2. 在FixedUpdate函数中获取骨骼信息,计算IK位置。
3. 编写AdjustFeetTarget方法,获取脚部Transform的位置,并进行调整以避免模型穿模。
4. 实现FootPositionSolver方法,使用Raycast检测地面位置,计算旋转角度。
动画曲线设置:
在动画中,脚部抬离地面时,需通过动画曲线调整IK目标的权重。通过在FBX Inspector中配置动画曲线,根据动画片段的不同阶段,设置合适的权重值,以实现脚部自然抬起与落地的效果。确保在Animator面板中正确添加Float参数,以便在播放动画时动态调整。
实践与原理:
1. 整理脚本并将其应用到角色GameObject上,激活IK功能,通过设置目标层级,使角色能够在阶梯上自然行走。
2. 讲解算法原理与流程,包括使用简单射线检测计算IK位置,以及在OnAnimatorIK方法中,通过动画曲线动态调整权重,影响骨骼位置。
揭秘Unity IK本质:
深入理解MoveFeetToIkPoint方法的工作原理,包括transform坐标变换、Animator的Getter与Setter机制。发现IK Goal实际上包含了与地面的偏移信息,并通过yVar变量进行动态调整,确保角色脚部贴合地面,防止穿模。了解Unity内部动画计算流程与IK应用顺序,揭示了为何增量赋值能有效控制角色行走。
小结:
通过解析Unity内置的IK系统,对功能插件的原理有了更深入的理解。展望未来,希望能够探索更多高级的IK实现方法,如Final IK与AnimationRigging,进一步提升角色动画效果。同时,源代码的分享将为社区开发者提供参考与灵感,促进Unity生态的共同进步。
Unity URP RayMarching 体积云
最近在unity中简单尝试了体积云的渲染,在这整理分享一下,如果有什么错误和建议还请大佬不要留有情面...
这是当前的一个效果(因为视频压缩啥的会比较糊, 在b站上传了个高清的),一共使用了3种构建云的方式
他们的性能消耗也是从上到下依次减小,如果你是初次接触体积云这东西,极有可能不知道我在说什么,但是莫慌,本文将通俗的讲解体积云是什么,如何创建他,如何优化(慌也莫用...)
后两种方式也打包到我的爪机上跑了跑,爪机是小米ultar,发布分辨率是*,云采用降半分辨率、分4帧进行渲染,帧率显示在左上角。可能会因为各种压缩导致画面比较胡,打包后的apk和工程放到了文章的最后面
构建云的几种方式:
在渲染一些普通物体时,一般我们都是通过3D软件进行建模,然后随手丢进引擎里进行渲染。但对于云这种边界模糊、可流动、可穿透的特殊物体显然就需要特殊对待他。针对云的渲染方式也是多种多样,主要是兼顾效果、性能、交互等方面,下面简单介绍几种
1. 公告牌云:这种云效果好、性能高,而且后续也可以做很多骚操作(例如云的交互、衔接天气系统等),缺点就是目前无法做到在云中穿梭的效果,效果会比较扁。详细可以看 杨超大佬的文章 公告牌云(billboard cloud)动态光照(三)
2. 面片穿插云:优点就是可以穿梭、实现简单,但某些视角会有穿帮,如果想要效果好需要多穿插面片,但是会产生大量的overdraw,当然也有一些优化方式。详细可以看 Marcus Xie大佬的 手游体积云:完全程序化生成,可穿越,The Witness ( artofluis.com/3d-work/t...)
3. 视差云:基于视差进行的云渲染,在视角移动时可以看到云的体积感,也是不能在云中穿梭,适合做山下的云海那种感觉,要想效果好需要多次迭代,在性能和效果上进行取舍。详细可以看 迎叔大佬的 Unity Shader基于视差映射的云海效果,视差的一些教程可以看 LearnOpenGL的教程讲的非常好
4. 模型云:有两种实现方式一种是模型沿法线外扩多层渲染、另一种是通过曲面细分,本质都是增加模型表面细节。可以做到比较风格化的效果,而且定义云的形状也非常的简单方便,缺点也是不能在云中穿梭,需要添加碰撞器避免角色进去造成穿帮。详细参考 WalkingFat大佬的 Bump Noise Cloud – 3D噪点+GPU instancing制作基于模型的体积云, 基于Tessellation的体积云
5. 天空盒:大家都懂的不必多说...(不会告诉你们是用来凑数的)
6. RayMarching体积云:这是目前我感觉最科学的渲染方式了,他的上限非常的高,可以对真实的云进行模拟,当然性能消耗也是无所匹敌的,其中也有很多优化方式,最后也是可以压缩在爪机上运行的(参考上面的视频),不过会有一些限制和效果的取舍。想要做好的话还是个人感觉还是有那么一点点小难度,如果考虑实际落地、教导美术使用、优化制作流程等可能就是两点点了。话不多说接下来就简单介绍下这个该怎么玩
如何渲染云:
在开始介绍RayMarching前,我们不妨思考对云这种特殊的物体如何进行渲染。其实非常简单,就和普通的物体渲染一样只需要分两步!
对没错就是如此的简单,剩下的就是对这两个步骤进行实现,以及后期的优化
1. 计算云的形状:我们是使用屏幕空间的绘制方式(也就和那些后处理一样),我们需要计算屏幕上每个像素云的密度(得到的就是云形状),简单来说就是这样的
为了更直观的介绍,在这里转到侧面
红线是我们每个像素的观察方向,从上图可以更直观的看到我们每个像素中云的密度(观察方向穿过云密度的总和),现在我们拿出其中一个像素来介绍如何计算密度
这其实就是数学中的积分了,这里就简单的说明一下。我们想要计算当前射线穿过云的总密度,我们可以对这射线进行区间划分,划分成[公式] 、 [公式] 、 [公式] 、....这几个区间,区间的间隔(也就是长度)为 [公式] 。这样我们当前射线的总密度就是 [公式] ,对于单个区间密度的计算就是 [公式] , [公式] 是当前区间末尾点的密度。其他的参数我们都知道了,但是指定点的密度 [公式] 我们该怎么获得呢?最简单、通用、直观的方式就是采样3D纹理。
3D纹理可以简单的理解为是一堆2D纹理叠起来的,他使用一个三维坐标(xyz)进行采样,关于3D纹理的创建我们会在后面说明。这样我们在获取指定点的密度[公式] 时,就可以直接用该点的世界坐标对3D纹理进行采样来获得。可以看到如果我们想要定义云的形状就需要制定相应的3D纹理。缩短区间的间隔(增加区间数)就可以更精准的逼近云的形状,但是消耗也会上去(增加了采样次数)。
说了这么半天那么何为RayMarching呢,RayMarching翻译为光线步进,就是光线随着观察方向一步步向前走,看上面在我们计算密度时,位置从起始点[公式] 开始,向观察方向步进(前进) [公式] 个长度,得到了第一个采样点,然后使用这个采样点的世界坐标对3D纹理采样,获取该点的密度 [公式] ,乘上刚才步进的距离 [公式] ,获得刚才步进区域的密度 [公式] ,之后在向观察方向步进....以此类推,伪代码是这样的
这是一个非常暴力简单的算法,可以看到我们是从起始点[公式] 开始步进的,其中[公式] 、 [公式] 、 [公式] 、 [公式] ...密度都是0,不是还没到云,就是早就穿过云了。这时的计算就是没有意义,而且还会消耗非常多的性能,这时候就是神奇的包围盒出场了
我们可以通过观察方向与指定的一个包围盒进行求交计算,获得起始点与结束点的位置。下面是射线与AABB(轴对齐包围盒)的求交计算
通过传入包围盒边界最小坐标和最大坐标,以及射线的起始位置和方向。该函数可以返回从射线起点到包围盒最近的距离,以及射线穿过包围盒的距离。有时间在写一下这个推到过程把...
这时候我们在进行RayMarching时就可以直接从起始点[公式] 开始进行步进,当穿过包围盒时直接结束计算就可以了,下面是伪代码
计算密度先到这里,接下来我们看如何计算云的光照
在真实生活中,当光线进入云层中会被云层中的粒子或水滴吸收一部分,然后在被散射到其他方向,接着又被其他粒子或水滴吸收和散射,直到光线被吸收没或者穿出云层,当穿出云层的方向刚好是我们的视角方向时,我们人眼将会捕获到这个亮度,就是我们最后看到云受光照的样子。
我们主要对以下3个效果进行分析模拟:
1. 吸收:大家都懂就不必多说了,这里主要说下方向散射(被分为向前散射和向后散射)、外散射、内散射
这些本质都是散射为啥会有这么多名字呢,其实就是对散射的方向进行的一些分类,以便更好的分析光在云中的复杂反应。可以看上图当光线进入云层时,会被云层中的粒子吸收一部分能量,然后会反弹到各个方向上继续前进,这个被称为散射。然后针对于这个散射的方向我们就有了上面几个分类。
2. 方向散射概率:了解了这些散射之后我们来看看第一个效果。因为在逆光时,光线在云中散射的方向大部分都是朝向人眼的,而且在云比较薄的地方会比较快的穿出云层,减少了被吸收、外散射的概率,所以会使得边缘会形成一个亮边。为了描述这种现象,就到了我们抄公式的时候了!Henyey-Greenstein相位函数!!!
[公式]
[公式] 是光照方向与观察方向大夹角, [公式] 其实就是 [公式] , [公式] 是离心率。该函数的数学图像如下
调整离心率就可以改变散射的概率,gif有点糊,感兴趣的可以去Desmos上画画(注意使用极坐标)。这是单散射的,一般我们会混合两个这样的函数,调整向后散射。
3. 吸收和外散射概率:这个也很容易理解,因为光线被吸收或外散射,从而导致光线的衰减,云层越厚被吸收和外散射的越多。我们同样也有一个公式来描述他,那就是Beer定律!!!
他通过给定一个光学厚度(密度)来计算出透射率。
4. 内散射概率:还有一种效果,当我们顺着太阳光观看厚云层时,可以明显的看到云上的暗边,以及折痕地方更亮的效果(有点像花椰菜...)。这种效果也被称为糖粉效应,因为在一堆糖粉中也可以看到这种效果...
因为散射的关系,一部分光线会产生°转弯从而到达我们的人眼中,在加上光在云中主要是以向前散射为主,所以需要比较大的距离(比较厚的云)才能完成这个转向,导致在厚的云层中看的更加明显。那为什么在折痕出会更加明亮呢?
看上图,[公式] 、 [公式] 在云中具有相同的深度,但是 [公式] 在云的更里面,拥有更高的概率内散射,所以折痕处会更加亮一些
<p