Hi,
I have a workspace with up to 9 background images, which are place on the top of each other for background scrolling. I have 9 hlsl and 9 glsl shaders. This is a hlsl:
Code: Select all
Texture2D backgroundMap : register(t0);
SamplerState samplerState : register(s0);
float speedX;
float speedY;
float4 main(float2 uv0 : TEXCOORD0) : SV_Target
{
// Apply scroll
uv0.x += speedX;
uv0.y += speedY;
return backgroundMap.Sample( samplerState, uv0 );
}
#version ogre_glsl_ver_330
vulkan( layout( ogre_s0 ) uniform sampler2D backgroundMap;
vulkan( layout( ogre_s0 ) uniform sampler samplerState );
vulkan_layout( location = 0 ) uniform float speedX;
vulkan_layout( location = 0 ) uniform float speedY;
vulkan_layout( location = 0 ) out vec4 fragColour;
vulkan_layout( location = 0 )
in block
{
vec2 uv0;
} inPs;
void main()
{
// Apply scroll
inPs.uv0.x += speedX;
inPs.uv0.y += speedY;
fragColour = texture( vkSampler2D( backgroundMap, samplerState ), inPs.uv0 )
}
Then I have 9 background.material files, which uses the shader and the texture. This is one of them:
Code: Select all
// GLSL shaders
fragment_program NOWABackgroundPostprocess_ps_GLSL glsl
{
source NOWABackgroundPostprocess_ps.glsl
default_params
{
param_named backgroundMap int 0
}
}
// GLSL (Vulkan) shaders
fragment_program NOWABackgroundPostprocess_ps_VK glslvk
{
source NOWABackgroundPostprocess_ps.glsl
default_params
{
param_named backgroundMap int 0
}
}
// HLSL shaders
fragment_program NOWABackgroundPostprocess_ps_HLSL hlsl
{
source NOWABackgroundPostprocess_ps.hlsl
entry_point main
target ps_5_0 ps_4_0 ps_4_0_level_9_1 ps_4_0_level_9_3
}
// Metal shaders
fragment_program NOWABackgroundPostprocess_ps_Metal metal
{
source NOWABackgroundPostprocess_ps.metal
// Because of this one, propably metal will not work, because background is just one texture and this vs is created for cube and not adapted (to complicated).
// shader_reflection_pair_hint NOWASkyPostprocess_vs_Metal
}
fragment_program NOWABackgroundPostprocess_ps unified
{
delegate NOWABackgroundPostprocess_ps_HLSL
delegate NOWABackgroundPostprocess_ps_GLSL
delegate NOWABackgroundPostprocess_ps_VK
// Causes could not find best technique crash
// delegate NOWABackgroundPostprocess_ps_Metal
}
// Material definition
material NOWABackgroundPostprocess
{
technique
{
pass
{
// https://forums.ogre3d.org/viewtopic.php?t=23280
// https://forums.ogre3d.org/viewtopic.php?f=2&t=82855&p=515294&hilit=material+scroll+texture#p515294
// scene_blend modulate
scene_blend alpha_blend
// scene_blend add
//lighting off
depth_check on
depth_write off
//
cull_hardware none
vertex_program_ref Ogre/Compositor/Quad_vs
{
}
fragment_program_ref NOWABackgroundPostprocess_ps
{
// Scroll parameters
// scroll * speed must be 1
// param_named_auto scroll time_0_x 20
param_named speedX float 0
param_named speedY float 0
}
texture_unit backgroundMap
{
texture Sky.png
alpha_op_ex add src_manual src_texture 0.1
filtering none
}
}
}
}
In C++ code I use this materials:
Code: Select all
void WorkspaceBackgroundComponent::internalCreateCompositorNode(void)
{
if (!this->compositorManager->hasNodeDefinition(this->renderingNodeName))
{
Ogre::CompositorNodeDef* compositorNodeDefinition = this->compositorManager->addNodeDefinition(this->renderingNodeName);
unsigned short numTexturesDefinitions = 0;
if (false == this->useHdr->getBool())
{
numTexturesDefinitions = 2;
}
else
{
numTexturesDefinitions = 3;
}
compositorNodeDefinition->setNumLocalTextureDefinitions(numTexturesDefinitions);
Ogre::TextureDefinitionBase::TextureDefinition* texDef = compositorNodeDefinition->addTextureDefinition("rt0");
if (this->superSampling->getReal() <= 0.0f)
{
this->superSampling->setValue(1.0f);
}
texDef->width = 0; // target_width
texDef->height = 0; // target_height
texDef->widthFactor = this->superSampling->getReal();
texDef->heightFactor = this->superSampling->getReal();
texDef->textureFlags = Ogre::TextureFlags::RenderToTexture | Ogre::TextureFlags::MsaaExplicitResolve;
// For SSAO necessary?
// texDef->format = Ogre::PFG_RGBA8_UNORM_SRGB;
texDef->format = Ogre::PFG_RGBA16_FLOAT;
if (true == this->useDistortion->getBool())
{
// texDef->depthBufferFormat = Ogre::PFG_D32_FLOAT;
// texDef->depthBufferId = 2;
// texDef->preferDepthTexture = true;
Ogre::TextureDefinitionBase::TextureDefinition* distortionTexDef = compositorNodeDefinition->addTextureDefinition("rt_distortion");
distortionTexDef->width = 0.0f; // target_width
distortionTexDef->height = 0.0f; // target_height
distortionTexDef->format = Ogre::PFG_RGBA8_UNORM_SRGB;
distortionTexDef->depthBufferFormat = Ogre::PFG_D32_FLOAT;
distortionTexDef->preferDepthTexture = true;
// Attention depth_pool?
distortionTexDef->depthBufferId = 2;
distortionTexDef->textureFlags = Ogre::TextureFlags::RenderToTexture;
}
Ogre::RenderTargetViewDef* rtv = compositorNodeDefinition->addRenderTextureView("rt0");
Ogre::RenderTargetViewEntry attachment;
attachment.textureName = "rt0";
rtv->colourAttachments.push_back(attachment);
rtv->depthBufferId = Ogre::DepthBuffer::POOL_DEFAULT;
texDef = compositorNodeDefinition->addTextureDefinition("rt1");
texDef->width = 0; // target_width
texDef->height = 0; // target_height
texDef->widthFactor = this->superSampling->getReal();
texDef->heightFactor = this->superSampling->getReal();
texDef->format = Ogre::PFG_RGBA16_FLOAT;
// texDef->msaa = this->msaaLevel;
texDef->textureFlags = Ogre::TextureFlags::RenderToTexture | Ogre::TextureFlags::MsaaExplicitResolve;
rtv = compositorNodeDefinition->addRenderTextureView("rt1");
attachment.textureName = "rt1";
rtv->colourAttachments.push_back(attachment);
rtv->depthBufferId = Ogre::DepthBuffer::POOL_DEFAULT;
if (true == this->useHdr->getBool())
{
texDef = compositorNodeDefinition->addTextureDefinition("oldLumRt");
texDef->width = 0.0f;
texDef->height = 0.0f;
texDef->format = Ogre::PFG_RGBA16_FLOAT;
texDef->textureFlags = Ogre::TextureFlags::RenderToTexture;
texDef->depthBufferId = Ogre::DepthBuffer::POOL_DEFAULT;
rtv = compositorNodeDefinition->addRenderTextureView("oldLumRt");
attachment.textureName = "oldLumRt";
rtv->colourAttachments.push_back(attachment);
rtv->depthBufferId = Ogre::DepthBuffer::POOL_NO_DEPTH;
}
if (true == this->useDistortion->getBool())
{
rtv = compositorNodeDefinition->addRenderTextureView("rt_distortion");
Ogre::RenderTargetViewEntry attachment;
attachment.textureName = "rt_distortion";
rtv->colourAttachments.push_back(attachment);
// rtv->depthBufferId = 2;
}
unsigned short numTargetPass = 1;
if (true == this->useHdr->getBool())
{
numTargetPass++;
}
if (true == this->useDistortion->getBool())
{
numTargetPass++;
}
compositorNodeDefinition->setNumTargetPass(numTargetPass);
{
Ogre::CompositorTargetDef* targetDef = compositorNodeDefinition->addTargetPass("rt0");
{
// if (true == this->canUseSplitscreen)
{
// Clear Pass
{
Ogre::CompositorPassClearDef* passClear;
auto pass = targetDef->addPass(Ogre::PASS_CLEAR);
passClear = static_cast<Ogre::CompositorPassClearDef*>(pass);
passClear->mClearColour[0] = Ogre::ColourValue(0.2f, 0.4f, 0.6f);
// passClear->setAllStoreActions(Ogre::StoreAction::Store);
passClear->mStoreActionColour[0] = Ogre::StoreAction::Store;
passClear->mStoreActionDepth = Ogre::StoreAction::Store;
passClear->mStoreActionStencil = Ogre::StoreAction::Store;
passClear->mProfilingId = "NOWA_Background_Split_Pass_Clear";
}
}
// Render Scene
{
Ogre::CompositorPassSceneDef* passScene;
auto pass = targetDef->addPass(Ogre::PASS_SCENE);
passScene = static_cast<Ogre::CompositorPassSceneDef*>(pass);
Ogre::ColourValue color(0.2f, 0.4f, 0.6f);
// passScene->setAllClearColours(color);
passScene->setAllLoadActions(Ogre::LoadAction::Clear);
passScene->mClearColour[0] = color;
// passScene->setAllStoreActions(Ogre::StoreAction::StoreOrResolve);
passScene->mStoreActionColour[0] = Ogre::StoreAction::StoreOrResolve; // Ogre::StoreAction::StoreAndMultisampleResolve; causes a crash, why?
passScene->mStoreActionDepth = Ogre::StoreAction::DontCare;
passScene->mStoreActionStencil = Ogre::StoreAction::DontCare;
passScene->mShadowNode = WorkspaceModule::getInstance()->shadowNodeName;
passScene->mFirstRQ = 0;
passScene->mLastRQ = 2;
if (true == this->usePlanarReflection->getBool())
{
// Used to identify this pass wants planar reflections
passScene->mIdentifier = 25001;
}
passScene->mProfilingId = "NOWA_Background_Before_Background_Pass_Scene";
// passScene->setAllStoreActions(Ogre::StoreAction::StoreOrResolve);
passScene->mStoreActionColour[0] = Ogre::StoreAction::StoreOrResolve;
if (true == this->canUseReflection)
{
//Our materials in this pass will be using this cubemap,
//so we need to expose it to the pass.
//Note: Even if it "just works" without exposing, the reason for
//exposing is to ensure compatibility with Vulkan & D3D12.
passScene->mExposedTextures.emplace_back(Ogre::IdString("rt1"));
}
passScene->mIncludeOverlays = false;
}
//https://forums.ogre3d.org/viewtopic.php?t=93636
//https://forums.ogre3d.org/viewtopic.php?t=94748
const Ogre::CompositorPassQuadDef::FrustumCorners corners = Ogre::CompositorPassQuadDef::NO_CORNERS;
// Background 1 quad
{
Ogre::CompositorPassQuadDef* passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = "NOWABackgroundPostprocess";
passQuad->mFrustumCorners = corners;
passQuad->mProfilingId = "NOWA_Background_1_Background_Pass_Quad";
}
// Background 2 quad
{
Ogre::CompositorPassQuadDef* passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = "NOWABackgroundPostprocess2";
passQuad->mFrustumCorners = corners;
passQuad->mProfilingId = "NOWA_Background_2_Background_Pass_Quad";
}
// Background 3 quad
{
Ogre::CompositorPassQuadDef* passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = "NOWABackgroundPostprocess3";
passQuad->mFrustumCorners = corners;
passQuad->mProfilingId = "NOWA_Background_3_Background_Pass_Quad";
}
// Background 4 quad
{
Ogre::CompositorPassQuadDef* passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = "NOWABackgroundPostprocess4";
passQuad->mFrustumCorners = corners;
passQuad->mProfilingId = "NOWA_Background_4_Background_Pass_Quad";
}
// Background 5 quad
{
Ogre::CompositorPassQuadDef* passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = "NOWABackgroundPostprocess5";
passQuad->mFrustumCorners = corners;
passQuad->mProfilingId = "NOWA_Background_5_Background_Pass_Quad";
}
// Background 6 quad
{
Ogre::CompositorPassQuadDef* passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = "NOWABackgroundPostprocess6";
passQuad->mFrustumCorners = corners;
passQuad->mProfilingId = "NOWA_Background_6_Background_Pass_Quad";
}
// Background 7 quad
{
Ogre::CompositorPassQuadDef* passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = "NOWABackgroundPostprocess7";
passQuad->mFrustumCorners = corners;
passQuad->mProfilingId = "NOWA_Background_7_Background_Pass_Quad";
}
// Background 8 quad
{
Ogre::CompositorPassQuadDef* passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = "NOWABackgroundPostprocess8";
passQuad->mFrustumCorners = corners;
passQuad->mProfilingId = "NOWA_Background_8_Background_Pass_Quad";
}
// Background 9 quad
{
Ogre::CompositorPassQuadDef* passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
passQuad->mMaterialName = "NOWABackgroundPostprocess9";
passQuad->mFrustumCorners = corners;
passQuad->mProfilingId = "NOWA_Background_9_Background_Pass_Quad";
}
// Render Scene
{
Ogre::CompositorPassSceneDef* passScene;
auto pass = targetDef->addPass(Ogre::PASS_SCENE);
passScene = static_cast<Ogre::CompositorPassSceneDef*>(pass);
passScene->mIncludeOverlays = false;
passScene->mShadowNode = WorkspaceModule::getInstance()->shadowNodeName;
passScene->mShadowNodeRecalculation = Ogre::ShadowNodeRecalculation::SHADOW_NODE_REUSE;
passScene->mFirstRQ = 2;
passScene->mProfilingId = "NOWA_Background_After_Background_Pass_Scene";
}
}
if (true == this->useHdr->getBool())
{
Ogre::CompositorTargetDef* targetDef = compositorNodeDefinition->addTargetPass("oldLumRt");
{
Ogre::CompositorPassClearDef* passClear;
auto pass = targetDef->addPass(Ogre::PASS_CLEAR);
passClear = static_cast<Ogre::CompositorPassClearDef*>(pass);
passClear->mNumInitialPasses = 1;
passClear->mClearColour[0] = Ogre::ColourValue(0.01f, 0.01f, 0.01f, 1.0f);
passClear->mProfilingId = "NOWA_Background_Hdr_Pass_Clear";
}
}
if (true == this->useDistortion->getBool())
{
Ogre::CompositorTargetDef* targetDef = compositorNodeDefinition->addTargetPass("rt_distortion");
// Render Scene for distortion
{
Ogre::CompositorPassSceneDef* passScene;
auto pass = targetDef->addPass(Ogre::PASS_SCENE);
passScene = static_cast<Ogre::CompositorPassSceneDef*>(pass);
passScene->mProfilingId = "NOWA_Background_Distortion_Pass_Scene";
passScene->setAllLoadActions(Ogre::LoadAction::Clear);
passScene->mClearColour[0] = Ogre::ColourValue(0.5f, 0.5f, 0.0f, 0.0f);
passScene->mUpdateLodLists = false;
passScene->mIncludeOverlays = false;
passScene->mFirstRQ = 16;
passScene->mLastRQ = 17;
}
this->createDistortionNode();
}
// Output channels
unsigned short outputChannel = 0;
if (false == this->useHdr->getBool())
{
outputChannel = 2;
}
else
{
outputChannel = 3;
}
if (true == this->useDistortion->getBool())
{
outputChannel++;
}
compositorNodeDefinition->setNumOutputChannels(outputChannel);
outputChannel = 0;
compositorNodeDefinition->mapOutputChannel(outputChannel++, "rt0");
compositorNodeDefinition->mapOutputChannel(outputChannel++, "rt1");
if (true == this->useHdr->getBool())
{
compositorNodeDefinition->mapOutputChannel(outputChannel++, "oldLumRt");
}
if (true == this->useDistortion->getBool())
{
compositorNodeDefinition->mapOutputChannel(outputChannel++, "rt_distortion");
}
this->createFinalRenderNode();
// For VR: disable this line and use NOWAPbsRenderingNodeVR
// this->changeViewportRect(0, this->viewportRect->getVector4());
if (true == this->externalChannels.empty())
{
this->externalChannels.resize(1);
this->externalChannels[0] = Core::getSingletonPtr()->getOgreRenderWindow()->getTexture();
}
}
if (true == this->usePlanarReflection->getBool())
{
if (false == this->compositorManager->hasNodeDefinition(this->planarReflectionReflectiveRenderingNode))
{
Ogre::CompositorNodeDef* compositorNodeDefinition = compositorManager->addNodeDefinition(this->planarReflectionReflectiveRenderingNode);
compositorNodeDefinition->addTextureSourceName("rt_renderwindow", 0, Ogre::TextureDefinitionBase::TEXTURE_INPUT);
unsigned short numTargetPass = 1;
compositorNodeDefinition->setNumTargetPass(numTargetPass);
{
Ogre::CompositorTargetDef* targetDef = compositorNodeDefinition->addTargetPass("rt_renderwindow");
{
// Render Scene
{
Ogre::CompositorPassSceneDef* passScene;
auto pass = targetDef->addPass(Ogre::PASS_SCENE);
passScene = static_cast<Ogre::CompositorPassSceneDef*>(pass);
passScene->mProfilingId = "NOWA_Background_PlanarReflection_Pass_Scene";
Ogre::ColourValue color(0.2f, 0.4f, 0.6f);
// passScene->setAllClearColours(color);
passScene->setAllLoadActions(Ogre::LoadAction::Clear);
passScene->mClearColour[0] = color;
// passScene->setAllStoreActions(Ogre::StoreAction::StoreOrResolve);
passScene->mStoreActionColour[0] = Ogre::StoreAction::StoreOrResolve; // Ogre::StoreAction::StoreAndMultisampleResolve; causes a crash, why?
passScene->mStoreActionDepth = Ogre::StoreAction::DontCare;
passScene->mStoreActionStencil = Ogre::StoreAction::DontCare;
passScene->mFirstRQ = 0;
passScene->mLastRQ = 2;
passScene->mIncludeOverlays = false;
// passScene->mVisibilityMask = 0xfffffffe;
//https://forums.ogre3d.org/viewtopic.php?t=93636
//https://forums.ogre3d.org/viewtopic.php?t=94748
passScene->mShadowNode = WorkspaceModule::getInstance()->shadowNodeName;
}
// Add background image passes
for (size_t i = 0; i < 9; i++)
{
Ogre::String strMaterialName = "NOWABackgroundPostprocess";
if (i > 0)
{
strMaterialName = "NOWABackgroundPostprocess" + Ogre::StringConverter::toString(i + 1);
}
Ogre::CompositorPassQuadDef* passQuad;
auto pass = targetDef->addPass(Ogre::PASS_QUAD);
passQuad = static_cast<Ogre::CompositorPassQuadDef*>(pass);
passQuad->mMaterialName = strMaterialName;
passQuad->mProfilingId = "NOWA_Background_Background_" + Ogre::StringConverter::toString(i) + "_Pass_Scene";
}
// Render Scene
{
Ogre::CompositorPassSceneDef* passScene;
auto pass = targetDef->addPass(Ogre::PASS_SCENE);
passScene = static_cast<Ogre::CompositorPassSceneDef*>(pass);
passScene->mIncludeOverlays = false;
passScene->mShadowNode = WorkspaceModule::getInstance()->shadowNodeName;
passScene->mShadowNodeRecalculation = Ogre::ShadowNodeRecalculation::SHADOW_NODE_REUSE;
passScene->mFirstRQ = 2;
passScene->mProfilingId = "NOWA_Background_Before_Background_Pass_Scene";
}
// Generate Mipmaps
{
Ogre::CompositorPassMipmapDef* passMipmap;
passMipmap = static_cast<Ogre::CompositorPassMipmapDef*>(targetDef->addPass(Ogre::PASS_MIPMAP));
passMipmap->mMipmapGenerationMethod = Ogre::CompositorPassMipmapDef::ComputeHQ;
passMipmap->mProfilingId = "NOWA_Background_Pass_Mipmap";
// ATTENTION: What here with splitting??
}
}
}
}
}
}
for (size_t i = 0; i < 9; i++)
{
Ogre::String strMaterialName = "NOWABackgroundPostprocess";
if (i > 0)
{
strMaterialName = "NOWABackgroundPostprocess" + Ogre::StringConverter::toString(i + 1);
}
this->materialBackgroundPtr[i] = Ogre::MaterialManager::getSingletonPtr()->getByName(strMaterialName);
if (true == this->materialBackgroundPtr[i].isNull())
{
Ogre::LogManager::getSingletonPtr()->logMessage(Ogre::LML_CRITICAL, "[WorkspaceBackgroundComponent] Could not set: " + this->workspaceName + " because the material: '" + strMaterialName + "' does not exist!");
throw Ogre::Exception(Ogre::Exception::ERR_ITEM_NOT_FOUND, "Could not create: " + this->workspaceName + " because the material: '" + strMaterialName + "' does not exist!", "NOWA");
}
Ogre::Material* material = this->materialBackgroundPtr[i].getPointer();
this->passBackground[i] = material->getTechnique(0)->getPass(0);
}
}
I control the position via:
Code: Select all
void WorkspaceBackgroundComponent::setBackgroundScrollSpeedX(unsigned short index, Ogre::Real backgroundScrollSpeedX)
{
// Threadsafe from the outside
if (nullptr != this->passBackground[index])
{
this->passBackground[index]->getFragmentProgramParameters()->setNamedConstant("speedX", backgroundScrollSpeedX);
}
}
void WorkspaceBackgroundComponent::setBackgroundScrollSpeedY(unsigned short index, Ogre::Real backgroundScrollSpeedY)
{
// Threadsafe from the outside
if (nullptr != this->passBackground[index])
{
this->passBackground[index]->getFragmentProgramParameters()->setNamedConstant("speedY", backgroundScrollSpeedY);
}
}
So the issue is: This approach is totally slow. What can that be?
Best Regards
Lax