我的专栏目录:
小IVan:专题概述及目录前面介绍了一般数据的传输方式,这一卷我们将一起来使用更高级的数据传输方式UniformBuffer。这个问题困扰了我两天,查了很多资料,翻了很多论坛也没找到解决办法。这里要特别感谢一位QQ昵称是“August”的朋友的指点帮助。
先看下效果吧
![v2-e4a621126481a8032119ca55a2c52922_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/b49827652375fda125c391d0356391b3.jpeg)
![v2-69b7859fa5eca3a412f6fbafc95a1ea9_b.gif](https://i-blog.csdnimg.cn/blog_migrate/c80f6ba3bf3424a240d792339e5739c7.gif)
可以看到这次是使用一个UniformBuffer在控制整个颜色的变换了。虽然效果很简单,但是最重要的其实是如何上传UniformBuffer。
关于UE4的Uniform buffer(CPU写,GPU只读),在D3D里相当于constbuffer,在OpenGL里相当于uniformbuffer,而UE4的Uniform buffer比较特殊的是: 在usf并没有采用hlsl的const buffer语法去定义uniformbuffer,从一些资料得知,可能的原因是为了统一和跨平台。如OpenGL的阉割版OpenGL es 2.0不支持uniformbuffer相关的语法。也就是说,UE4的Uniform buffer是epic自己封装,在某些平台上,是用模拟的方式达到uniformbuffer的功能,在usf里没有直接的uniformbuffer定义语法,这方面是UE的shader编译器动态生成相关的定义代码。Uniform buffer在c++用以下几个宏实现:
BEGIN_UNIFORM_BUFFER_STRUCT
DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER
END_UNIFORM_BUFFER_STRUCT
IMPLEMENT_UNIFORM_BUFFER_STRUCT
在代码里是这样的(如下图所示)(注意那个逗号):
![v2-ef4749432dfaf341dbfdf88fb3f63270_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/cd2450a062afbb50c5c219ac88eed832.jpeg)
这样就声明了一个uniformbuffer。这几个宏回帮我们在渲染线程实现一些类的声明和渲染资源的准备。下面就是我们需要在c++层来设置这个uniformbuffer了,既然需要设置,那么我们就在c++层声明一个结构体用来设置这个uniformbuffer
![v2-65154763795cf6a3725ab730c2b65876_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/38e8380761a152260d459edb376ec877.jpeg)
再用SetUniformBufferParameterImmediatehan函数设置一下:
![v2-3e0dd3a6970dda158f364d5f973d8762_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/04297722ab3608a40bf7460ebc722201.jpeg)
这样便完成了c++层的uniformbuffer的数据传输。
这里需要值得注意的是我们HLSL代码可以直接使用这个uniformbuffer,虚幻4会自动给我们生成一个uniformbuffer的HLSL代码然后给我们include到Common.usf里面,所以shader代码必须包含Common.ush。
![v2-f7ff7e77a28a11a52c578f85c0af41c8_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/3266e8c7e0032f55b780a36375f5229c.jpeg)
我们再来捋一下思路。首先我们用虚幻的那几个宏,声明并准备一个UniformBuffer。这个UniformBuffer并不需要在HLSL文件里声明对应的变量。因为虚幻考虑到优化和跨平台,所以会帮我们封装然后生成这个UniformBuffer的HLSL代码,我们在shader里直接调用即可。但是虚幻生成的这些HLSL代码是被Common.usf包含的,所以我们需要在我们自己的shader文件里包含Common.ush才行,如果不做这一步会导致HLSL编译失败。我们在c++层声明了一个和Uniform数据结构类似的结构体用于c++层向渲染层传数据。再用SetUniformBufferParameterImmediatehan设置buffer的值。
下面是完整代码:
MyShaderTest.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Classes/Kismet/BlueprintFunctionLibrary.h"
#include "MyShaderTest.generated.h"
USTRUCT(BlueprintType)
struct FMyShaderStructData
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadWrit