mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 21:59:55 +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:
commit
d4e2000d5b
6 changed files with 56 additions and 8 deletions
|
@ -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")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue