惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
The GitHub Blog
The GitHub Blog
C
Check Point Blog
博客园_首页
MongoDB | Blog
MongoDB | Blog
N
Netflix TechBlog - Medium
F
Full Disclosure
Microsoft Security Blog
Microsoft Security Blog
爱范儿
爱范儿
Recent Announcements
Recent Announcements
阮一峰的网络日志
阮一峰的网络日志
G
GRAHAM CLULEY
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Threat Research - Cisco Blogs
C
Cybersecurity and Infrastructure Security Agency CISA
V
Vulnerabilities – Threatpost
K
Kaspersky official blog
博客园 - 司徒正美
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
Project Zero
Project Zero
云风的 BLOG
云风的 BLOG
Cisco Talos Blog
Cisco Talos Blog
Know Your Adversary
Know Your Adversary
雷峰网
雷峰网
V
V2EX - 技术
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Spread Privacy
Spread Privacy
罗磊的独立博客
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
S
Security Affairs
SecWiki News
SecWiki News
Schneier on Security
Schneier on Security
O
OpenAI News
Jina AI
Jina AI
PCI Perspectives
PCI Perspectives
Cyberwarzone
Cyberwarzone
Y
Y Combinator Blog
Apple Machine Learning Research
Apple Machine Learning Research
B
Blog RSS Feed
I
InfoQ
D
Docker
P
Palo Alto Networks Blog
Recorded Future
Recorded Future
M
MIT News - Artificial intelligence
博客园 - Franky
B
Blog
Scott Helme
Scott Helme
博客园 - 叶小钗
D
DataBreaches.Net

博客园 - 林公子

【译】Import Changes from Direct3D 11 to Direct3D 12 Ring buffers and queues Texture tiling and swizzling 关于strlen误用的一点记录 关于UIView的显示问题 关于“应用程序无法正常启动(0xc000007b)。请单击“确定”关闭应用程序。” 【转】齐次坐标的理解 Learning XNA 3.0翻译连载--第六章 基本的人工智能(2) Learning XNA 3.0翻译连载--第六章 基本的人工智能(1) Learning XNA 3.0翻译连载--第5章 声音和音效 - 林公子 Learning XNA 3.0翻译连载--第4章 应用面向对象设计 Learning XNA 3.0翻译连载--第3章 用户输入和碰撞检测 Learning XNA 3.0翻译连载--第2章 精灵的乐趣(2) Learning XNA 3.0翻译连载--第2章 精灵的乐趣(1) Learning XNA 3.0翻译连载--第1章 起步 Learning XNA 3.0翻译连载--序言 Learning XNA 3.0翻译连载 xpath? XPath! --大小写之惑 理解C#中的委托和事件
Unreal Engine 3自定义Post Process Effect
林公子 · 2012-04-24 · via 博客园 - 林公子

         本文成于学习独行剑侠的一篇文章《Unreal Engine Shader编程基础》的过程中遇到的问题以及自己尝试的结果。

          首先,要新建一个usf格式的文件,放到引擎根目录/Engine/Shaders目录中。这个是UE3中使用的Shader文件格式(大概就是unreal shader file的意思: ),其实也就是文本文件。我们写个最简单的Pixel Shader:

   1: // TestShader.usf
   2:  
   3: float4 MainPS(float2 InUV : TEXCOORD0) : COLOR0
   4: {
   5:     return float4(InUV, 0, 1.0);
   6: }

       Shader代码写好后就要求我们按照Unreal的规则来创建对应的.cpp和/或.uc源文件,我们一步步来。

        在Engine\Src项目目录下新建一个UnTestPixelShaderEffect.cpp文件,用来映射我们的TestPixelShader.usf。

   1: IMPLEMENT_CLASS(UTestEffect);
   2:  
   3: class FTestPixelShader : public FGlobalShader
   4: {
   5:     DECLARE_SHADER_TYPE(FTestPixelShader, Global);
   6: public:
   7:     static UBOOL ShouldCache(EShaderPlatform Platform)
   8:     {
   9:         return TRUE;
  10:     }
  11:  
  12:     static void ModifyCompilationEnvironment(EShaderPlatform Platform, 
  13:                                              FShaderCompilerEnvironment& OutEnvironment)
  14:     {
  15:     }
  16:  
  17:     FTestPixelShader()
  18:     {
  19:     }
  20:  
  21:     FTestPixelShader(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
  22:     : FGlobalShader(Initializer)
  23:     {
  24:     }
  25: };
  26:  
  27: IMPLEMENT_SHADER_TYPE(, FTestPixelShader, TEXT("TestPixelShader"), TEXT("MainPS"), SF_Pixel, 0, 0);

     DECLARE_SHADER_TYPE和IMPLEMENT_SHADER_TYPE宏分别用来声明和定义Shader。这是Shader不带参数的最简单的情况,如果Shader带参数还要在类中声明相应的FShaderParameter/FShaderResourceParameter参数。FGlobalShader还有一个重载函数virtual UBOOL Serialize(FArchive& Ar)用于序列化,我们这里没有用到所以不需要重写它。

      在原文这里就要添加相应的绘制代码到引擎源文件中,出于简单测试目的我不是很想改动底层文件,于是我想能不能利用UE3的PostProcess来达到同样的目的。经过一番探索有了理想的结果。

      要在UE3中使用Post Process首先要创建PostProcessChain,然后将相应的Post Process Effect连接到PostProcessChain。这里就要涉及到自定义Post Process Effect如何实现了。一个Post Process Effect的实现由三部分组成,.cpp文件, .uc文件以及.usf文件,其中usf和cpp文件我们在文章开头已经准备好。经过对UE3自带Post Process Effect的参考,需要创建TestEffect.uc文件以及修改UnTestPixelShaderEffect.cpp文件。

      在Engine/Src/Classes/PostProcess/项目目录创建TestEffect.uc。

   1: class TestEffect extends PostProcessEffect
   2:     native;
   3:  
   4: cpptext
   5: {
   6:     // UPostProcessEffect interface
   7:     /**
   8:      * Creates a proxy to represent the render info for a post process effect
   9:      * @param WorldSettings - The world's post process settings for the view.
  10:      * @return The proxy object.
  11:      */
  12:     virtual class FPostProcessSceneProxy* CreateSceneProxy(const FPostProcessSettings* WorldSettings);
  13:  
  14:     /**
  15:      * @param View - current view
  16:      * @return TRUE if the effect should be rendered
  17:      */
  18:     virtual UBOOL IsShown(const FSceneView* View) const;
  19:  
  20:     /**
  21:     * Called after this instance has been serialized.  UberPostProcessEffect should only
  22:     * ever exists in the SDPG_PostProcess scene
  23:     */
  24:     virtual void PostLoad();
  25: }

      然后修改UnTestPixelShader.cpp,在开头的代码之后添加如下代码:

   1: class FTestEffectPostProcessSceneProxy : public FPostProcessSceneProxy
   2: {
   3: public:
   4:     /** 
   5:     * Initialization constructor. 
   6:     * @param InEffect - DOF post process effect to mirror in this proxy
   7:     */
   8:     FTestEffectPostProcessSceneProxy(const UTestEffect* InEffect,
   9:                                      const FPostProcessSettings* WorldSettings);
  10:  
  11:     /**
  12:     * Render the post process effect
  13:     * Called by the rendering thread during scene rendering
  14:     * @param InDepthPriorityGroup - scene DPG currently being rendered
  15:     * @param View - current view
  16:     * @param CanvasTransform - same canvas transform used to render the scene
  17:     * @param LDRInfo - helper information about SceneColorLDR
  18:     * @return TRUE if anything was rendered
  19:     */
  20:     UBOOL Render(const FScene* Scene, UINT InDepthPriorityGroup,FViewInfo& View,
  21:                  const FMatrix& CanvasTransform,FSceneColorLDRInfo& LDRInfo);
  22: };
  23:  
  24: FTestEffectPostProcessSceneProxy
  25: ::FTestEffectPostProcessSceneProxy(const UTestEffect* InEffect,const FPostProcessSettings* WorldSettings)
  26: : FPostProcessSceneProxy(InEffect)
  27: {
  28: }
  29:  
  30: UBOOL FTestEffectPostProcessSceneProxy::Render(const FScene* Scene, UINT InDepthPriorityGroup,FViewInfo& View,
  31:                                                const FMatrix& CanvasTransform,FSceneColorLDRInfo& LDRInfo)
  32: {
  33:     RHISetRenderTarget(GSceneRenderTargets.GetSceneColorSurface(), FSurfaceRHIRef());
  34:  
  35:     GSceneRenderTargets.BeginRenderingSceneColor();
  36:  
  37:     TShaderMapRef<FScreenVertexShader>  TestVertexShader( GetGlobalShaderMap() );
  38:     TShaderMapRef<FTestPixelShader>     TestPixelShader( GetGlobalShaderMap() );
  39:  
  40:     RHISetViewport( 0, 0, 0.0f, View.RenderTargetX + View.RenderTargetSizeX, 
  41:                                 View.RenderTargetY + View.RenderTargetSizeY, 1.0f );
  42:     RHISetViewParameters(View);
  43:  
  44:     static FGlobalBoundShaderState TestBoundState;
  45:     SetGlobalBoundShaderState( 
  46:         TestBoundState,
  47:         GFilterVertexDeclaration.VertexDeclarationRHI,
  48:         *TestVertexShader,
  49:         *TestPixelShader,
  50:         sizeof(sizeof(FFilterVertex))
  51:         );
  52:  
  53:     DrawDenormalizedQuad(
  54:         View.RenderTargetX, View.RenderTargetY,
  55:         View.RenderTargetSizeX, View.RenderTargetSizeY,
  56:         View.RenderTargetX, View.RenderTargetY,
  57:         View.RenderTargetSizeX, View.RenderTargetSizeY,
  58:         View.RenderTargetSizeX, View.RenderTargetSizeY,
  59:         GSceneRenderTargets.GetBufferSizeX(), GSceneRenderTargets.GetBufferSizeY()
  60:         );
  61:  
  62:     GSceneRenderTargets.FinishRenderingSceneColor();
  63:  
  64:     return TRUE;
  65: }
  66:  
  67: FPostProcessSceneProxy* UTestEffect::CreateSceneProxy(const FPostProcessSettings* WorldSettings)
  68: {
  69:     return new FTestEffectPostProcessSceneProxy(this, WorldSettings);
  70: }
  71:  
  72: UBOOL UTestEffect::IsShown(const FSceneView* View) const
  73: {
  74:     return Super::IsShown(View);
  75: }
  76:  
  77: void UTestEffect::PostLoad()
  78: {
  79:     Super::PostLoad();
  80: }

     完成之后先运行一遍Editor,引擎会解析TestEffect.uc然后在EngineClasses.h头文件中添加对应的native类定义。之后完整编译整个项目。重新打开Editor,新建一个PostProcessChain,命名为TestEffect,双击打开,在Post Process编辑器中右键可以看到菜单底部有我们自定义的TestEffect,将它连接到默认的SceneRenderTarget上,保存PostProcessChain,然后选中它。

     打开任意一张地图,进入View->World Properties菜单项,点击World Post Process Chain栏旁的箭头按钮赋予我们选中的TestEffect,如果一切正常,结果应该类似这样:

      至此一个简单的自定义Post Process Effect就完成了^_^。

     更新:带参数的Shader

     昨天试验过不带参数的简单Shader之后,今天尝试了添加Shader参数的支持。

     首先我们在TestPixelShader.usf文件中添加一个变量:

   1: // TestShader.usf
   2: float4 ShadingColor;
   3:  
   4: float4 MainPS(float2 InUV : TEXCOORD0) : COLOR0
   5: {
   6:     return float4(InUV, 0, 1.0) + ShadingColor;
   7: }

     简单的进行颜色叠加。

     然后我们在TestEffect.uc文件中添加一个编辑器变量以便我们在运行时更改Shader参数进行测试。

   1: var() Vector ShadingColor;

     在defaultproperties块中给一个默认值:

   1: defaultproperties
   2: {
   3:     ShadingColor = (X=0.0f, Y=0.0f, Z=0.0f)
   4: }

     保存文件,在这时运行一下Editor,让EngineClass中UTestShaderEffect的声明得到更新。现在来修改UnTestPixelShader.cpp文件。

     先在FTestPixelShader类中声明一个FShaderParameter变量:

   1: FShaderParameter ShadingColorParameters;

     因为这一次我们用到了Shader参数,所以要重写FGlobalShader基类的Serialize(FArchive& Ar)方法:

   1: virtual UBOOL Serialize(FArchive& Ar)
   2: {
   3:     UBOOL bShaderHasOutdatedParameters = FShader::Serialize(Ar);
   4:     Ar << ShadingColorParameters;
   5:  
   6:     return bShaderHasOutdatedParameters;
   7: }

     然后在构造函数中绑定我们的Shader参数:

   1: FTestPixelShader(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
   2: : FGlobalShader(Initializer)
   3: {
   4:     ShadingColorParameters.Bind(Initializer.ParameterMap, TEXT("ShadingColor"), TRUE);
   5: }

     之后,在FTestEffectPostProcessSceneProxy类中定义一个用来传入Shader的变量FVector ShadingColor,在FTestEffectPostProcessSceneProxy构造函数中接收来自Post Process编辑器中用户指定的ShadingColor值。

   1: FTestEffectPostProcessSceneProx
   2: y::FTestEffectPostProcessSceneProxy(const UTestEffect* InEffect,const FPostProcessSettings* WorldSettings)
   3: : FPostProcessSceneProxy(InEffect)
   4: {
   5:     ShadingColor = InEffect->ShadingColor;
   6: }

     最后,我们需要将接收到的Shader参数实际应用到Shader中,在FTestEffectPostProcessSceneProxy::Render函数的SetGlobalBoundShaderState后面添加以下代码:

   1: SetPixelShaderValues(
   2:     TestPixelShader->GetPixelShader(),
   3:     TestPixelShader->ShadingColorParameters,
   4:     &ShadingColor,
   5:     1);

     这样,编辑器中的ShadingColor参数就和Shader文件中的ShadingColor变量建立了联系,现在启动Editor来进行测试。

     加载任意一张地图,打开内容浏览器找到上次创建TestEffect PostProcessChain,双击打开,在Post Process编辑器中选中它,我们可以发现编辑中已经可以看到我们定义的Shading Color变量了。

     随便改一下试试,比如把X改成1.0,然后将将PostProcessChain赋予场景观察结果:

B

     Bingo!运行正常~