Hi,
I would like to handle split screens dynamically. So I would like to create in C++ a material file, and create glsl/hlsl shaders with a dynamic count of textures and geomData and write the shaders to disc.
The shaders do already work. But I'm struggling in attaching the shaders programmatically to a generated material.
This is the already working material file:
Code: Select all
fragment_program DynamicSplitTexturesShader_GLSL glsl
{
source DynamicSplitTexturesShader.glsl
default_params
{
param_named tex1 int 0
param_named tex2 int 1
}
}
fragment_program DynamicSplitTexturesShader_HLSL hlsl
{
source DynamicSplitTexturesShader.hlsl
entry_point main
target ps_5_0 ps_4_0 ps_4_0_level_9_1 ps_4_0_level_9_3
default_params
{
param_named tex1 int 0
param_named tex2 int 1
}
}
// Unified fragment program
fragment_program DynamicSplitTexturesShader unified
{
delegate DynamicSplitTexturesShader_GLSL
delegate DynamicSplitTexturesShader_HLSL
}
// Material definition
material DynamicSplitTexturesMaterial
{
technique
{
pass
{
depth_check off
depth_write off
cull_hardware none
vertex_program_ref Ogre/Compositor/Quad_vs
{
}
fragment_program_ref DynamicSplitTexturesShader
{
}
texture_unit tex1
{
filtering none
tex_address_mode clamp
}
texture_unit tex2
{
filtering none
tex_address_mode clamp
}
}
}
}
In C++ I already have things ready, but I need to set e.g.
Code: Select all
depth_check off
depth_write off
cull_hardware none
In C++ I do:
Code: Select all
Ogre::MaterialPtr material = Ogre::MaterialManager::getSingletonPtr()->create(materialName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
Ogre::Technique* technique = material->createTechnique();
Ogre::Pass* pass = technique->createPass();
Ogre::HlmsMacroblock macroblock;
macroblock.mDepthWrite = false;
macroblock.mDepthCheck = false;
macroblock.mCullMode = Ogre::CullingMode::CULL_NONE;
pass->setMacroblock(macroblock);
Or for this part:
Code: Select all
texture_unit tex1
{
filtering none
tex_address_mode clamp
}
I do:
Code: Select all
for (size_t i = 0; i < textureNames.size(); ++i)
{
Ogre::String paramName = "tex" + Ogre::StringConverter::toString(i + 1); // Match shader uniform
Ogre::TextureUnitState* texUnit = pass->createTextureUnitState(paramName);
Ogre::HlmsSamplerblock samplerblock;
samplerblock.mU = Ogre::TAM_CLAMP;
samplerblock.mV = Ogre::TAM_CLAMP;
samplerblock.mW = Ogre::TAM_CLAMP;
samplerblock.mMinFilter = Ogre::FO_NONE;
samplerblock.mMagFilter = Ogre::FO_NONE;
samplerblock.mMipFilter = Ogre::FO_NONE;
texUnit->setSamplerblock(samplerblock);
}
But I get always the error message:
Code: Select all
16:56:57: OGRE EXCEPTION(3:RenderingAPIException): Fixed Function pipeline is no longer allowed nor supported. The material DynamicSplitMaterial must use shaders in HlmsLowLevel::calculateHashFor at E:\Ogre2.2SDK\OgreMain\src\OgreHlmsLowLevel.cpp (line 173)
16:56:57: OGRE EXCEPTION(3:RenderingAPIException): Fixed Function pipeline is no longer allowed nor supported. The material DynamicSplitMaterial must use shaders in HlmsLowLevel::calculateHashFor at E:\Ogre2.2SDK\OgreMain\src\OgreHlmsLowLevel.cpp (line 173)
16:56:57: Couldn't apply datablock '[Value 0x0000012f]' to this renderable. Using default one. Check previous log messages to see if there's more information.
16:56:57: OGRE EXCEPTION(9:UnimplementedException): Trying to use slow-path on a desktop implementation. Change the RenderQueue settings. in HlmsPbs::fillBuffersFor at E:\Ogre2.2SDK\Components\Hlms\Pbs\src\OgreHlmsPbs.cpp (line 2970)
But for what?? I thought using the Ogre::Material is always for v1. I have no Idea for which object shall I change the render queue?
The next question would be:
- I also generate the shader at runtime. So I need to add textures programatically. In the material file, it does work this way:
Code: Select all
fragment_program DynamicSplitTexturesShader_HLSL hlsl
{
source DynamicSplitTexturesShader.hlsl
entry_point main
target ps_5_0 ps_4_0 ps_4_0_level_9_1 ps_4_0_level_9_3
default_params
{
param_named tex1 int 0
param_named tex2 int 1
}
}
But how can that be written in C++? How can I set e.g. both textures there in C++?
I already tried this code, but I think it will not work:
Code: Select all
Ogre::GpuProgramPtr SplitScreenComponent::loadDynamicShader(const Ogre::String& shaderFolder, const Ogre::String& shaderName, const std::vector<Ogre::String>& textureNames, const Ogre::String& shaderSyntax)
{
Ogre::GpuProgramPtr shaderProgram;
try
{
if (shaderSyntax == "GLSL" || shaderSyntax == "GLSLES")
{
shaderProgram = Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(shaderName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "glsl", Ogre::GPT_FRAGMENT_PROGRAM);
}
else if (shaderSyntax == "HLSL")
{
shaderProgram = Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(shaderName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "hlsl", Ogre::GPT_FRAGMENT_PROGRAM);
shaderProgram->setParameter("entry_point", "main");
// "ps_5_0 ps_4_0 ps_4_0_level_9_1 ps_4_0_level_9_3"
shaderProgram->setParameter("target", "ps_5_0");
}
else if (shaderSyntax == "Metal")
{
shaderProgram = Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(
shaderName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"metal", Ogre::GPT_FRAGMENT_PROGRAM);
shaderProgram->setParameter("entry_point", "main");
}
else
{
OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Unsupported shader syntax: " + shaderSyntax, "loadDynamicShader");
}
//default_params
//{
// param_named tex1 int 0 // First texture
// param_named tex2 int 1 // Second texture
//}
// Bind textures dynamically
#if 1
for (size_t i = 0; i < textureNames.size(); ++i)
{
Ogre::String paramName = "tex" + Ogre::StringConverter::toString(i + 1); // Match shader uniform
shaderProgram->setParameter(paramName, Ogre::StringConverter::toString(i));
}
#endif
Ogre::String shaderFileName = shaderName + "." + (shaderSyntax == "HLSL" ? "hlsl" : "glsl");
shaderProgram->setSourceFile(shaderFolder + "/" + shaderFileName);
shaderProgram->load();
Ogre::LogManager::getSingleton().logMessage("[loadDynamicShader] Shader successfully loaded: " + shaderName);
}
catch (const Ogre::Exception& e)
{
Ogre::LogManager::getSingleton().logMessage("[loadDynamicShader] ERROR: " + e.getFullDescription(), Ogre::LML_CRITICAL);
return shaderProgram;
}
return shaderProgram;
}
void SplitScreenComponent::createDynamicMaterial(const Ogre::String& materialName, const Ogre::String& shaderFolder, const Ogre::String& shaderName, const std::vector<Ogre::String>& textureNames,
const std::vector<Ogre::Vector4>& geometryVectors, const Ogre::String& shaderSyntax)
{
Ogre::MaterialPtr material = Ogre::MaterialManager::getSingletonPtr()->create(materialName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
Ogre::Technique* technique = material->createTechnique();
Ogre::Pass* pass = technique->createPass();
#if 0
Ogre::HlmsMacroblock macroblock;
macroblock.mDepthWrite = false;
macroblock.mDepthCheck = false;
macroblock.mCullMode = Ogre::CullingMode::CULL_NONE;
pass->setMacroblock(macroblock);
#endif
pass->setVertexProgram("Ogre/Compositor/Quad_vs");
Ogre::GpuProgramPtr fragmentShader;
#if 0
// Set shader
Ogre::GpuProgramPtr fragmentShader = Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(shaderName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
shaderSyntax == "HLSL" ? "hlsl" : "glsl", Ogre::GPT_FRAGMENT_PROGRAM);
Ogre::String shaderFileName = shaderName + "." + (shaderSyntax == "HLSL" ? "hlsl" : "glsl");
fragmentShader->setSourceFile(shaderFolder + "/" + shaderFileName);
fragmentShader->load();
pass->setFragmentProgram(fragmentShader->getName());
#else
fragmentShader = this->loadDynamicShader(shaderFolder, shaderName, textureNames, shaderSyntax);
pass->setFragmentProgram(fragmentShader->getName());
#endif
for (size_t i = 0; i < textureNames.size(); ++i)
{
Ogre::String paramName = "tex" + Ogre::StringConverter::toString(i + 1); // Match shader uniform
Ogre::TextureUnitState* texUnit = pass->createTextureUnitState(paramName);
#if 0
Ogre::HlmsSamplerblock samplerblock;
samplerblock.mU = Ogre::TAM_CLAMP;
samplerblock.mV = Ogre::TAM_CLAMP;
samplerblock.mW = Ogre::TAM_CLAMP;
samplerblock.mMinFilter = Ogre::FO_NONE;
samplerblock.mMagFilter = Ogre::FO_NONE;
samplerblock.mMipFilter = Ogre::FO_NONE;
texUnit->setSamplerblock(samplerblock);
#endif
}
// material->load();
material->compile();
// Loads dynamic shader parameters
Ogre::GpuProgramParametersSharedPtr fragmentParams = pass->getFragmentProgramParameters();
//// Bind textures dynamically
#if 0
for (size_t i = 0; i < textureNames.size(); ++i)
{
Ogre::String paramName = "tex" + Ogre::StringConverter::toString(i + 1); // Match shader uniform
if (fragmentParams->_findNamedConstantDefinition(paramName, false))
{
fragmentParams->setNamedConstant(paramName, static_cast<int>(i));
}
else
{
Ogre::LogManager::getSingleton().logMessage("[SplitScreenComponent]: Shader uniform not found: " + paramName, Ogre::LML_CRITICAL);
}
}
#endif
// Bind geometry vectors dynamically
for (size_t i = 0; i < geometryVectors.size(); ++i)
{
Ogre::String paramName = "geomData" + Ogre::StringConverter::toString(i + 1); // Match shader uniform
if (fragmentParams->_findNamedConstantDefinition(paramName, false))
{
fragmentParams->setNamedConstant(paramName, geometryVectors[i]);
}
else
{
Ogre::LogManager::getSingleton().logMessage("[SplitScreenComponent]: Shader uniform not found: " + paramName, Ogre::LML_CRITICAL);
}
}
}
I hope somebody has an idea, how to answer those 2 questions.
Best Regards
Lax