333 lines
10 KiB
C++
333 lines
10 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 <OgrePrerequisites.h>
|
|
|
|
#include <OgreMaterialManager.h>
|
|
#include <OgreGpuProgramManager.h>
|
|
#include <OgreStringConverter.h>
|
|
#include <OgreHighLevelGpuProgramManager.h>
|
|
#include <OgreHighLevelGpuProgram.h>
|
|
#include <OgreTechnique.h>
|
|
|
|
#include "gazebo/rendering/deferred_shading/GBufferMaterialGenerator.hh"
|
|
|
|
// Use this directive to control whether you are writing
|
|
// projective (regular) or linear depth.
|
|
#define WRITE_LINEAR_DEPTH
|
|
|
|
using namespace gazebo;
|
|
using namespace rendering;
|
|
|
|
// This is the concrete implementation of the material generator.
|
|
class GBufferMaterialGeneratorImpl : public MaterialGenerator::Impl
|
|
{
|
|
public: GBufferMaterialGeneratorImpl(const Ogre::String &_baseName,
|
|
GBufferMaterialGenerator::GBufferType _type)
|
|
: baseName(_baseName), type(_type) {}
|
|
|
|
public: void SetType(GBufferMaterialGenerator::GBufferType _type)
|
|
{this->type = _type;}
|
|
|
|
protected: virtual Ogre::GpuProgramPtr GenerateVertexShader(
|
|
MaterialGenerator::Perm permutation);
|
|
protected: virtual Ogre::GpuProgramPtr GenerateFragmentShader(
|
|
MaterialGenerator::Perm permutation);
|
|
protected: virtual Ogre::MaterialPtr GenerateTemplateMaterial(
|
|
MaterialGenerator::Perm permutation);
|
|
|
|
protected: Ogre::String baseName;
|
|
private: GBufferMaterialGenerator::GBufferType type;
|
|
};
|
|
|
|
/////////////////////////////////////////////////
|
|
GBufferMaterialGenerator::GBufferMaterialGenerator(GBufferType _type)
|
|
: MaterialGenerator()
|
|
{
|
|
vsMask = VS_MASK;
|
|
fsMask = FS_MASK;
|
|
matMask = MAT_MASK;
|
|
|
|
if (_type == GBT_FAT)
|
|
{
|
|
materialBaseName = "DeferredShading";
|
|
this->schemeName = "DSGBuffer";
|
|
}
|
|
else if (_type == GBT_NORMAL_AND_DEPTH)
|
|
{
|
|
materialBaseName = "DeferredLighting";
|
|
this->schemeName = "DLGBuffer";
|
|
}
|
|
else if (_type == GBT_DSF)
|
|
{
|
|
materialBaseName = "InferredLighting";
|
|
this->schemeName = "ILGBuffer";
|
|
}
|
|
|
|
materialBaseName += "/GBuffer/";
|
|
this->impl = new GBufferMaterialGeneratorImpl(materialBaseName, _type);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
Ogre::GpuProgramPtr GBufferMaterialGeneratorImpl::GenerateVertexShader(
|
|
MaterialGenerator::Perm _permutation)
|
|
{
|
|
Ogre::StringStream ss;
|
|
uint32_t numTexCoords = (_permutation &
|
|
GBufferMaterialGenerator::GBP_TEXCOORD_MASK) >> 8;
|
|
|
|
if (_permutation & GBufferMaterialGenerator::GBP_NORMAL_MAP)
|
|
ss << "attribute vec3 tangentMap;\n";
|
|
|
|
ss << "uniform mat4 worldViewProj;\n";
|
|
ss << "uniform mat4 worldView;\n";
|
|
|
|
#ifdef WRITE_LINEAR_DEPTH
|
|
ss << "varying vec3 viewPos;\n";
|
|
#else
|
|
ss << "varying float depth;\n";
|
|
#endif
|
|
ss << "varying vec3 normal;\n";
|
|
|
|
if (_permutation & GBufferMaterialGenerator::GBP_NORMAL_MAP)
|
|
{
|
|
ss << "out vec3 tangent;\n";
|
|
ss << "out vec3 biNormal;\n";
|
|
}
|
|
|
|
ss << "void main()\n{\n";
|
|
ss << " gl_Position = worldViewProj * gl_Vertex;\n";
|
|
ss << " normal = (worldView * vec4(gl_Normal, 0.0)).xyz;\n";
|
|
|
|
if (_permutation & GBufferMaterialGenerator::GBP_NORMAL_MAP)
|
|
{
|
|
// THis is probably wrong because I copied it incorrectly
|
|
ss << " tangent = (worldView * vec4(tangentMap, 0)).xyz;\n";
|
|
ss << " biNormal = cross(normal, tangent);\n";
|
|
}
|
|
|
|
#ifdef WRITE_LINEAR_DEPTH
|
|
ss << " viewPos = (worldView * gl_Vertex).xyz;\n";
|
|
#else
|
|
ss << " depth = gl_Position.w;\n";
|
|
#endif
|
|
|
|
for (uint32_t i = 0; i < numTexCoords; ++i)
|
|
{
|
|
ss << " gl_TexCoord[" << i << "] = gl_MultiTexCoord" << i << ";\n";
|
|
}
|
|
ss << "}\n";
|
|
|
|
Ogre::String programSource = ss.str();
|
|
Ogre::String programName = this->baseName + "VP_" +
|
|
Ogre::StringConverter::toString(_permutation);
|
|
|
|
#if OGRE_DEBUG_MODE
|
|
Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(programSource);
|
|
#endif
|
|
|
|
// Create shader object
|
|
Ogre::HighLevelGpuProgramPtr ptrProgram =
|
|
Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(
|
|
programName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
|
"glsl", Ogre::GPT_VERTEX_PROGRAM);
|
|
|
|
ptrProgram->setSource(programSource);
|
|
|
|
const Ogre::GpuProgramParametersSharedPtr ¶ms =
|
|
ptrProgram->getDefaultParameters();
|
|
params->setNamedAutoConstant("worldViewProj",
|
|
Ogre::GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
|
params->setNamedAutoConstant("worldView",
|
|
Ogre::GpuProgramParameters::ACT_WORLDVIEW_MATRIX);
|
|
ptrProgram->load();
|
|
|
|
return Ogre::GpuProgramPtr(ptrProgram);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
Ogre::GpuProgramPtr GBufferMaterialGeneratorImpl::GenerateFragmentShader(
|
|
MaterialGenerator::Perm _permutation)
|
|
{
|
|
Ogre::StringStream ss;
|
|
|
|
uint32_t numTexCoords =
|
|
(_permutation & GBufferMaterialGenerator::GBP_TEXCOORD_MASK) >> 8;
|
|
uint32_t numTextures =
|
|
_permutation & GBufferMaterialGenerator::GBP_TEXTURE_MASK;
|
|
|
|
if (_permutation & GBufferMaterialGenerator::GBP_NORMAL_MAP)
|
|
ss << "uniform sampler2D normalMap;\n";
|
|
|
|
if (this->type == GBufferMaterialGenerator::GBT_FAT)
|
|
{
|
|
for (uint32_t i = 0; i < numTextures; ++i)
|
|
ss << "uniform sampler2D tex" << i << ";\n";
|
|
}
|
|
|
|
if (numTextures == 0 ||
|
|
_permutation & GBufferMaterialGenerator::GBP_HAS_DIFFUSE_COLOUR)
|
|
{
|
|
if (this->type == GBufferMaterialGenerator::GBT_FAT)
|
|
ss << "uniform vec4 diffuseColor;\n";
|
|
}
|
|
|
|
#ifdef WRITE_LINEAR_DEPTH
|
|
ss << "uniform float farDistance;\n";
|
|
#endif
|
|
|
|
if (this->type == GBufferMaterialGenerator::GBT_FAT)
|
|
ss << "uniform float specularity;\n";
|
|
else if (this->type == GBufferMaterialGenerator::GBT_DSF)
|
|
ss << "uniform vec4 objectId;\n";
|
|
|
|
#ifdef WRITE_LINEAR_DEPTH
|
|
ss << "varying vec3 viewPos;\n";
|
|
#else
|
|
ss << "varying float depth;\n";
|
|
#endif
|
|
ss << "varying vec3 normal;\n";
|
|
|
|
if (_permutation & GBufferMaterialGenerator::GBP_NORMAL_MAP)
|
|
{
|
|
ss << "varying vec3 tangent;\n";
|
|
ss << "varying vec3 biNormal;\n";
|
|
}
|
|
|
|
ss << "void main()\n{\n";
|
|
|
|
if (this->type == GBufferMaterialGenerator::GBT_FAT)
|
|
{
|
|
if (numTexCoords > 0 && numTextures > 0)
|
|
{
|
|
ss << " gl_FragData[1].xyz = texture2D(tex0, gl_TexCoord[0].st);\n";
|
|
if (_permutation & GBufferMaterialGenerator::GBP_HAS_DIFFUSE_COLOUR)
|
|
ss << " gl_FragData[1].xyz *= diffuseColor.xyz;\n";
|
|
}
|
|
else
|
|
{
|
|
ss << " gl_FragData[1].xyz = diffuseColor.xyz;\n";
|
|
}
|
|
ss << " gl_FragData[1].w = specularity;\n";
|
|
}
|
|
|
|
|
|
if (_permutation & GBufferMaterialGenerator::GBP_NORMAL_MAP)
|
|
{
|
|
ss << " vec3 texNormal = "
|
|
<< "texture2D(normalMap, gl_TexCoord[0].st) - 0.5) * 2.0;\n";
|
|
ss << " mat3 normalRotation = mat3(tangent, biNormal, normal);\n";
|
|
ss << " gl_FragData[0].xyz = normalize(texNormal * normalRotation);\n";
|
|
}
|
|
else
|
|
{
|
|
ss << " gl_FragData[0].xyz = normalize(normal);\n";
|
|
}
|
|
|
|
#ifdef WRITE_LINEAR_DEPTH
|
|
ss << " gl_FragData[0].w = length(viewPos) / farDistance;\n";
|
|
#else
|
|
ss << " gl_FragData[0].w = depth;\n";
|
|
#endif
|
|
|
|
if (this->type == GBufferMaterialGenerator::GBT_DSF)
|
|
{
|
|
ss << " vec3 norm = normalize(normal);\n";
|
|
ss << " gl_FragData[1].x = length(viewPos) / farDistance;\n";
|
|
ss << " gl_FragData[1].y = objectId.r;\n";
|
|
ss << " gl_FragData[1].z = normal.x;\n";
|
|
ss << " gl_FragData[1].w = normal.y;\n";
|
|
}
|
|
|
|
ss << "}\n";
|
|
|
|
Ogre::String programSource = ss.str();
|
|
Ogre::String programName = this->baseName + "FP_" +
|
|
Ogre::StringConverter::toString(_permutation);
|
|
|
|
#if OGRE_DEBUG_MODE
|
|
Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(programSource);
|
|
#endif
|
|
|
|
// Create shader object
|
|
Ogre::HighLevelGpuProgramPtr ptrProgram =
|
|
Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(
|
|
programName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
|
"glsl", Ogre::GPT_FRAGMENT_PROGRAM);
|
|
|
|
ptrProgram->setSource(programSource);
|
|
|
|
const Ogre::GpuProgramParametersSharedPtr ¶ms =
|
|
ptrProgram->getDefaultParameters();
|
|
|
|
if (this->type == GBufferMaterialGenerator::GBT_FAT)
|
|
{
|
|
params->setNamedAutoConstant("specularity",
|
|
Ogre::GpuProgramParameters::ACT_SURFACE_SHININESS);
|
|
|
|
if (numTextures == 0 ||
|
|
_permutation & GBufferMaterialGenerator::GBP_HAS_DIFFUSE_COLOUR)
|
|
{
|
|
params->setNamedAutoConstant("diffuseColor",
|
|
Ogre::GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
|
}
|
|
}
|
|
|
|
if (this->type == GBufferMaterialGenerator::GBT_DSF)
|
|
{
|
|
params->setNamedAutoConstant("objectId",
|
|
Ogre::GpuProgramParameters::ACT_CUSTOM, 0);
|
|
}
|
|
|
|
#ifdef WRITE_LINEAR_DEPTH
|
|
// TODO : Should this be the distance to the far corner,
|
|
// not the far clip distance?
|
|
params->setNamedAutoConstant("farDistance",
|
|
Ogre::GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
|
|
#endif
|
|
|
|
ptrProgram->load();
|
|
return Ogre::GpuProgramPtr(ptrProgram);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
Ogre::MaterialPtr GBufferMaterialGeneratorImpl::GenerateTemplateMaterial(
|
|
MaterialGenerator::Perm _permutation)
|
|
{
|
|
Ogre::String matName = this->baseName + "Mat_" +
|
|
Ogre::StringConverter::toString(_permutation);
|
|
|
|
Ogre::MaterialPtr matPtr = Ogre::MaterialManager::getSingleton().create
|
|
(matName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
|
|
|
Ogre::Pass *pass = matPtr->getTechnique(0)->getPass(0);
|
|
pass->setName(this->baseName + "Pass_" +
|
|
Ogre::StringConverter::toString(_permutation));
|
|
pass->setLightingEnabled(false);
|
|
|
|
if (_permutation & GBufferMaterialGenerator::GBP_NORMAL_MAP)
|
|
pass->createTextureUnitState();
|
|
|
|
uint32_t numTextures = _permutation &
|
|
GBufferMaterialGenerator::GBP_TEXTURE_MASK;
|
|
|
|
for (uint32_t i = 0; i < numTextures; ++i)
|
|
pass->createTextureUnitState();
|
|
|
|
return matPtr;
|
|
}
|