1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 18:59:57 +00:00

Merge branch 'render_targets' into 'master'

Bind custom render targets per pass

See merge request OpenMW/openmw!1884
This commit is contained in:
psi29a 2022-05-19 11:03:02 +00:00
commit d4e2000d5b
6 changed files with 56 additions and 8 deletions

View file

@ -79,7 +79,7 @@ namespace MWLua
shader.mQueuedAction = true; shader.mQueuedAction = true;
context.mLuaManager->addAction( context.mLuaManager->addAction(
[&] { MWBase::Environment::get().getWorld()->getPostProcessor()->enableTechnique(shader.mShader, pos); }, [=] { MWBase::Environment::get().getWorld()->getPostProcessor()->enableTechnique(shader.mShader, pos); },
"Enable shader " + (shader.mShader ? shader.mShader->getName() : "nil") "Enable shader " + (shader.mShader ? shader.mShader->getName() : "nil")
); );
}; };

View file

@ -574,10 +574,11 @@ namespace MWRender
uniform->setUniform(node.mRootStateSet->getOrCreateUniform(uniform->mName, type.value())); uniform->setUniform(node.mRootStateSet->getOrCreateUniform(uniform->mName, type.value()));
} }
int subTexUnit = texUnit; std::unordered_map<osg::Texture2D*, osg::Texture2D*> renderTargetCache;
for (const auto& pass : technique->getPasses()) for (const auto& pass : technique->getPasses())
{ {
int subTexUnit = texUnit;
fx::DispatchNode::SubPass subPass; fx::DispatchNode::SubPass subPass;
pass->prepareStateSet(subPass.mStateSet, technique->getName()); pass->prepareStateSet(subPass.mStateSet, technique->getName());
@ -591,6 +592,7 @@ namespace MWRender
const auto [w, h] = rt.mSize.get(mWidth, mHeight); const auto [w, h] = rt.mSize.get(mWidth, mHeight);
subPass.mRenderTexture = new osg::Texture2D(*rt.mTarget); subPass.mRenderTexture = new osg::Texture2D(*rt.mTarget);
renderTargetCache[rt.mTarget] = subPass.mRenderTexture;
subPass.mRenderTexture->setTextureSize(w, h); subPass.mRenderTexture->setTextureSize(w, h);
subPass.mRenderTexture->setName(std::string(pass->getTarget())); subPass.mRenderTexture->setName(std::string(pass->getTarget()));
@ -600,10 +602,18 @@ namespace MWRender
subPass.mRenderTarget = new osg::FrameBufferObject; subPass.mRenderTarget = new osg::FrameBufferObject;
subPass.mRenderTarget->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(subPass.mRenderTexture)); subPass.mRenderTarget->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(subPass.mRenderTexture));
subPass.mStateSet->setAttributeAndModes(new osg::Viewport(0, 0, w, h)); subPass.mStateSet->setAttributeAndModes(new osg::Viewport(0, 0, w, h));
node.mRootStateSet->setTextureAttributeAndModes(subTexUnit, subPass.mRenderTexture);
node.mRootStateSet->addUniform(new osg::Uniform(subPass.mRenderTexture->getName().c_str(), subTexUnit++));
} }
for (const auto& whitelist : pass->getRenderTargets())
{
auto it = technique->getRenderTargetsMap().find(whitelist);
if (it != technique->getRenderTargetsMap().end() && renderTargetCache[it->second.mTarget])
{
subPass.mStateSet->setTextureAttributeAndModes(subTexUnit, renderTargetCache[it->second.mTarget]);
subPass.mStateSet->addUniform(new osg::Uniform(std::string(it->first).c_str(), subTexUnit++));
}
}
node.mPasses.emplace_back(std::move(subPass)); node.mPasses.emplace_back(std::move(subPass));
} }

View file

@ -200,6 +200,9 @@ float omw_GetPointLightRadius(int index)
for (size_t pos = header.find(define); pos != std::string::npos; pos = header.find(define)) for (size_t pos = header.find(define); pos != std::string::npos; pos = header.find(define))
header.replace(pos, define.size(), value); header.replace(pos, define.size(), value);
for (const auto& target : mRenderTargets)
header.append("uniform sampler2D " + std::string(target) + ";");
for (auto& uniform : technique.getUniformMap()) for (auto& uniform : technique.getUniformMap())
if (auto glsl = uniform->getGLSL()) if (auto glsl = uniform->getGLSL())
header.append(glsl.value()); header.append(glsl.value());

View file

@ -43,7 +43,9 @@ namespace fx
void compile(Technique& technique, std::string_view preamble); void compile(Technique& technique, std::string_view preamble);
std::string_view getTarget() const { return mTarget; } std::string getTarget() const { return mTarget; }
const std::array<std::string, 3>& getRenderTargets() const { return mRenderTargets; }
void prepareStateSet(osg::StateSet* stateSet, const std::string& name) const; void prepareStateSet(osg::StateSet* stateSet, const std::string& name) const;
@ -67,7 +69,9 @@ namespace fx
bool mUBO; bool mUBO;
bool mSupportsNormals; bool mSupportsNormals;
std::string_view mTarget; std::array<std::string, 3> mRenderTargets;
std::string mTarget;
std::optional<osg::Vec4f> mClearColor; std::optional<osg::Vec4f> mClearColor;
std::optional<osg::BlendFunc::BlendFuncMode> mBlendSource; std::optional<osg::BlendFunc::BlendFuncMode> mBlendSource;

View file

@ -822,6 +822,21 @@ namespace fx
expect<Lexer::Literal>(); expect<Lexer::Literal>();
pass->mTarget = std::get<Lexer::Literal>(mToken).value; pass->mTarget = std::get<Lexer::Literal>(mToken).value;
} }
else if (key == "rt1")
{
expect<Lexer::Literal>();
pass->mRenderTargets[0] = std::get<Lexer::Literal>(mToken).value;
}
else if (key == "rt2")
{
expect<Lexer::Literal>();
pass->mRenderTargets[1] = std::get<Lexer::Literal>(mToken).value;
}
else if (key == "rt3")
{
expect<Lexer::Literal>();
pass->mRenderTargets[2] =std::get<Lexer::Literal>(mToken).value;
}
else if (key == "blend") else if (key == "blend")
{ {
expect<Lexer::Open_Parenthesis>(); expect<Lexer::Open_Parenthesis>();

View file

@ -500,7 +500,8 @@ is not wanted and you want a custom render target.
To use the render target you must assign passes to it, along with any optional clear modes or custom blend modes. To use the render target you must assign passes to it, along with any optional clear modes or custom blend modes.
In the code snippet below a rendertarget is used to draw the red cannel of a scene at half resolution. In the code snippet below a rendertarget is used to draw the red cannel of a scene at half resolution, then a quarter. As a restriction,
only three render targets can be bound per pass with ``rt1``, ``rt2``, ``rt3``, respectively.
.. code-block:: none .. code-block:: none
@ -512,6 +513,11 @@ In the code snippet below a rendertarget is used to draw the red cannel of a sce
source_format = red; source_format = red;
} }
render_target RT_Downsample4 {
width_ratio = 0.25;
height_ratio = 0.25;
}
fragment downsample2x(target=RT_Downsample) { fragment downsample2x(target=RT_Downsample) {
omw_In vec2 omw_TexCoord; omw_In vec2 omw_TexCoord;
@ -522,6 +528,16 @@ In the code snippet below a rendertarget is used to draw the red cannel of a sce
} }
} }
fragment downsample4x(target=RT_Downsample4, rt1=RT_Downsample) {
omw_In vec2 omw_TexCoord;
void main()
{
omw_FragColor = omw_Texture2D(RT_Downsample, omw_TexCoord);
}
}
Now, if we ever run the `downsample2x` pass it will write to the target buffer instead of the default Now, if we ever run the `downsample2x` pass it will write to the target buffer instead of the default
one assigned by the engine. one assigned by the engine.