pxmlw6n2f/Gazebo_Distributed_TCP/gazebo/rendering/deferred_shading/MergeSchemeHandler.cc

264 lines
8.2 KiB
C++

/*
* Copyright (C) 2012 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <OgreMaterialManager.h>
#include <OgreTechnique.h>
#include "gazebo/rendering/deferred_shading/MergeSchemeHandler.hh"
using namespace gazebo;
using namespace rendering;
// The merge pass doesn't necesarily need normals, since they can be
// retreived from the GBuffer. However, getting them from the input stream is
// faster, and allows us to ignore the GBuffer completely in this step(less
// texture sampling is the whole purpose of this technique).
const std::string MergeSchemeHandler::normal_map_pattern = "normal";
/////////////////////////////////////////////////
Ogre::Technique *MergeSchemeHandler::handleSchemeNotFound(
uint16_t /*_schemeIndex*/, const Ogre::String &_schemeName,
Ogre::Material *_originalMaterial, uint16_t _lodIndex,
const Ogre::Renderable *_rend)
{
Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton();
Ogre::String curSchemeName = matMgr.getActiveScheme();
matMgr.setActiveScheme(Ogre::MaterialManager::DEFAULT_SCHEME_NAME);
Ogre::Technique *originalTechnique =
_originalMaterial->getBestTechnique(_lodIndex, _rend);
matMgr.setActiveScheme(curSchemeName);
Ogre::Technique *mergeTech = _originalMaterial->createTechnique();
mergeTech->removeAllPasses();
mergeTech->setSchemeName(_schemeName);
Ogre::Technique *noMergeTech = _originalMaterial->createTechnique();
noMergeTech->removeAllPasses();
// objects that don't render in the GBuffer, won't need to be merged
noMergeTech->setSchemeName("NoGBuffer");
for (uint16_t i = 0; i < originalTechnique->getNumPasses(); ++i)
{
Ogre::Pass *originalPass = originalTechnique->getPass(i);
PassProperties props = InspectPass(originalPass, _lodIndex, _rend);
if (!props.isDeferred)
{
// Just copy the technique so it gets rendered regularly
Ogre::Pass *clonePass = noMergeTech->createPass();
*clonePass = *originalPass;
continue;
}
Ogre::Pass *newPass = mergeTech->createPass();
MaterialGenerator::Perm perm = this->GetPermutation(props);
const Ogre::MaterialPtr &templateMat =
this->materialGenerator->GetMaterial(perm);
// We assume that the Merge technique contains only one pass. But its true.
*newPass = *(templateMat->getTechnique(0)->getPass(0));
this->FillPass(newPass, originalPass, props);
}
return mergeTech;
}
/////////////////////////////////////////////////
bool MergeSchemeHandler::CheckNormalMap(Ogre::TextureUnitState *_tus,
MergeSchemeHandler::PassProperties &_props)
{
bool isNormal = false;
Ogre::String lowerCaseAlias = _tus->getTextureNameAlias();
Ogre::StringUtil::toLowerCase(lowerCaseAlias);
if (lowerCaseAlias.find(normal_map_pattern) != Ogre::String::npos)
isNormal = true;
else
{
Ogre::String lowerCaseName = _tus->getTextureName();
Ogre::StringUtil::toLowerCase(lowerCaseName);
if (lowerCaseName.find(normal_map_pattern) != Ogre::String::npos)
isNormal = true;
}
if (isNormal)
{
if (_props.normalMap == 0)
_props.normalMap = _tus;
else
{
OGRE_EXCEPT(Ogre::Exception::ERR_DUPLICATE_ITEM,
"Multiple normal map patterns matches",
"MergeSchemeHandler::inspectPass");
}
}
return isNormal;
}
/////////////////////////////////////////////////
MergeSchemeHandler::PassProperties MergeSchemeHandler::InspectPass(
Ogre::Pass *_pass, uint16_t /*_lodIndex*/,
const Ogre::Renderable * /*_rend*/)
{
PassProperties props;
// TODO : Use renderable to indicate wether this has skinning.
// Probably use same const cast that renderSingleObject uses.
if (_pass->hasVertexProgram())
props.isSkinned = _pass->getVertexProgram()->isSkeletalAnimationIncluded();
else
props.isSkinned = false;
for (uint16_t i = 0; i < _pass->getNumTextureUnitStates(); ++i)
{
Ogre::TextureUnitState *tus = _pass->getTextureUnitState(i);
if (!this->CheckNormalMap(tus, props))
props.regularTextures.push_back(tus);
if (tus->getEffects().size() > 0)
props.isDeferred = false;
}
if (_pass->getDiffuse() != Ogre::ColourValue::White)
{
props.hasDiffuseColor = true;
}
// Check transparency
if (_pass->getDestBlendFactor() != Ogre::SBF_ZERO)
{
// TODO : Better ways to do this
props.isDeferred = false;
}
return props;
}
/////////////////////////////////////////////////
MaterialGenerator::Perm MergeSchemeHandler::GetPermutation(
const PassProperties &_props)
{
MaterialGenerator::Perm perm = 0;
switch (_props.regularTextures.size())
{
case 0:
{
perm |= MergeMaterialGenerator::MP_NO_TEXTURES;
if (_props.normalMap != 0)
perm |= MergeMaterialGenerator::MP_ONE_TEXCOORD;
else
perm |= MergeMaterialGenerator::MP_NO_TEXCOORDS;
break;
}
case 1:
{
perm |= MergeMaterialGenerator::MP_ONE_TEXTURE;
perm |= MergeMaterialGenerator::MP_ONE_TEXCOORD;
break;
}
case 2:
{
perm |= MergeMaterialGenerator::MP_TWO_TEXTURES;
// TODO : When do we use two texcoords?
perm |= MergeMaterialGenerator::MP_ONE_TEXCOORD;
break;
}
case 3:
{
perm |= MergeMaterialGenerator::MP_THREE_TEXTURES;
perm |= MergeMaterialGenerator::MP_ONE_TEXCOORD;
break;
}
default:
{
OGRE_EXCEPT(Ogre::Exception::ERR_NOT_IMPLEMENTED,
"Can not generate Merge materials for '>3 regular-texture' objects",
"MergeSchemeHandler::inspectPass");
}
}
if (_props.isSkinned)
perm |= MergeMaterialGenerator::MP_SKINNED;
if (_props.normalMap != 0)
perm |= MergeMaterialGenerator::MP_NORMAL_MAP;
if (_props.hasDiffuseColor)
perm |= MergeMaterialGenerator::MP_HAS_DIFFUSE_COLOUR;
return perm;
}
/////////////////////////////////////////////////
void MergeSchemeHandler::FillPass(Ogre::Pass *_mergePass,
Ogre::Pass *_originalPass, const PassProperties &_props)
{
// Reference the correct textures. Normal map first!
int texUnitIndex = 0;
if (_props.normalMap != 0)
{
*(_mergePass->getTextureUnitState(texUnitIndex)) = *(_props.normalMap);
texUnitIndex++;
}
for (size_t i = 0; i < _props.regularTextures.size(); ++i)
{
*(_mergePass->getTextureUnitState(texUnitIndex)) =
*(_props.regularTextures[i]);
++texUnitIndex;
}
// Use the LBuffer as an input
_mergePass->getTextureUnitState(texUnitIndex)->setContentType(
Ogre::TextureUnitState::CONTENT_COMPOSITOR);
_mergePass->getTextureUnitState(texUnitIndex)->setCompositorReference(
this->techName + "/ShowLit", "LBuffer");
_mergePass->getTextureUnitState(texUnitIndex)->setDesiredFormat(
Ogre::PF_FLOAT16_RGBA);
_mergePass->getTextureUnitState(texUnitIndex)->setTextureFiltering(
Ogre::TFO_NONE);
++texUnitIndex;
// If we're using inferred lighting, handle the extra GBuffer input
if (this->useDSF)
{
_mergePass->getTextureUnitState(texUnitIndex)->setContentType(
Ogre::TextureUnitState::CONTENT_COMPOSITOR);
_mergePass->getTextureUnitState(texUnitIndex)->setCompositorReference(
this->techName + "/GBuffer", "mrt_output", 1);
_mergePass->getTextureUnitState(texUnitIndex)->setTextureFiltering(
Ogre::TFO_NONE);
_mergePass->getTextureUnitState(texUnitIndex)->setDesiredFormat(
Ogre::PF_FLOAT16_RGBA);
}
_mergePass->setAmbient(_originalPass->getAmbient());
_mergePass->setDiffuse(_originalPass->getDiffuse());
_mergePass->setSpecular(_originalPass->getSpecular());
_mergePass->setShininess(_originalPass->getShininess());
_mergePass->setCullingMode(_originalPass->getCullingMode());
_mergePass->setLightingEnabled(false);
}