2016-05-23 18:46:10 noahzuo 阅读数 4884
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2158 人正在学习 去看看 杨石兴

这篇博客讲解了在UE4中,反射机制的实现。


反射机制

反射机制指的是程序可以在运行期间进行检测和修改自己状态的能力。

UE4引擎使用C++语言编写,C++语言本质上不支持反射机制,但是UE4提供了反射机制的实现。

FindFunction函数

在UE4中提供了FindFunction函数,用于在UObject或者AActor中查找某个函数名的函数并且返回其函数指针。

使用方法如下:

UFunction *Injured = this->FindFunction(TEXT("Injured"));

因此我们可以在Runtime时根据函数名的不同来进行函数的查找并且触发。

使用ProcessEvent函数来进行函数的触发

在UE4中提供了ProcessEvent函数来进行触发函数指针对应的函数,具体使用方法如下:

UFunction *Injured = this->FindFunction(TEXT("Injured"));
if (Injured)
{
    ProcessEvent(Injured, nullptr);
}

ProcessEvent函数第一个参数是函数指针,第二个参数指的是参数列表,其类型为void*类型。

使用CallFunction函数进行触发

还可以使用CallFunction函数来进行对应函数的触发,但是需要进行FFrame的建立。

并且为了避免内存泄漏,需要注意在使用过后销毁FFrame

使用方法如下:

UFunction *Injured = this->FindFunction(TEXT("Injured"));
if (Injured)
{
    void* params = nullptr;
    FFrame* frame = new Frame(this, Injured, params);
    CallFunction(*frame, params, Injured);

    delete frame;
}

额外功效

使用如下的两种方法还可以有一个额外的功能 —— 在C++中进行BP函数的调用。当需要在C++与BP进行通信时,一个做法是在关卡中进行通信,另一个做法则是使用上面的方法进行函数调用。

<全文完>

2020-01-15 14:39:30 weixin_37641634 阅读数 10
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2158 人正在学习 去看看 杨石兴

4.24毛发文档:
1.首先: 把project setting 里的设置
在这里插入图片描述
在这里插入图片描述

2.Plugn里把groom和Niagara的插件开启
在这里插入图片描述
在这里插入图片描述

3.毛发导出就是以曲线的方式导出,没有特别的设置,Fbx,abc格式groom都可识别,官方给的支持格式是abc模式,具体差别尚待测试。

在这里插入图片描述
在这里插入图片描述

导入后groom的detail里有个hair width,需要调节宽度,才能反射出材质效果。

在这里插入图片描述

4.头发材质不做详细讲解,还是那么写…
5.Niagara碰撞:
在这里插入图片描述
首先把插件显示打开
在这里插入图片描述
然后绑定到对应骨骼

在这里插入图片描述

然后再groom里添加Niagara,注意父子关系就可以了,第一次添加groomAssetSystem的时候可能会卡,耐心等待。

之后参数参考,自行测试调节吧在这里插入图片描述

官方文档的地址:https://docs.unrealengine.com/zh-CN/Engine/HairRendering/QuickStart/index.html

2016-07-14 02:31:01 kevin_dust 阅读数 1570
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2158 人正在学习 去看看 杨石兴

Unreal Engine 4 PBR节选翻译
——– Real Shading in Unreal Engine 4
图片稍后补上

Introduction

Shading Model

Diffuse BRDF
我们评估了Burley的漫反射模型,但是仅仅看到跟Lambert模型的一点点区别。因此我们无法理解这种额外的花销。此外,对于IBL(ImageBased-Light)和Harmonic Lighting(球谐照明),任何更复杂的漫反射模型都难以被有效利用。最终导致我们并没有投入过多的精力去评估其他选择。

Cdiffuse 代表材质的漫反射的反射率(Albedo)

Microfacet Specular BRDF
一般的Cook-Torrance微平面高光模型是:

我们起步于Disney模型,并为每个项评估提供比其更高效的替换项的重要性。这做起来比听起来要困难得多。对于公布的公式的每个项,没有必要使用相同的输入参数,这是对于做正确的比较非常重要。

Specular D
对于法线分布函数(NDF),我们发现disney使用的GGX/Trowbridge-Reitz是非常消耗的。使用Blinn-Phong,额外的花销会很小,而且由于其函数的长尾巴展现的独特且自然的表现吸引了我们的美术人员。我们还采用了Disney对roughtness的重新参数化。

Specular G

相比其他,我们对镜面反射的几何衰减项进行更多选择上的评估。最后我们选择了Schlick模型。但是k = a/2,以便在GGX上更好地适应Smith模型。有了这样的修改,Schlick模型更加贴近当a=1的Smith模型,而且范围非常接近[0,1](如Figure 2)。我们同样选择去使用Disney的更改去减少“hotness”(过热),通过在平方前使用(Roughtness+1)/2,重新将roughness映射。需要注意的是,注重处理只使用于可解释的光源(Analytic Light),如果它被运用到IBL上,会导致在掠视角的地方过黑。

Specular F
对于菲涅尔,我们选择经典的Schlick方法,但是仍然有一点点的改动:我们使用Sphere Gausian 近似方法来替代power。这会使得计算有稍微改进,且画面上不会感到明显的不同。公式如下:

F0是在法线出的镜面反射率。

Image-Based Lighting
要将该渲染模型作用于IBL上,需要解决辐射度的积分。这需要用到重要性采样(Importance Sample),下面的公式描述了该积分:

下面是展示如何让我们的渲染模型处理的HLSL代码

即使使用重要性采样,还是要进行很多次采样。使用mipmap可以大幅度降低采样的次数,但是为了满足质量次数还是比16要大。由于本地反射,我们需要对每个像素进行许多次环境贴图的采样,所以我们只能对每个像素提供一次单独的采样。

Split Sum Approximation
为了达到该目的,我们近似地将上述和式拆成两个部分。每个分拆的和式都可以被预先计算。这种近似对于恒定不变的光和普通的环境是相当准确的。

Pre-Filtered Environment Map
我们对不同粗糙度预计算第一个和式,并且将结果存储到具有mipmap等级的CubeMap中。这是游戏工业的一个典型做法。一个细微的区别是我们使用重要性采样对GGX分布的Environment Map进行卷积计算。因为他是一个微平面,分布形状根据对表面观看角度的不同而改变。所以我们假设这个角度为0度,即n=v=r。这个各向同性假设是近似的第二来源,并且很不幸的,这意味着我们无法在掠视角得到足够长的反射。与拆分和式的方法相比,这是我们IBL解决方案的一个很大错误。如下面代码所示,我们发现将cos(Lk)的权重设为1将有更好的效果。
EnvironmentBRDF
第二个和式包含其他所有东西,这根正在一个完全白的环境下对specularBRDF积分,即Li(lk)=1
通过Schlick的菲涅尔近似替换,我们发现,F0是可以从积分中分解出来。

这就只剩下两个输入量:Roughness和,还有两个输出量:scale和F0的bias。上述的参数都是很方便地落于[0,1]中。我们预计算这个函数的结果,并将其保存在look-up texture(LUT)中。

完成这些工作后,我们发现,现有的和正在研究的结果都最终共同指向这个方法。Whilst Gotanda使用一个3D LUT,Dro0bot 将其优化到一个2D LUT上,这跟我们的方法类似。

最后,为了近似重要性采样,我们将两个预计算的和式相乘:

Material Model
Material Layering
Lighting Model
Area Lights
Billboard Reflections
Cone Intersection
Specular D Modification
Representative Point
Sphere Lights
Tube Lights
Conclusion

下面是一个关于该演讲的后续技术补充:
在移动平台下对UE4 PBR的改进
https://www.unrealengine.com/zh-CN/blog/physically-based-shading-on-mobile

2020-01-12 16:41:18 a497406594 阅读数 7
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2158 人正在学习 去看看 杨石兴

前言

首先,C++不同于C#或者Java,没有自带反射机制,只能通过C++一些传统艺能变着法地实现。

有哪些反射

1、类对象反射:简单地说就是程序运行时读进来一个字符串,然后程序就会自动创建出字符串对应名字的类对象

2、类属性反射:能够遍历得到类的所有成员,知道它们的数据类型和名字。最实际的例子就是Unreal和Unity中UI的实现,当定义一个类成员变量时,它就能在UI中显示出来。而不需要费事地再去针对新增的变量写UI代码,让它显示在界面上。

3、函数反射:能够自动搜集函数的相关的所有信息,包括名称,参数个数,参数类型,返回值。

类对象反射

其实用工厂模式就能轻松解决这个问题。解决这个问题的思路是

1、首先,创建对象的接口要方便,最好统一成一个,也就是说类似下面这个接口。无论什么对象,只要传个名字就能返回对象指针。

static Object* CreateObject(std::string className)

2、由于返回的是同样类型的指针,那么就必须继承相同的基类,也就是Object。

3、然后要怎么根据名字创建对象呢?就需要用到工厂模式了,用一个map存储工厂类,然后工厂类去创建对象

class ObjectFactory
{
public:
	virtual Object* CreateObject() = 0;
};

template<class T>
class ObjectFactoryImp :public ObjectFactory
{
public:
	virtual Object* CreateObject()
	{
		return new T();
	}
};

std::map<std::string, ObjectFactory*> factoryMap;

4、也就是说我们需要去构造factoryMap,当调用CreateObject时,实际是调用factoryMap[className]->CreateObject(); 构造的方法也很简单,也就是每个类定义的时候,也进行一次初始化,初始化要做的事情就是注册一个工厂类。

template<class T>
void RegisterObject(std::string className)
{
	ObjectFactory* factory = new ObjectFactoryImp<T>();
	if (factoryMap.count(className) == 0)
	{
		factoryMap[className] = factory;
	}
    else
    {
	    delete factory;
    }
}

// 使用方式
RegisterObject<类名>(类名对应字符串);

5、以上就是类反射实现的所有内容,用法也很简单,先调用RegisterObject去注册对象,然后直接调用CreateObject创建对象就行了。我在此基础上做了简单的封装,感兴趣的可以下载看看https://download.csdn.net/download/a497406594/12099078

 

类属性反射

https://zhuanlan.zhihu.com/p/88144082 这篇文章有提到怎么实现,个人是比较倾向于静态反射的,不过老实说用了太多语法糖就不香了,可读性较差。个人是比较推荐这本书的作者用的方式,知识点在第八章。https://zhuanlan.zhihu.com/p/54166550。这部分比较难,并且它这个牵扯的比较多,因为这本书的作者还想顺便实现UI的反射。

如果只是想实现属性反射的话,我按照自己的理解整理了下,至少需要做以下工作

1、定义一个属性类,至少包含属性数据类型,名字,在类中的偏移

2、要实现属性反射的类中需要定义一个静态成员队列,用来存储属性对象,每个属性对应队列里一个元素。这个队列记录在另外的一个单例类里,因为涉及继承,以及是静态的,所以不可能放自己的类里。最好是用一个通用的类,类似上面类反射一样放在全局里,或者某个静态类或单例里。

3、需要像类对象反射一样,先对每个属性进行注册,也就是不得不.h声明完变量之后,又在cpp里再写一遍类似声明的东西。所谓注册,就是创建属性对象加到类的队列里。这一步可以用宏包装下,可以减少一定的代码量

我简单实现了下,感兴趣的可以下载看看https://download.csdn.net/download/a497406594/12100744

函数反射

https://zhuanlan.zhihu.com/p/54166550 这本书依旧有这个知识点,我还不会就先Mark一下吧

2019-06-11 13:35:20 yinxuancheng 阅读数 16
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2158 人正在学习 去看看 杨石兴

官方定义

反射是程序可以访问、检测和修改它本身状态或行为的一种能力。

C++本身并不支持反射机制,可手动通过Map实现。

实际需求

通过类名字符串如“ClassA”生成对应的类对象,并获取类中声明的成员变量和方法,Unreal中蓝图访问C++中类方法即是使用了C++反射机制。

实现思路

为需要反射的类创建类对象的回调函数,在Map中以类名字符串为Key,类对象回调函数为Value,实现绑定。

具体实现

//定义一个函数指针类型,用于指向创建类实例的回调函数
typedef void* (*PTRCreateObject)(void); 

//工厂类的定义

class ClassFactory{
private:  
    map<string, PTRCreateObject> m_classMap ;  
    ClassFactory(){}; //构造函数私有化

public:   
    void* getClassByName(string className);  
    void registClass(string name, PTRCreateObject method) ;  
    static ClassFactory& getInstance() ;  
};

//工厂类的实现

//@brief:获取工厂类的单个实例对象  
ClassFactory& ClassFactory::getInstance(){
    static ClassFactory sLo_factory;  
    return sLo_factory ;  
}  

//@brief:通过类名称字符串获取类的实例
void* ClassFactory::getClassByName(string className){  
    map<string, PTRCreateObject>::const_iterator iter;  
    iter = m_classMap.find(className) ;  
    if ( iter == m_classMap.end() )  
        return NULL ;  
    else  
        return iter->second() ;  
}  

//@brief:将给定的类名称字符串和对应的创建类对象的函数保存到map中   
void ClassFactory::registClass(string name, PTRCreateObject method){  
    m_classMap.insert(pair<string, PTRCreateObject>(name, method)) ;  
}

未完待续...

https://blog.csdn.net/scythe666/article/details/51718864

没有更多推荐了,返回首页