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

240 lines
6.9 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 <OgreTechnique.h>
#include "gazebo/common/Exception.hh"
#include "gazebo/rendering/deferred_shading/GBufferSchemeHandler.hh"
using namespace gazebo;
using namespace rendering;
const std::string GBufferSchemeHandler::normal_map_pattern = "normal";
/////////////////////////////////////////////////
Ogre::Technique *GBufferSchemeHandler::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 *gBufferTech = _originalMaterial->createTechnique();
gBufferTech->removeAllPasses();
gBufferTech->setSchemeName(_schemeName);
Ogre::Technique *noGBufferTech = _originalMaterial->createTechnique();
noGBufferTech->removeAllPasses();
noGBufferTech->setSchemeName("NoGBuffer");
for (int i = 0; i < originalTechnique->getNumPasses(); ++i)
{
Ogre::Pass *originalPass = originalTechnique->getPass(i);
PassProperties props = this->InspectPass(originalPass,
_lodIndex, _rend);
if (!props.isDeferred)
{
// Just copy the technique so it gets rendered regularly
Ogre::Pass *clonePass = noGBufferTech->createPass();
*clonePass = *originalPass;
continue;
}
Ogre::Pass *newPass = gBufferTech->createPass();
MaterialGenerator::Perm perm = this->GetPermutation(props);
const Ogre::MaterialPtr &templateMat =
this->materialGenerator.GetMaterial(perm);
// We assume that the GBuffer technique contains only one pass.
*newPass = *(templateMat->getTechnique(0)->getPass(0));
this->FillPass(newPass, originalPass, props);
}
return gBufferTech;
}
/////////////////////////////////////////////////
bool GBufferSchemeHandler::CheckNormalMap(
Ogre::TextureUnitState *_tus, GBufferSchemeHandler::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
{
// TODO: Replace with gazebo exception
OGRE_EXCEPT(Ogre::Exception::ERR_DUPLICATE_ITEM,
"Multiple normal map patterns matches",
"GBufferSchemeHandler::InspectPass");
}
}
return isNormal;
}
/////////////////////////////////////////////////
GBufferSchemeHandler::PassProperties GBufferSchemeHandler::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 (int 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 GBufferSchemeHandler::GetPermutation(
const PassProperties &_props)
{
MaterialGenerator::Perm perm = 0;
switch (_props.regularTextures.size())
{
case 0:
{
perm |= GBufferMaterialGenerator::GBP_NO_TEXTURES;
if (_props.normalMap != 0)
perm |= GBufferMaterialGenerator::GBP_ONE_TEXCOORD;
else
perm |= GBufferMaterialGenerator::GBP_NO_TEXCOORDS;
break;
}
case 1:
{
perm |= GBufferMaterialGenerator::GBP_ONE_TEXTURE;
perm |= GBufferMaterialGenerator::GBP_ONE_TEXCOORD;
break;
}
case 2:
{
perm |= GBufferMaterialGenerator::GBP_TWO_TEXTURES;
// TODO : When do we use two texcoords?
perm |= GBufferMaterialGenerator::GBP_ONE_TEXCOORD;
break;
}
case 3:
{
perm |= GBufferMaterialGenerator::GBP_THREE_TEXTURES;
perm |= GBufferMaterialGenerator::GBP_ONE_TEXCOORD;
break;
}
default:
{
gzthrow("Can not generate G-Buffer materials for '>3 regular-texture'\
objects");
}
}
if (_props.isSkinned)
perm |= GBufferMaterialGenerator::GBP_SKINNED;
if (_props.normalMap != 0)
perm |= GBufferMaterialGenerator::GBP_NORMAL_MAP;
if (_props.hasDiffuseColor)
perm |= GBufferMaterialGenerator::GBP_HAS_DIFFUSE_COLOUR;
return perm;
}
/////////////////////////////////////////////////
void GBufferSchemeHandler::FillPass(
Ogre::Pass *_gBufferPass, Ogre::Pass *_originalPass,
const PassProperties &_props)
{
// Reference the correct textures. Normal map first!
int texUnitIndex = 0;
if (_props.normalMap != 0)
{
*(_gBufferPass->getTextureUnitState(texUnitIndex)) = *(_props.normalMap);
++texUnitIndex;
}
for (size_t i = 0; i < _props.regularTextures.size(); ++i)
{
*(_gBufferPass->getTextureUnitState(texUnitIndex++)) =
*(_props.regularTextures[i]);
}
_gBufferPass->setAmbient(_originalPass->getAmbient());
_gBufferPass->setDiffuse(_originalPass->getDiffuse());
_gBufferPass->setSpecular(_originalPass->getSpecular());
_gBufferPass->setShininess(_originalPass->getShininess());
_gBufferPass->setCullingMode(_originalPass->getCullingMode());
_gBufferPass->setLightingEnabled(false);
}