在起源引擎中主动调用 ReShade 进行后处理
需要修改的地方有 ShaderAPI_DX9
\ MaterialSystem
\ Client
这边使用的方法是, 将游戏的 client.dll
作为 ReShade 5.x 的 Addon 加载。
首先需要配置项目, 由于 ReShade 的头文件使用了 namespace reshade::api
这种定义方式, 所以需要将项目的 C++ 版本调整为 C++17 或者更新。请注意: VS2017 之后才支持 C++17。
由于 ReShade 的需要原生 D3D 的 ID3DTexture
指针, 所以修改 IShaderAPI
接口, 增加方法 GetRawTextureHandle
用于获取原生指针:
/** ishaderapi.h **/
#define SHADERAPI_INTERFACE_VERSION "ShaderApi031"
abstract_class IShaderAPI : public IShaderDynamicAPI
{
// ...
virtual void* GetRawTextureHandle( ShaderAPITextureHandle_t tex ) = 0;
};
/** shaderapidx8.h **/
class CShaderAPIDx8 : public CShaderDeviceDx8, public IShaderAPIDX8, public IDebugTextureInfo
{
// ...
IDirect3DBaseTexture* GetD3DTexture( ShaderAPITextureHandle_t hTexture );
virtual void* GetRawTextureHandle(ShaderAPITextureHandle_t tex);
// ...
};
/** shaderapidx8.cpp **/
void* CShaderAPIDx8::GetRawTextureHandle(ShaderAPITextureHandle_t tex)
{
return this->GetD3DTexture(tex);
}
随后对 ITexture 接口也做这样的操作, 同样的增加 GetRawTextureHandle
方法
/** itexture.h **/
abstract_class ITexture
{
// ...
virtual void* GetRawTextureHandle() = 0;
};
/** ctexture.cpp **/
class CReferenceToHandleTexture : public ITextureInternal
{
virtual void* GetRawTextureHandle()
{
return g_pShaderAPI->GetRawTextureHandle( m_pTextureHandles[0] );
}
}
class CTexture : public ITextureInternal
{
virtual void* GetRawTextureHandle()
{
return g_pShaderAPI->GetRawTextureHandle( m_pTextureHandles[0] );
}
}
/** mat_stub.cpp **/
class CDummyTexture : public ITexture
{
virtual void* GetRawTextureHandle() { return nullptr; }
}
随后就是在 cdll_client_int 的初始化函数中调用 reshade 的 api 注册 addon, 并且在 effect 渲染之前绑定 rendertarget 以及其他渲染用参数即可
参考:
/** reshade.h **/
#include "materialsystem/itexture.h"
namespace reshade_addon {
void init();
void init_rts(IMaterialSystem *pMaterialSystem);
extern CTextureReference opaque_texture;
extern CTextureReference depth_buffer_texture;
extern CTextureReference ui_texture;
};
/** reshade.cpp **/
#include "reshade.hpp"
#include "materialsystem/MaterialSystemUtil.h"
#include "materialsystem/itexture.h"
#include "cdll_int.h"
extern "C" __declspec(dllexport) const char* NAME = "Source Engine Client";
extern "C" __declspec(dllexport) const char* DESCRIPTION = "client.dll as module";
extern IVEngineClient* engine;
namespace reshade_addon {
using namespace reshade;
CTextureReference opaque_texture;
CTextureReference depth_buffer_texture;
CTextureReference ui_texture;
static void on_present(api::effect_runtime* runtime)
{
runtime->set_effects_state(engine->IsInGame());
}
static void on_begin_effect(api::effect_runtime* runtime, api::command_list* cmd_list, api::resource_view rtv, api::resource_view rtv_srgb)
{
if (!engine->IsInGame()) return;
#define BIND_TEXTURE(texture, name) \
if (##texture.IsValid()) \
{ \
api::resource_view rtv{ uint64_t(##texture->GetRawTextureHandle()) }; \
runtime->update_texture_bindings(name, rtv); \
}
BIND_TEXTURE(opaque_texture, "OPAQUE");
BIND_TEXTURE(depth_buffer_texture, "DEPTH");
BIND_TEXTURE(ui_texture, "UI");
}
void init_rts(IMaterialSystem* pMaterialSystem)
{
int w = 0, h = 0;
pMaterialSystem->GetBackBufferDimensions(w, h);
opaque_texture.Init(
pMaterialSystem->CreateRenderTargetTexture(
w, h,
RT_SIZE_FULL_FRAME_BUFFER, IMAGE_FORMAT_RGBA16161616F
)
);
depth_buffer_texture.Init(
pMaterialSystem->CreateRenderTargetTexture(
w, h,
RT_SIZE_FULL_FRAME_BUFFER, IMAGE_FORMAT_R32F, MATERIAL_RT_DEPTH_ONLY
)
);
ui_texture.Init(
pMaterialSystem->CreateRenderTargetTexture(
w, h,
RT_SIZE_FULL_FRAME_BUFFER, IMAGE_FORMAT_RGBA8888
)
);
}
void init()
{
register_addon(GetModuleHandleA("client.dll"));
register_event<addon_event::reshade_begin_effects>(on_begin_effect);
register_event<addon_event::reshade_present>(on_present);
}
}
/** cdll_client_int.cpp **/
int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physicsFactory, CGlobalVarsBase *pGlobals )
{
reshade_addon::init();
return true;
}
在你 client 初始化 rendertargets 的地方调用一下 reshade_addon::init_rts
然后在 viewrender.cpp 中在对应的地方设置 rendertarget 即可
这只是一种思路,仅供参考。