Papalqi published on 2020-09-30 included in 物理 虚幻引擎4使用 PhysX 3.3 物理引擎来模拟物理效果。所有物理运动(坠落或受力的物理形体)以及碰撞(物理形体的相互作用)都由 PhysX 管理。
一.Physx 1.1Physx简介 UE4.21前的版本采用的是NVIDIA的PhysX做为其默认的物理引擎,用于计算3D世界的碰撞查询与物理模拟。自4.21版本开始重构了代码调用,兼容使用Chaos物理系统,4.26才会实装,如要使用的话是需要自己构建的。
由于Epic 和NVIDIA的PY交易。Epic为UE4开发者们提供PhysX 3.3.3的基于CPU实现的二进制代码访问权,而且还包括其C++源代码访问权,以及布料库和可破坏物体库。 现在除了可以获得虚幻引擎4的完整C++源代码外,还可以查看和修改此PhysX代码。
参见:https://ue4community.wiki/legacy/physx-integrating-physx-code-into-your-project-ryzw4tj3
Physx文档:https://gameworksdocs.nvidia.com/PhysX/3.3/PhysXGuide/Index.html
1.1.1使用debug 模式检测物理 UE4 使用NVIDIA 的PhysX 3.3物理引擎来模拟物理效果,使用 APEX 模拟 destruction 和 clothing。对于PhyX,它对于UE4来说就是一个提供输入然后获取输出的黑 盒,不过可以通过NVIDIA提供的PhysX Visual Debugger(PVD)来进行可视化调试在编辑器运行游戏 输入pvd connect我们就可以得到实时的物理调试结果。
整个debug软件是比较重的,功能众多,如果大家在项目中遇到了一下物理上的性能问题,强烈建议可以打开pvd看下场景里的动态rigidbody情况,碰撞穿插解算的复杂度,一般严重的性能问题都是在这方面的。
1.1.2基本数据结构 PxPhysics:用来创建Physx各种实用组件,像场景,Shape,Rigidbody,布料,粒子系统等。 PxScene:物理场景,是碰撞盒组件的模拟环境,它的创建是根据PxSceneDesc属性来的。一个大型系统可以有多个场景,不同场景的组件相互不影响,比如UE4,使用了2个场景,用来模拟同步和异步的物理模拟功能。 PxSceneDesc:有如下属性: gravity 重力大小和方向, PxSimulationEventCallback 模拟事件回调, PxContactModifyCallback 碰撞解算修改回调, PxCCDContactModifyCallback CCD的碰撞解算修改回调, filterShader 全局的碰撞分类处理函数, cpuDispatcher Cpu线程分配器 PxCooking:碰撞盒得有形状,我们知道物理引擎里碰撞盒不仅仅是只有胶囊体,长方形,球形,还有凸包体,复杂的静态地表碰撞盒,三角形面片构成的碰撞盒。对于比较复杂的碰撞盒,Phyx支持用PxCooking类接受面片数据,然后create出可以使用的碰撞mesh。 Rigidbody: 它首先是Actor,作为Scene的基础实体,然后可以分成静态的和动态的,静态的如房子,各种场景部件,有自带的预处理功能,处理碰撞等运算性能高很多,动态的像人,车,可以运动,但性能会差一些,动态Rigidbody里用的比较多的是PxRigidDynamic,而Articulation是专门给类似布娃娃这样的系统设计的。
PxShape:SimulationFilterData 这个是做碰撞模拟类别划分的,这边设定好SimulationFilterData,在场景下的filterShader进行区分,可以控制哪些碰撞shape之间是可以相互进行碰撞计算的。 PxMaterial:DynamicFriction,StaticFriction动摩擦,静摩擦,Restitution弹性系数,FrictionCombineMode 摩擦力计算的方式,比如两个物体碰撞了,摩擦力双方不同,可以选择取最小的,最大的,或者平均一下,RestitutionCombineMode,弹力计算模式,摩擦力的一样。 1.1.3几何体 UE4 里面使用的几何体完全匹配于Physx的类型。
球 胶囊体 box 平面 凸包 三角形Mesh 需要注意的问题是,凸包的在Physx里面限定的个数是255.
1.1.3.1Cooking 对于凸包和三角Mesh 的来说,将会发生Cooking。这是PhysX提供的一种转换、序列化批量数据的一种方式。这是一种对于凸包和Mesh 的预处理。Physx需要将你提供的凸包和三角形变成他们自己的结构去加速他们自己的计算。
在UE4中,有复杂碰撞和简单碰撞的区别,复杂碰撞仅仅指的是将整个的Mesh传入的形式,而凸包依旧属于简单碰撞。
大致从UE4.25开始,虚幻引擎开始逐步将Shader交叉编译器从HLSLCC(基于Mesa3d的方案)替换为DXC(Shader Conductor)
为什么说DXC是未来?
HLSLCC停止维护 & 输出Shader可读性差
DXC 优化Pass提升性能(减少寄存器等) 移动平台使用下面的工具链进行交叉编译:
HLSL源码经过mcpp,填充UnfiormStruct数据,并将引用的HLSL代码合并为单HLSL文件
DXC(DirectX Shader Compiler)将HLSL编译为 SPIRV格式
SPIRV经过 SPIRV-OPT 进行优化(Performance 、Code Size)
SPIRV经过 SPIRV-Cross 交叉编译为 ESSL、MSL 源码 虚幻引擎 着色器交叉编译 - 腾讯游戏知识库 - KM平台
Opengl ES 编译 与OpenGL ES中的其他调用相比,编译和链接着色器是一个耗时的过程。它的代价较高。建议在初始化过程中加载和编译着色器,然后在渲染阶段通过调用glUseProgram根据需要在着色器之间进行切换。
对于OpenGL ES 2.0、ES 3.0和ES 3.1上下文,建议使用二进制大对象(blob)。在编译并链接程序对象后,可以使用以下其中之一的函数检索二进制表示或blob:
使用glGetProgramBinaryOES,如果在OpenGL ES 2.0上下文中,且GL_OES_get_program_binary扩展可用 使用glGetProgramBinary,如果在OpenGL ES 3.0或3.1上下文中(核心功能). 然后可以将blob保存到持久存储器中。下次启动应用程序时,无需重新编译和链接着色器。相反,直接从持久存储器中读取blob,并使用glProgramBinaryOES或glProgramBinary将其加载到程序对象中。这可以显著加快应用程序启动时间。
Papalqi published on 2020-03-12 included in 渲染 什么是RDG 渲染依赖性图表(Rendering Dependency Graph) 也被称为RDG或渲染图表,是一个基于图表的调度系统,用于执行渲染管线的整帧优化。它利用DirectX12这样的现代API,使用自动异步计算调度以及更高效的内存管理和屏障管理来提高性能。
RDG的概念如下:在GPU上并非立即执行通道,而是延迟到整个帧已记录到依赖性图表数据结构之中后再执行。当完成了对所有通道的收集之后,则按照依赖性的排序顺序对图表进行编译和执行。这主要是因为DirectX 12、Vulkan和Metal2之类的现代图形API选择将低级GPU管理的负担转移至应用程序本身。这提供了一个机会,可以利用渲染管线的高级情境来驱动调度,从而提高性能并且简化渲染堆栈。
我们今天的RDG有什么好处,就要看之前的方式有多菜。来看一下传统的下图分别是07年和17年的渲染系统的复杂程度
可以参考:
http://www.frostbite.com/2007/04/frostbite-rendering-architecture-and-real-time-procedural-shading-texturing-techniques
为什么需要RDG 这里当然不是非常的具体,不过我们都能看出这里非常的复杂。
当然,我们可以进行一些简单的简化,如下图
战地四的pass数(Feature)
面临的挑战:
显示的代码驱动的即时渲染模式 显示的资源管理 手动的ESRAM管理 每一个不同的游戏团队有着不同的实现方式 不同的渲染系统有紧密的耦合性 对于管线定制的扩展性差 游戏团队必须对这些定制fork/diverge 代码数飞速增长,将产生很多重复性的代码 所以,我们需要将整个的渲染结构进行一个更高层次的抽象,让其拥有更高的扩展性,模块化,更好的可视化和debug,资源的自动管理,解耦模块并使其可自由组合。
这就是新的结构:
RDG设计理念 我们将抛弃即时的渲染模式;将渲染代码分离到pass中,大致分为三个阶段
1.Setup phase 2.Compile phase 3.Execute phase
Setup phase 我们将定义这个pass是一个render pass, 还是compute pass我们将定义每一个resource,对于输入和输出对于renderpass ,我们要定义资源的使用其是read,write,还是create。当然对于长期贮存的资源我们是要imported进RDG中,例如History buffer for TAA,Backbuffer
Compile phase 剔除没有使用的资源和pass
计算资源的生命周期
根据使用情况分配实际的GPU资源
Execute phase 对于每个pass执行回调函数
这个阶段就是跟我们的之前的渲染流程一样的执行draw,dispatch
Unreal RDG 实例 由于unreal4.23后,RDG才真正的加入,目前的资料还是比较的稀少,所以我们需要学习如何使用,最好的方式就是仿造引擎中一些已经使用到的地方。
FTAAShaderParameters,FSSDSignalTextures,FDOFGatherInputTextures,FDeferredLightUniformStruct
Screen pass pixel shader: ●SSS ●Motion Blur
Stenciltest: ●SSR Stencil Setup ●TAA Pixel Shader
Papalqi published on 2020-02-17 included in 动画 AR Kit sample分析
arkit动画模型规范
关卡蓝图流程 Live Link Plugin 使用Live Link Plugin驱动面部追踪数据,包括当前的面部表情和头部旋转,作为一个运动捕获设备来puppeteer一个onscreen charater.
概览 对比51个独立的面部位姿。这些位姿在ARKit SDK内部,每一个位姿对应面部的一个特定部分。比如左眼,右眼,嘴巴等。位姿的值在[0.0, 1.0]间变化。举例来说,如果一个用户闭上左眼,那么LeftEyeBlink会在[0.0, 1.0]之间变化。
也就是说,用户的面部自然移动时,所有的51个位姿会被SDK评估并分配一个值。UE4 ARKit集成了所有的51个位姿,通过Live Link Plugin导入到UE4中。这51个值能够驱动实时的任务面部表情。
需要做的是捕获并驱动人物的头部来确保角色内容能够使用这51个数据。这51个反馈数据在[0.0, 1.0]之间,因而十分适合驱动人物角色表情。
详情请参见:
arkit动画模型规范
设置 角色设置
创建一个blend shape角色模型基于面部动画,包括51个blend shapes.理想的,这些blend shapes的命名也与Apple ARKit一致。 导入到UE4,确保导入了Blend Shapes 在DefaultEngine.ini文件中开启面部追踪。
打开项目,在项目设置中设置AR为On.
创建并应用一个Data Asset来进行面部追踪。
内容浏览器,Miscellaneous > Data Asset 选择ARSessionConfig 双击 new Asset 设置 World Alignment: Camera Session Type: Face Horizontal Plane Detecion: Off Vertical Plane Detection: Off Enable Auto Focus: Off Light Estimation Mode: Off Enable Automatic Camera Overlay\Trakcing :Off 在关卡蓝图中Begin Play后,带动Start AR Session,并设置ARSessionConfig数据。 创建一个动画蓝图,使用LiveLinkPose节点,名称为FaceAR.
Papalqi published on 2020-02-14 included in 动画 arkit动画模型规范 Neutral-静态的pose
一.创建Blendshape 曲线 苹果通过ARKit面部捕捉技术,提供开发者使用iphoneX以上的机器的前置摄像头,实现面部捕捉。blendshape名称是写死的,总共51个blendshape我们需要去实现,不过我们可以实现一些而不是全部。强烈建议的是,命名和功能需要保持一致。所有的值是在0-1之间.
eyeBlinkLeft eyeLookDownLeft eyeLookInLeft eyeLookOutLeft eyeLookUpLeft eyeSquintLeft eyeWideLeft eyeBlinkRight eyeLookDownRight eyeLookInRight eyeLookOutRight eyeLookUpRight eyeSquintRight eyeWideRight jawForward jawRight jawOpen mouthClose mouthFunnel mouthPucker mouthLeft mouthRight mouthSmileLeft mouthSmileRight mouthFrownLeft mouthFrownRight mouthDimpleLeft mouthDimpleRight mouthStretchLeft mouthStretchRight mouthRollLower mouthRollUpper mouthShrugLower mouthShrugUpper mouthPressLeft mouthPressRight mouthLowerDownLeft mouthLowerDownRight mouthUpperUpLeft mouthUpperUpRight browDownLeft browDownRight browInnerUp browOuterUpLeft cheekSquintRight noseSneerLeft noseSneerRight eyeBlinkLeft ;eyeLookDownLeft ;eyeLookInLeft eyeLookOutLeft eyeLookUpLeft eyeSquintLeft eyeWideLeft eyeBlinkRight eyeLookDownRight eyeLookInRight eyeLookOutRight eyeLookUpRight eyeSquintRight eyeWideRight jawForward jawLeft jawRight jawOpen mouthClose mouthFunnel mouthPucker mouthLeft mouthRight mouthSmileLeft mouthSmileRight mouthFrownLeft mouthFrownRight mouthDimpleLeft mouthDimpleRight mouthStretchLeft mouthStretchRight mouthRollLower mouthRollUpper mouthShrugLower mouthShrugUpper mouthPressLeft mouthPressRight mouthLowerDownLeft mouthLowerDownRight mouthUpperUpLeft mouthUpperUpRight browDownLeft browDownRight browInnerUp browOuterUpLeft browOuterUpRight cheekPuff cheekSquintLeft cheekSquintRight noseSneerLeft noseSneerRight 二.
Papalqi published on 2020-01-21 included in 动画 动画基础概念 3D模型动画的基本原理是让模型中各顶点的位置随时间变化。主要种类有Morph(变形)动画,关节动画和骨骼蒙皮动画(SkinnedMesh)。
从动画数据的角度来说,三者一般都采用关键帧技术,即只给出关键帧的数据,其他帧的数据使用插值得到。但由于这三种技术的不同,关键帧的数据是不一样的。
Morph(渐变,变形)动画是直接指定动画每一帧的顶点位置,其动画关键中存储的是Mesh所有顶点在关键帧对应时刻的位置。 关节动画的模型不是一个整体的Mesh,而是分成很多部分(Mesh),通过一个父子层次结构将这些分散的Mesh组织在一起,父Mesh带动其下子Mesh的运动,各Mesh中的顶点坐标定义在自己的坐标系中,这样各个Mesh是作为一个整体参与运动的。动画帧中设置各子Mesh相对于其父Mesh的变换(主要是旋转,当然也可包括移动和缩放),通过子到父,一级级的变换累加(当然从技术上,如果是矩阵操作是累乘)得到该Mesh在整个动画模型所在的坐标空间中的变换(从本文的视角来说就是世界坐标系了,下同),从而确定每个Mesh在世界坐标系中的位置和方向,然后以Mesh为单位渲染即可。关节动画的问题是,各部分Mesh中的顶点是固定在其Mesh坐标系中的,这样在两个Mesh结合处就可能产生裂缝。 第三类就是骨骼蒙皮动画即SkinnedMesh了,骨骼蒙皮动画的出现解决了关节动画的裂缝问题,而且效果非常酷,发明这个算法的人一定是个天才,因为SkinnedMesh的原理简单的难以置信,而效果却那么好。骨骼动画的基本原理可概括为:在骨骼控制下,通过顶点混合动态计算蒙皮网格的顶点,而骨骼的运动相对于其父骨骼,并由动画关键帧数据驱动。一个骨骼动画通常包括骨骼层次结构数据,网格(Mesh)数据,网格蒙皮数据(skin info)和骨骼的动画(关键帧)数据。下面将具体分析。 SkinnedMesh中文一般称作骨骼蒙皮动画,正如其名,这种动画中包含骨骼(Bone)和蒙皮(Skinned Mesh)两个部分,Bone的层次结构和关节动画类似,Mesh则和关节动画不同:关节动画中是使用多个分散的Mesh,而Skinned Mesh中Mesh是一个整体,也就是说只有一个Mesh,实际上如果没有骨骼让Mesh运动变形,Mesh就和静态模型一样了。
Skinned Mesh技术的精华在于蒙皮,所谓的皮并不是模型的贴图(也许会有人这么想过吧),而是Mesh本身,蒙皮是指将Mesh中的顶点附着(绑定)在骨骼之上,而且每个顶点可以被多个骨骼所控制,这样在关节处的顶点由于同时受到父子骨骼的拉扯而改变位置就消除了裂缝。
Skinned Mesh这个词从字面上理解似乎是有皮的模型,哦,如果贴图是皮,那么普通静态模型不也都有吗?所以我觉得应该理解为具有蒙皮信息的Mesh或可当做皮肤用的Mesh,这个皮肤就是Mesh。
而为了有皮肤功能,Mesh还需要蒙皮信息,即Skin数据,没有Skin数据就是一个普通的静态Mesh了。
Skin数据决定顶点如何绑定到骨骼上。顶点的Skin数据包括顶点受哪些骨骼影响以及这些骨骼影响该顶点时的权重(weight),另外对于每块骨骼还需要骨骼偏移矩阵(BoneOffsetMatrix)用来将顶点从Mesh空间变换到骨骼空间。在本文中,提到骨骼动画中的Mesh特指这个皮肤Mesh,提到模型是指骨骼动画模型整体。骨骼控制蒙皮运动,而骨骼本身的运动呢?当然是动画数据了。
每个关键帧中包含时间和骨骼运动信息,运动信息可以用一个矩阵直接表示骨骼新的变换,也可用四元数表示骨骼的旋转,也可以随便自己定义什么只要能让骨骼动就行。除了使用编辑设定好的动画帧数据,也可以使用物理计算对骨骼进行实时控制。
线性混合蒙皮算法 在骨骼动画的蒙皮算法中,出现最早、最经典,也是应用最为广泛的算法是线性混合蒙皮算法。
根据骨骼动画的基本原理,动画模型之所以能够运动,是由于其骨骼带动了蒙在骨骼之上的皮肤一同动作,实现了动画效果。因此,因首先设置好模型骨架以及各骨骼之间的关联性,当运动数据到来时,计算皮肤顶点的新位置,就可以完成模型的运动。
黑色与白色的皮肤顶点分别与其相同颜色的骨骼相绑定。
方框里的皮肤顶点离两个骨骼关节最近,它们同时受到两个骨骼关节的影响。当骨架运动的时候,对于这些受多个骨骼共同影响的皮肤顶点,我们要计算它们变换后的位置信息,即找到皮肤网格自动变形后的方法,传统一般采用线性混合蒙皮算法。线性混合蒙皮算法是由 Lander 最早提出并实现的一种柔性绑定算法。Lander 利用线性混合蒙皮算法实现了人体上臂的动画,解决了之前的刚性绑定算法在关节处的失真问题。该算法的基本原理可以用下列公式表示
V表示顶点变换前的世界坐标系中的位置,V’表示顶点变换后的位置,i 表示同时影响该顶点的骨骼数量,一般取 2-4 之间的值。W_i表示第 i 个骨骼对该顶点的施加的影响权重,取 0-1 之间的值,M_i表示在模型初始参考姿势下,与顶点相关的第 i 个骨骼由本地坐标转换为世界坐标的转换矩阵(即骨骼变换的绝对矩阵),通过矩阵M_i能将骨骼 i 从初始位置转换到动画数据来到时的新位置上.
综上所述,线性混合蒙皮算法即是求得一个顶点在每个骨骼影响下的一系列新的位置,然后对这些位置数据进行加权平均计算得到最后的结果。
在线性混合蒙皮算法中,顶点的新位置 V′是通过其初始位置V 乘以一个矩阵 C 得到,这个矩阵被称为变换矩阵。
我们可以使用 OFFSET(偏移)的 3 个量来表示子关节相对父关节的偏移量;用 CHANNELS 来表示关节旋转通道数量和旋转顺序,其中根关节有6个通道,其他关节有3个通道,与根关节相比少了XYZ的位置(position)信息,这是因为其他关节都可以根据相对其于父关节的偏移量计算坐标位置。
运动数据对应的是骨架信息中各关节点的层次数据,即CHANNELS 中 Zrotation Xrotation Yrotation 顺序的数据。对于子关节来说,平移信息存储在骨架信息的 OFFSET 中,旋转信息则来自于运动数据部分;对于根关节来说,平移量是 OFFSET 和运动数据部分中定义的平移量之和。要得到蒙皮所需的绝对变换矩阵,首先需要根据 BVH 文件中的旋转数据分别创建三个方向轴(Y 轴,X 轴,Z 轴)对应的旋转矩阵,然后将它们按顺序相乘得到矩阵R (也称相对矩阵):
绝对变换矩阵是由关节的相对矩阵乘上它的父关节的绝对矩阵得到的,其中,根关节的绝对变换矩阵就是它的相对矩阵。因此,根据骨架各关节之间的关系,可以计算出每一个关节的绝对变换矩阵,用来将关节的本地坐标变换为世界坐标。
在骨骼动画中,一般使用正向运动学和逆向运动学将运动数据作用到动画模型上。正向运动学是从模型的根节点开始(对人体模型来说,髋关节就是根节点),根据骨骼的拓展顺序,逐个计算各关节在动画数据下的偏移和旋转量,直至到达末端节点为止。
蒙皮算法中变换矩阵的计算实际上就是插值的计算。对于动画中发生动作的骨骼,应根据该骨骼的数据找出其前后两个关键帧,根据时间差进行插值计算。对于使用四元数表示旋转的情况,可以使用四元数线性插值或四元数球面插值。将插值得到的四元数转换成变换矩阵(旋转矩阵部分),最后更新骨骼之间的层次关系,计算出各个骨骼的绝对变换矩阵,完成顶点的新位置计算。
线性混合蒙皮算法的缺陷 线性混合蒙皮算法需要手工设置骨骼对皮肤顶点影响的权重值,这项工作繁琐耗时,并且要求设计者对模型的构成要比较熟悉。不过随着建模软件的日趋完善,现在已经有很多建模软件简化了权重设置这项工作,比如常用的 3DMax、Maya 等大型 3D 建模软件,为骨骼与皮肤的绑定提供了很多便捷的操作功能,能大大节省该工作的时间,提高工作效率。
Papalqi published on 2020-01-04 included in 灯光 构建 在编辑器中,我们可以找到build的按钮,当然,我们这里讨论的并不是构建所有的东西,而仅仅讨论在构建灯光的时候。关于构建参数,请参考光照设置
编辑器构建系统 当我们点击build的时候,我们将触发下面的函数, 1 2 3 4 5 6 FEditorBuildUtils::EditorBuild(); //其会调用StopRenderingThread(); if (GUseThreadedRendering) { StartRenderingThread(); } 其中,关于build的内容定义为
目前我们仅关心的是BUILDTYPE_Lighting,看buildLighting的分支
这里会对BSP进行特殊处理,如果场景中没有BSP的话,我们就不需要进行 geometryrebuild。之后,我们会进行BuildLighting。
我们看一下传入的数据LightingBuildOptions的填充,其是取的config里面的数据
在这里,收前强制关闭所有的texture property windows,因为这些在构建灯光时是无效的。 之后有一个回调这个目前来看并没有东西,我们暂且先不去管他。
建立构建系统 首先FStaticLightingManager,其为单例模式,用来进行管理静态光照的所有系统和子系统。其只是一个管理功能,而不是一个真正的执行build的类。
其最开始的入口就是CreateStaticLightingSystem。如果目前已经有了StaticLightingSystems那么会发生警告说
如果目前没有残存的余孽的话,我们会有进行接下来的流程。这里会有一个逻辑,如果我们的配置中没有选择bOnlyBuildVisibility,也就是是由只是构建可见的,其会在结束后build ReflectionCaptures。
之后,对整个world的所有level进行判断,看是否有lighting scenario,这个概念是说同一个level可以有不同的光照图。这里是说,这个level是否是一个lightingscenario。 我们会把需要构建的level进行添加,如果我们对应的level,我们添加空的。
我们会将每一个level添加入FStaticLightingManager内部中的真正处理的类为StaticLightingSystem其进行处理的单元是一个level,这从它的构造函数可以很明显的看出来。
在FStaticLightingManager中有一个针对class FStaticLightingSystem*的指针。
之后获取列表中StaticLightingSystems的指针,然后进行真正的构建,BeginLightmassProcess,如果成功,SendProgressNotification进行显示,如果失败DestroyStaticLightingSystems通知显示。
每一个level的构建 因此,我们进入FStaticLightingSystem,来进行每一个level的构建
初始化。对所有的UPrimitiveComponent,里面的VisibilityId进行赋值INDEX_NONE初始化。对所有的level,如果不是当前的PersistentLevel,那就FindStreamingLevel。并且在设置中,会有设置,如是否只build CurrentLevel,bOnlyBuildSelectedLevels等会有不同的变化。那些被Skipped的Levels会被收集。这里还会有TextureStreaming的配置的搜集。在进行load一些其他的LoadGlobalIniFile里面的东西。
收集灯光,剔除所有的AGeneratedMeshAreaLight(在逻辑上是自发光物体)。搜集场景中所有的ULightComponentBase存储在TArray Lights;
收集mesh,Gather static lighting info from BSP.Gather HLOD primitives Gather static lighting info from actors.Recurse through HLOD trees, group actors and calculate child ranges。
这里面非常重要的结构
显而易见,这里一个是有排序的,一个是没有排序的。
我们将看到FStaticLightingMapping在世界的平面和static lighting cache的一个映射。
一.网络总览 Unreal Engine4使用标准的Server-Client体系结构。 这意味着服务器是权威的,所有数据必须首先从客户端发送到服务器。 然后服务器依赖你写的代码验证数据并且给予反馈。
1.1一个简单的例子 在多人匹配中,作为一个客户端,当你移动你的角色时,你并不是自己移动你的角色,而是告诉服务器你想移动它。 然后服务器为其他人(包括你)更新你的位置,。
注意:为了防止对本地客户端产生“滞后”的感觉,程序员经常让这个玩家直接在本地控制他们的角色,虽然服务器仍然可能在客户端开始作弊的时候覆盖角色的位置!这意味着,客户端将(几乎)永远不会直接与其他客户端“交谈”。
1.2其他的例子 当向另一个客户端发送聊天消息时,您实际上是将其发送到服务器,然后服务器将其传递给您想要到达的客户端。 也许你消息的结构方并不是一个人,也就是不只是一次私聊,对方有可能是是一个team,guild,group等。
永远不要相信客户! 信任客户端意味着在执行客户端操作之前不测试客户端操作。 这将允许作弊!不过有些情况下我们可能会允许一些纯粹表现的效果只在客户端进行而不在客户端验证。一个简单的例子是射击:在服务器上应当确保对某个客户端的测试,如果在服务器的记录中显示该客户端实际上有弹药,才应当允许该客户端射击,而不是直接在客户端处理射击!
二.UE4 的网络框架 我们如果拥有一个对象,使用前面关于UE4的Server-Client体系结构的信息,我们可以将框架分成4个部分:
Server Only – 只在服务器上 Server & Clients – 同时存在客户端和服务器 Server & Owning Client – 只在服务器和拥有他的客户端上 Owning Client Only – 这些对象只存在于客户端上 “Owning Client”是一个所有权的问题,也就是这个对象的所有权是否是在你这一台客户端上,例如你控制的角色,这个对象对于你来说,归属权就是Owning Client。 所有权在以后的“RPC”中变得很重要。下图展示了一些常见的类以及它们存在的部分。这就是一些最重要的类是如何在网络框架中布局的。 下图显示了另一个例子(具有两个客户端的专用服务器),说明这些类的对象如何通过网络框架分发: 之后将展示一些最常见的类。 还将提供如何使用这些类的小示例。
如果不理解,请忽略,直到您阅读系列后面有关复制等章节的内容。
一些游戏类型可能会使用不同方式使用这些类。 下面的例子和解释不是唯一的方法
2.1 GameMode 4.14开始GameMode类被分成 GameModeBase和GameMode。 GameModeBase的功能较少,因为有些游戏可能不需要GameModeBase类的完整功能。
GameMode用于定义游戏的规则。 这包括如Apawn、Player Controller、APlayer State等。 它只在服务器上可用。 客户端没有这个对象,并且在试图检索它时只会得到一个nullptr。
GameMode例如死亡匹配,团队死亡匹配或捕获旗帜等模式。这意味着游戏模式可以定义如下内容:
我们是团队比赛还是个人竞赛 获胜条件是什么?一个人/一个团队需要多少次杀戮? 如何取得胜利? 杀了人? 夺旗? 将使用哪些角色? 允许使用哪些武器? 只有手枪? 在多人游戏中,GameMode也有一些有趣的功能,帮助我们管理玩家和/或一般的比赛流程。
Papalqi published on 2019-12-30 included in 灯光 丑话说在前面,基于物理的灯光参数有没有用呢?看如何对待,如果我只要效果,你如何进行灯光的调节只要最后好看,就没有问题;但是如果我们想要一个能够复用的灯光资源库,这就是一个非常好的一种方法。现在来说等白嫖(别人把理论研究清楚,因为现在还没有基于这种做法而商业成功的项目)而不是自己去研究是一个非常务实的想法。 在unreal中如果我们把灯光值调到和现实中一致的单位,默认情况下一定是曝光过度。这是因为我们的EV值。因为引擎中的成像原理和现实中的相机的一致。EV值代表的是快门,光圈,ISO的组合结果。
我们为什么要基于物理照明? 基于物理的光照使我们能够根据实际值为场景设置基础的光照,并且即使稍后能调整它也能表现很好。如果你的场景拥有截然不同的光源。一个简单的例子是一个场景,有太阳,也有一些人造光,如灯或火把。一个天真的方法,也就是经常采用的方法就是让太阳比灯强四倍,如果经过调整,可能看起来合理。但是,请考虑您决定在场景中再添加五盏灯。这可能会摒弃你的太阳和灯之间的微弱人工平衡,需要重新调整。每当变量快速变化时,这种不断调整会耗费大量时间并导致大量冗余工作。当然,问题是太阳的强度只比灯泡高四倍,这实际上是扯淡的。它比典型灯要大50-70倍。 Unreal 在4.19版本增加了基于物理的灯光参数。很多情况下我们都是结果导向的,所以用不用我们在值得商榷的,毕竟这个流程能够提升的东西并不是非常的多。唉,再说吧。
光学的定义 1.光强度(luminous intensity)是光源在单位立体角内辐射的光通量,以I表示,单位为坎德拉(candela,简称cd).1坎德拉表示在单位立体角内辐射出1流明的光通量. 2.光通量(luminous flus)是由光源向各个方向射出的光功率,也即每一单位时间射出的光能量,以φ表示,单位为流明(lumen,简称lm). 3.光照度(illuminance)是从光源照射到单位面积上的光通量,以E表示,照度的单位为勒克斯(Lux,简称lx). 坎德拉是基本单位,就是先定它,其他都是推导的。最初是用蜡烛来定义的。1948年第九届国际计量大会上决定采用处于铂凝固点温度的黑体作为发光强度的基准,同时定名为坎德拉,曾一度称为新烛光,1967年第十三届国际计量大会又对坎德拉作了更加严密的定义。由于用该定义复现的坎德拉误差较大,1979年第十六届国际计量大会决定采用现行的新定义。
所以,液晶屏单位是坎德拉,投影仪是使用的是流明.流明是1坎德拉的光源在单位立体角里放射的光通量。 换算体系: Candela= 0.09290304 Lux
日间场景 夜间场景 在夜间场景中,月亮是场景中的主要光源。使用完全逼真的月亮的亮度值会导致相当无聊的外观。考虑到月亮在晴朗的夜空中提供了大约0.25勒克斯的空间,与阳光提供的20,000 - 120,000勒克斯相比,这是一个绝对巨大的差距。
由于场景完全依赖于自然光线,这将意味着一个非常黑暗的场景。所以我们实际上在这种情况下增强了间接照明。话虽如此,我们在各种光源(月亮,天光等)上均匀地增强了照明,使它们的相对关系保持完整。这是使用现实价值观的真正要点 , 不是教条地坚持它们,而是提供一个坚实的基础,从而以足够灵活的方式调整和实现你的艺术目标,以便将来修改。
´ RHIThread并不是所有平台都需要的。默认仅给PC平台开启。
RHI线程的话,做三件事情:
DrawCommand to GPU Command, 把DrawCommand转化为渲染API的GPU Command GPU Command submit, 提交DrawCall。 Flip GPU,等待Swapchain发生。 我们的输入和最后的呈现其实会有6帧的延迟 主线程处理 渲染线程处理 RHI等提交给GPU GPU垂直同步 双重缓冲交换 为什么需要RHI线程 在某些平台上比如d3d11,提交渲染命令不支持并行化。为了解决这个问题,提交渲染命令是最初是放到渲染线程的,后来为了加快渲染线程的计算,把提交渲染命令单独抽到了一个线程,这个线程就是RHI线程。 我们可以看到,开启RHI线程后将会变的非常平滑