在Havok Vision 中创建后期处理效果

如果有人参考了 官方手册的教程 Tutorial: Creating Custom Post-Processing Effects
然后使用 PA 的 vGameSolutionCreator 默认设置创建项目,会发现运行报错
active renderer does not provide all buffers required by the post processor.Execute

经过debug,发现默认创建的render node 实际上是 VMobileForwardRenderingSystem
它只支持一个bufferflag 就是 VBUFFERFLAG_FINALCOLOR

让我们从头开始
postprocessing
打开 VForge 编写我们的后期处理特效,这次范例就用径向模糊(Dx9,Dx11)

打开Shader Code Editor
顶点Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <Shaders/VisionCommon.inc>

#ifdef _VISION_DX11
cbuffer g_GlobalConstantBufferObject : register (b1)
{
  float4x4 matMVP : packoffset(c4);   // model view projection matrix
}
#else
  float4x4 matMVP : register(c8);
#endif
 
struct Data_In
{
    float4 VectPos  : POSITION;
    float4 UV       : TEXCOORD0;
};

struct Data_Out
{
    float4 ProjPos  : SV_POSITION;
    float4 UV       : TEXCOORD0;
};

Data_Out vs_main( Data_In In )
{
    Data_Out output;
    output.ProjPos = mul(matMVP, In.VectPos);
    output.UV = In.UV;
    return output;
}

像素 Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <Shaders/VisionCommon.inc>

#if defined(_VISION_DX11)
Texture2D <float4> BaseTexture        : register(t0);
sampler            BaseTextureSampler : register(s0);

cbuffer g_GlobalConstantBufferObject : register (b2)
{
    float SampleDist                      : register(c0);
    float SampleStrength                  : register(c1);
}

#else
sampler2D          BaseTexture        : register(s0);
float SampleDist;
float SampleStrength;
#endif

struct Data_In
{
    float4 ProjPos  : SV_POSITION;
    float4 UV       : TEXCOORD0;
};

float4 ps_main( Data_In In ) : SV_Target
{
    float2 dir = 0.5 - In.UV;
    float dist = length(dir);
    dir /= dist;
    float4 color = vTex2D(BaseTexture, BaseTextureSampler, In.UV);
    float4 sum = color;
   
    float startValue = -0.08;
    for(int i = 0; i < 10; i++)
    {
        sum += vTex2D(BaseTexture,BaseTextureSampler,In.UV + dir * startValue * SampleDist);
        startValue += 0.3;
    }
   
    sum /= 11.0;
   
    float t = saturate(dist * SampleStrength);
   
    float4 final = lerp(color, sum, t);
   
    return final;
}

Shader Tech的名字为 RadialBlurShader 然后保存 ShaderLib
之后编写我们的 Vision Code

头文件
CustomPostProcessor.h

class CustomPostProcessor : public VPostProcessingBaseComponent
{
public:
	CustomPostProcessor(float fSampleDist = 0.5f, float fSampleStrength = 10.0f);
	virtual ~CustomPostProcessor();

	virtual void Serialize( VArchive &ar ) HKV_OVERRIDE;
	virtual void OnHandleCallback(IVisCallbackDataObject_cl *pData);

	float m_fSampleDist;
	float m_fSampleStrength;
private:
	V_DECLARE_SERIAL_DLLEXP(CustomPostProcessor,SAMPLEPLUGIN_IMPEXP);
	V_DECLARE_VARTABLE(CustomPostProcessor, SAMPLEPLUGIN_IMPEXP);
        virtual void Execute() HKV_OVERRIDE;
	void SetupContext();
	void RemoveContext();

	void CreateShaders();
	void RemoveShaders();

	//shader
	VCompiledTechniquePtr m_spCustomTechnique;
};

cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
V_IMPLEMENT_SERIAL( CustomPostProcessor, VPostProcessingBaseComponent, 0, &g_myComponentModule );

START_VAR_TABLE(CustomPostProcessor, VPostProcessingBaseComponent, "VCustomPostProcessor", 0, "")
    DEFINE_VAR_FLOAT(CustomPostProcessor, m_fSampleDist, "m_fSampleDist", "0.0", 0, "Slider(0,100)");
    DEFINE_VAR_FLOAT(CustomPostProcessor, m_fSampleStrength, "m_fSampleStrength", "0.0", 0, "Slider(0,100)");
END_VAR_TABLE

CustomPostProcessor::CustomPostProcessor( float fSampleDist /*= 0.5f*/, float fSampleStrength/* = 10.0f*/ )
:m_spCustomTechnique(NULL)
{
    m_fSampleDist = fSampleDist;
    m_fSampleStrength = fSampleStrength;

    m_iRequiredBufferFlags = VBUFFERFLAG_FINALCOLOR;

    m_fPriority = VIS_RENDERCONTEXTPRIORITY_POSTPROCESSOR_RESOLVED + 6000.0f;

    // Our post-processor covers the entire render target
    m_bufferUsageFlags = DRAWS_FULLSCREEN_QUAD;

    Vision::Callbacks.OnUpdateSceneBegin += this;
}

CustomPostProcessor::~CustomPostProcessor()
{
    Vision::Callbacks.OnUpdateSceneBegin -= this;
}

void CustomPostProcessor::Serialize( VArchive &ar )
{
    char iLocalVersion = 0;
    if(ar.IsLoading())
    {
        ar >> iLocalVersion;
        ar >> m_bActive;
        ar >> m_fSampleDist;
        ar >> m_fSampleStrength;
    }else{
        ar << iLocalVersion;
        ar << m_bActive;
        ar << m_fSampleDist;
        ar << m_fSampleStrength;
    }
}

void CustomPostProcessor::InitializePostProcessor()
{
    if(m_bIsInitialized)
    {
        return;
    }

    SetupContext();
    CreateShaders();

    m_bIsInitialized = true;
}

void CustomPostProcessor::DeInitializePostProcessor()
{
    if(!m_bIsInitialized)
    {
        return;
    }

    RemoveShaders();
    RemoveContext();

    m_bIsInitialized = false;
}

void CustomPostProcessor::Execute()
{

    VCompiledShaderPass * pPass = m_spCustomTechnique->GetShader(0);

    IVRender2DInterface *pRender = Vision::RenderLoopHelper.BeginOverlayRendering();
    Overlay2DVertex_t * pVertex = GetOwner()->GetRendererNodeHelper()->GetOverlayVertices();
    pRender->Draw2DBufferWithShader(6, pVertex, m_spSourceTextures[0], *pPass);
    Vision::RenderLoopHelper.EndOverlayRendering();
}

void CustomPostProcessor::SetupContext()
{
    VisRenderContext_cl * pTargetContext = GetTargetContext();

    pTargetContext->SetName("VCustomPostProcessor - Target Context");

    //在渲染节点中注册上下文
    GetOwner()->AddContext(pTargetContext);

    //获取纹理引用
    m_spSourceTextures[0] = GetOwner()->GetGBuffer(IVRendererNode::VGBT_Diffuse);
    m_iNumSourceTextures = 1;
}

void CustomPostProcessor::RemoveContext()
{
    m_spSourceTextures[0] = NULL;

    GetOwner()->RemoveContext(GetTargetContext());
}

void CustomPostProcessor::CreateShaders()
{
    if(Vision::Shaders.LoadShaderLibrary("\shaders\EasyGameShader.ShaderLib"))
    {
        m_spCustomTechnique = Vision::Shaders.CreateTechnique("RadialBlurShader", NULL, NULL, EFFECTCREATEFLAG_FORCEUNIQUE);
        if(m_spCustomTechnique){
            //后期渲染不需要深度
            m_spCustomTechnique->GetShader(0)->GetRenderState()->GetDepthStencilState().m_bDepthTestEnabled = false;
            m_spCustomTechnique->GetShader(0)->GetRenderState()->GetDepthStencilState().ComputeHash();
        }
    }
}

void CustomPostProcessor::RemoveShaders()
{
    m_spCustomTechnique = NULL;
}

void CustomPostProcessor::OnHandleCallback( IVisCallbackDataObject_cl *pData )
{
    if(pData->m_pSender== &Vision::Callbacks.OnUpdateSceneBegin)
    {
        if(m_spCustomTechnique){
            VCompiledShaderPass * pPass = m_spCustomTechnique->GetShader(0);
            const float * fSampleDist = &m_fSampleDist;
            const float * fSampeStrength = &m_fSampleStrength;
            pPass->GetConstantBuffer(VSS_PixelShader)->SetSingleParameterF("SampleDist", fSampleDist);
            pPass->GetConstantBuffer(VSS_PixelShader)->SetSingleParameterF("SampleStrength", fSampeStrength);
            pPass->m_bModified = true;
        }
    }
}

最后加载这个后期处理特效
在 GameManager 的 OnAfterSceneLoaded callback 中

1
2
3
CustomPostProcessor * tmp = new CustomPostProcessor(0.5f,10.0f);
Vision::Renderer.GetRendererNode(0)->AddComponent(tmp);
tmp->SetActive(true);

大功告成,运行看看吧

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.