661 lines
25 KiB
C++
661 lines
25 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 <OgreGpuProgramManager.h>
|
|
#include <OgreStringConverter.h>
|
|
#include <OgreHighLevelGpuProgramManager.h>
|
|
#include <OgreHighLevelGpuProgram.h>
|
|
#include <OgreTechnique.h>
|
|
#include <OgreTextureUnitState.h>
|
|
|
|
#include "gazebo/rendering/deferred_shading/MergeMaterialGenerator.hh"
|
|
|
|
using namespace gazebo;
|
|
using namespace rendering;
|
|
|
|
/// This is the concrete implementation of the material generator.
|
|
class MergeMaterialGeneratorImpl : public MaterialGenerator::Impl
|
|
{
|
|
public:
|
|
MergeMaterialGeneratorImpl(const Ogre::String &_baseName, bool _useDSF)
|
|
: baseName(_baseName), useDSF(_useDSF) {}
|
|
|
|
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: bool useDSF;
|
|
};
|
|
|
|
/////////////////////////////////////////////////
|
|
MergeMaterialGenerator::MergeMaterialGenerator(Ogre::String _matName,
|
|
bool _useDSF)
|
|
{
|
|
this->vsMask = VS_MASK;
|
|
this->fsMask = FS_MASK;
|
|
this->matMask = MAT_MASK;
|
|
materialBaseName = _matName + "/Merge/";
|
|
this->impl = new MergeMaterialGeneratorImpl(materialBaseName, _useDSF);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
Ogre::GpuProgramPtr MergeMaterialGeneratorImpl::GenerateVertexShader(
|
|
MaterialGenerator::Perm _permutation)
|
|
{
|
|
Ogre::StringStream ss;
|
|
|
|
uint32_t numTexCoords =
|
|
(_permutation & MergeMaterialGenerator::MP_TEXCOORD_MASK) >> 8;
|
|
|
|
ss << "uniform mat4 worldViewProj;\n";
|
|
ss << "uniform mat4 worldView;\n";
|
|
|
|
if (_permutation & MergeMaterialGenerator::MP_NORMAL_MAP)
|
|
{
|
|
ss << "attribute vec3 iTangent;\n";
|
|
ss << "varying vec3 tangent;\n";
|
|
ss << "varying vec3 biNormal;\n";
|
|
}
|
|
|
|
if (this->useDSF)
|
|
ss << "varying vec3 viewPos;\n";
|
|
|
|
ss << "varying vec3 normal;\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 & MergeMaterialGenerator::MP_NORMAL_MAP )
|
|
{
|
|
ss << " tangent = mul(worldView, vec4(iTangent, 0.0)).xyz;\n";
|
|
ss << " biNormal = cross(normal, tangent);\n";
|
|
}
|
|
|
|
for (uint32_t i = 0; i < numTexCoords; ++i)
|
|
ss << "gl_TexCoord[" << i << "] = gl_MultiTexCoord" << i << ";\n";
|
|
|
|
if (this->useDSF)
|
|
ss << " viewPos = (worldView * gl_Vertex).xyz;\n";
|
|
|
|
ss << "}\n";
|
|
|
|
Ogre::String programSource = ss.str();
|
|
|
|
std::cout << programSource << "\n";
|
|
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 MergeMaterialGeneratorImpl::GenerateFragmentShader(
|
|
MaterialGenerator::Perm _permutation)
|
|
{
|
|
Ogre::StringStream ss;
|
|
|
|
// comparison thresholds for Inferred Lighting. The thresholds are
|
|
// a compromise between getting aliased edges, and getting blocky
|
|
// illumination due to pixel-sized details offseting the comparison
|
|
if (this->useDSF)
|
|
{
|
|
ss << "#define depth_epsilon 0.001\n";
|
|
ss << "#define normal_epsilon 0.2\n";
|
|
}
|
|
|
|
// use the pixel position to index the LBuffer; this is more precise than
|
|
// computing tex coords based on the view matrix(it's slightly more expensive
|
|
// as well).
|
|
if (this->useDSF)
|
|
{
|
|
ss << "uniform float farDistance;\n";
|
|
ss << "uniform half objectId;\n";
|
|
ss << "varying vec3 viewPos;\n";
|
|
}
|
|
|
|
|
|
if (_permutation & MergeMaterialGenerator::MP_NORMAL_MAP)
|
|
{
|
|
ss << "uniform sampler2D normalMap;\n";
|
|
ss << "varying vec3 tanget;\n";
|
|
ss << "varying vec3 biNormal;\n";
|
|
}
|
|
|
|
uint32_t numTextures = _permutation & MergeMaterialGenerator::MP_TEXTURE_MASK;
|
|
uint32_t numTexCoords = (_permutation &
|
|
MergeMaterialGenerator::MP_TEXCOORD_MASK) >> 8;
|
|
|
|
for (uint32_t i = 0; i < numTextures; ++i)
|
|
ss << "uniform sampler2D tex" << i << ";\n";
|
|
|
|
ss << "uniform sampler2D LBuffer;\n";
|
|
|
|
if (this->useDSF)
|
|
ss << "uniform sampler2D DSFBuffer;\n";
|
|
|
|
if (numTextures == 0 ||
|
|
_permutation & MergeMaterialGenerator::MP_HAS_DIFFUSE_COLOUR)
|
|
ss << "uniform vec4 diffuseColor;\n";
|
|
|
|
ss << "uniform float specularity;\n";
|
|
ss << "uniform float height;\n";
|
|
ss << "uniform float width;\n";
|
|
ss << "uniform float flip;\n";
|
|
|
|
ss << "varying vec3 normal;\n";
|
|
|
|
ss << "void main()\n{\n";
|
|
|
|
ss << " vec2 pixpos = gl_FragCoord.xy * vec2(1.0, -flip);\n";
|
|
|
|
if (this->useDSF)
|
|
ss << " vec2 LBuffpos_frac = frac(pixpos * 0.75);\n";
|
|
|
|
ss << " pixpos.x /= width;\n";
|
|
ss << " pixpos.y /= height;\n";
|
|
|
|
if (this->useDSF)
|
|
{
|
|
/// calculate sample positions in order to reconstruct bilinear filtering
|
|
ss << " float depth = length(viewPos) / farDistance;\n";
|
|
ss << " vec2 sample0 = vec2(+1.0/width, -1.0/height) / (2.0 * 0.75);\n";
|
|
ss << " vec2 sample1 = vec2(-1.0/width, -1.0/height) / (2.0 * 0.75);\n";
|
|
ss << " vec2 sample2 = vec2(+1.0/width, +1.0/height) / (2.0 * 0.75);\n";
|
|
ss << " vec2 sample3 = vec2(-1.0/width, +1.0/height) / (2.0 * 0.75);\n";
|
|
|
|
// get the values of the Discontinuity Sensible Filter
|
|
ss << " vec4 DSF0 = texture2D(DSFBuffer, pixpos + sample0);\n";
|
|
ss << " vec4 DSF1 = texture2D(DSFBuffer, pixpos + sample1);\n";
|
|
ss << " vec4 DSF2 = texture2D(DSFBuffer, pixpos + sample2);\n";
|
|
ss << " vec4 DSF3 = texture2D(DSFBuffer, pixpos + sample3);\n";
|
|
|
|
// normalize the input normal for proper comparison
|
|
ss << " vec3 normal = normalize(normal);\n";
|
|
|
|
// get the usual bilinear interpolation weights
|
|
ss << " vec4 w = vec4((1.0 - LBuffpos_frac.x) * (1.0 - LBuffpos_frac.y),\n"
|
|
<< " LBuffpos_frac.x * (1.0 - LBuffpos_frac.y),\n"
|
|
<< " (1.0 - LBuffpos_frac.x) * LBuffpos_frac.y,\n"
|
|
<< " LBuffpos_frac.x * LBuffpos_frac.y);\n";
|
|
|
|
// see if each sample is on the same surface or not
|
|
ss << " float w0 =\n"
|
|
<< "clamp(100.0 * (depth_epsilon - abs(depth - DSF0.x)), 0.0, 1.0) * "
|
|
<< "clamp((1.0 - 1000.0 * abs(DSF0.y - objectId)), 0.0, 1.0) * "
|
|
<< "clamp(1000.0 * (normal_epsilon - abs(normal.x - DSF0.z)), 0.0, 1.0)*"
|
|
<< "clamp(1000.0 * (normal_epsilon - abs(normal.y - DSF0.w)), 0.0, 1.0);"
|
|
<< std::endl;
|
|
|
|
ss << " float w1 =\n"
|
|
<< "clamp(100.0 * (depth_epsilon - abs(depth - DSF1.x)), 0.0, 1.0) *"
|
|
<< "clamp((1.0 - 1000.0 * abs(DSF1.y - objectId)), 0.0, 1.0) *"
|
|
<< "clamp(1000.0 * (normal_epsilon - abs(normal.x - DSF1.z)), 0.0, 1.0)*"
|
|
<< "clamp(1000.0 * (normal_epsilon - abs(normal.y - DSF1.w)));\n";
|
|
|
|
ss << " float w2 =\n"
|
|
<< "clamp(100.0 * (depth_epsilon - abs(depth - DSF2.x)), 0.0, 1.0) *"
|
|
<< "clamp((1.0 - 1000.0 * abs(DSF2.y - objectId)), 0.0, 1.0) *"
|
|
<< "clamp(1000.0 * (normal_epsilon - abs(normal.x - DSF2.z))) *"
|
|
<< "clamp(1000.0 * (normal_epsilon - abs(normal.y - DSF2.w)));\n";
|
|
|
|
ss << " float w3 =\n"
|
|
<< "clamp(100.0 * (depth_epsilon - abs(depth - DSF3.x)),0.0, 1.0) *"
|
|
<< "clamp((1.0 - 1000.0 * abs(DSF3.y - objectId)), 0.0, 1.0) *"
|
|
<< "clamp(1000.0 * (normal_epsilon-abs(normal.x - DSF3.z)), 0.0, 1.0)*"
|
|
<< "clamp(1000.0 * (normal_epsilon - abs(normal.y - DSF3.w)));\n";
|
|
|
|
// TODO: find a better way to check if at least a sample is on the surface
|
|
ss <<" if (w0 + w1 + w2 + w3 > 0)\n";
|
|
// bias bilinear filtering
|
|
ss <<" w *= vec4(w0, w1, w2, w3);\n";
|
|
|
|
// get the light's value
|
|
ss << "vec4 lightVal =\n"
|
|
<< " (w.x * texture2D(LBuffer, pixpos + sample0) +"
|
|
<< " w.y * texture2D(LBuffer, pixpos + sample1) +"
|
|
<< " w.z * texture2D(LBuffer, pixpos + sample2) +"
|
|
<< " w.w * texture2D(LBuffer, pixpos + sample3)) / "
|
|
<< " (w.x + w.y + w.z + w.w);\n";
|
|
}
|
|
else
|
|
{
|
|
ss << " vec4 lightVal = texture2D(LBuffer, pixpos);\n";
|
|
}
|
|
|
|
ss << " vec3 diffuseCol;\n";
|
|
|
|
if (numTexCoords > 0 && numTextures > 0)
|
|
{
|
|
ss << " diffuseCol = texture2D(tex0, gl_TexCoord[0].xy).xyz;\n";
|
|
if (_permutation & MergeMaterialGenerator::MP_HAS_DIFFUSE_COLOUR)
|
|
{
|
|
ss << " diffuseCol *= diffuseColor.xyz;\n";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ss << " diffuseCol = diffuseColor.xyz;\n";
|
|
}
|
|
|
|
// use the luminance as an aproximation of the intensity of the
|
|
// NL*attenuation term
|
|
ss << " float luminance = dot(lightVal.xyz,vec3(0.2126, 0.7152, 0.0722));\n";
|
|
|
|
// reconstruct HV^n_light based on that, and get the specular term
|
|
ss << " vec3 specular = diffuseCol * max(0.0, pow(lightVal.w / luminance, "
|
|
<< "1.0 + specularity));\n";
|
|
|
|
// get the final lighting value
|
|
ss << " gl_FragColor = vec4(lightVal.xyz * (diffuseCol + specular), 1.0);\n";
|
|
ss << "}\n";
|
|
|
|
Ogre::String programSource = ss.str();
|
|
Ogre::String programName = this->baseName + "FP_" +
|
|
Ogre::StringConverter::toString(_permutation);
|
|
|
|
std::cout << programSource << "\n";
|
|
#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();
|
|
|
|
uint32_t texIndex = 0;
|
|
for (; texIndex < numTextures; ++texIndex)
|
|
{
|
|
std::ostringstream stream;
|
|
stream << "tex" << texIndex;
|
|
params->setNamedConstant(stream.str(), static_cast<int>(texIndex));
|
|
}
|
|
|
|
params->setNamedConstant("LBuffer", static_cast<int>(texIndex));
|
|
|
|
if (numTextures == 0 || _permutation &
|
|
MergeMaterialGenerator::MP_HAS_DIFFUSE_COLOUR)
|
|
{
|
|
params->setNamedAutoConstant("diffuseColor",
|
|
Ogre::GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
|
}
|
|
|
|
params->setNamedAutoConstant("specularity",
|
|
Ogre::GpuProgramParameters::ACT_SURFACE_SHININESS);
|
|
// params->setNamedAutoConstant("specularColor",
|
|
// Ogre::GpuProgramParameters::ACT_SURFACE_SPECULAR_COLOUR);
|
|
params->setNamedAutoConstant("width",
|
|
Ogre::GpuProgramParameters::ACT_VIEWPORT_WIDTH);
|
|
params->setNamedAutoConstant("height",
|
|
Ogre::GpuProgramParameters::ACT_VIEWPORT_HEIGHT);
|
|
params->setNamedAutoConstant("flip",
|
|
Ogre::GpuProgramParameters::ACT_RENDER_TARGET_FLIPPING);
|
|
|
|
if (this->useDSF)
|
|
{
|
|
params->setNamedAutoConstant("farDistance",
|
|
Ogre::GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
|
|
params->setNamedAutoConstant("objectId",
|
|
Ogre::GpuProgramParameters::ACT_CUSTOM, 0);
|
|
}
|
|
|
|
ptrProgram->load();
|
|
|
|
return Ogre::GpuProgramPtr(ptrProgram);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
Ogre::MaterialPtr MergeMaterialGeneratorImpl::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 & MergeMaterialGenerator::MP_NORMAL_MAP)
|
|
pass->createTextureUnitState();
|
|
|
|
uint32_t numTextures = _permutation &
|
|
MergeMaterialGenerator::MP_TEXTURE_MASK;
|
|
|
|
for (uint32_t i = 0; i < numTextures + 1; ++i)
|
|
pass->createTextureUnitState();
|
|
|
|
if (this->useDSF)
|
|
pass->createTextureUnitState();
|
|
|
|
return matPtr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// CG shader code taken from Ogre Deferred Shading sample. DELETE ME
|
|
/*
|
|
Ogre::GpuProgramPtr MergeMaterialGeneratorImpl::GenerateVertexShader(
|
|
MaterialGenerator::Perm permutation)
|
|
{
|
|
Ogre::StringStream ss;
|
|
|
|
ss << "void MergeVP(" << std::endl;
|
|
ss << " float4 iPosition : POSITION," << std::endl;
|
|
//Get the normal, although this isn't 100% necesarry, it is cheaper to use the normal from the input
|
|
//geometry than fetching it from the GBuffer
|
|
ss << " float3 iNormal : NORMAL," << std::endl;
|
|
|
|
Ogre::uint32 numTexCoords = (permutation & MergeMaterialGenerator::MP_TEXCOORD_MASK) >> 8;
|
|
for (Ogre::uint32 i = 0; i < numTexCoords; i++)
|
|
{
|
|
ss << " float2 iUV" << i << " : TEXCOORD" << i << ',' << std::endl;
|
|
}
|
|
|
|
if (permutation & MergeMaterialGenerator::MP_NORMAL_MAP)
|
|
{
|
|
ss << " float3 iTangent : TANGENT0," << std::endl;
|
|
}
|
|
|
|
//TODO : Skinning inputs
|
|
ss << std::endl;
|
|
|
|
ss << " out float4 oPosition : POSITION," << std::endl;
|
|
|
|
int texCoordNum=0;
|
|
ss << " out half3 oNormal : TEXCOORD" <<texCoordNum++<<","<<std::endl;
|
|
|
|
if ((permutation & MergeMaterialGenerator::MP_NORMAL_MAP) )
|
|
{
|
|
ss << " out half3 oTangent : TEXCOORD" << texCoordNum++ << ',' << std::endl;
|
|
ss << " out half3 oBiNormal : TEXCOORD" << texCoordNum++ << ',' << std::endl;
|
|
}
|
|
for (Ogre::uint32 i = 0; i<numTexCoords; i++)
|
|
{
|
|
ss << " out half2 oUV" << i << " : TEXCOORD" << texCoordNum++ << ',' << std::endl;
|
|
}
|
|
if(this->useDSF){
|
|
ss << " out float3 oViewPos : TEXCOORD"<<texCoordNum++<<"," << std::endl;
|
|
}
|
|
ss << std::endl;
|
|
|
|
ss << " uniform float4x4 cWorldViewProj," << std::endl;
|
|
ss << " uniform float4x4 cWorldView" << std::endl;
|
|
|
|
ss << " )" << std::endl;
|
|
|
|
|
|
ss << "{" << std::endl;
|
|
ss << " oPosition = mul(cWorldViewProj, iPosition);" << std::endl;
|
|
ss << " oNormal = mul(cWorldView, float4(iNormal,0)).xyz;" << std::endl;
|
|
|
|
if (permutation & MergeMaterialGenerator::MP_NORMAL_MAP)
|
|
{
|
|
ss << " oTangent = mul(cWorldView, float4(iTangent,0)).xyz;" << std::endl;
|
|
ss << " oBiNormal = cross(oNormal, oTangent);" << std::endl;
|
|
}
|
|
|
|
for (Ogre::uint32 i = 0; i < numTexCoords; i++) {
|
|
ss << " oUV" << i << " = iUV" << i << ';' << std::endl;
|
|
}
|
|
if(this->useDSF){
|
|
ss << " oViewPos = mul(cWorldView, iPosition).xyz;" << std::endl;
|
|
}
|
|
ss << "}" << std::endl;
|
|
|
|
Ogre::String programSource = ss.str();
|
|
|
|
Ogre::String programName = this->baseName + "VP_" + Ogre::StringConverter::toString(permutation);
|
|
std::cout << programSource << "\n";
|
|
//#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,
|
|
"cg", Ogre::GPT_VERTEX_PROGRAM);
|
|
ptrProgram->setSource(programSource);
|
|
ptrProgram->setParameter("entry_point","MergeVP");
|
|
ptrProgram->setParameter("profiles","vs_3_0 arbvp1");
|
|
|
|
const Ogre::GpuProgramParametersSharedPtr& params = ptrProgram->getDefaultParameters();
|
|
params->setNamedAutoConstant("cWorldViewProj", Ogre::GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
|
params->setNamedAutoConstant("cWorldView", Ogre::GpuProgramParameters::ACT_WORLDVIEW_MATRIX);
|
|
ptrProgram->load();
|
|
|
|
return Ogre::GpuProgramPtr(ptrProgram);
|
|
}
|
|
|
|
Ogre::GpuProgramPtr MergeMaterialGeneratorImpl::GenerateFragmentShader(
|
|
MaterialGenerator::Perm permutation)
|
|
{
|
|
Ogre::StringStream ss;
|
|
|
|
//DirectX needs this to compensate for jitter
|
|
|
|
ss <<"ps_3_0 float2 fixUV(float2 texCoord,float flip){"<<std::endl;
|
|
ss <<"return (texCoord*float2(1,flip) + float2(0.5,0.5));}"<<std::endl;
|
|
|
|
ss<<"float2 fixUV(float2 texCoord,float flip){"<<std::endl;
|
|
ss<<"return texCoord*float2(1,-flip);}"<<std::endl;
|
|
//comparison thresholds for Inferred Lighting. The thresholds are a compromise between getting aliased edges,
|
|
//and getting blocky illumination due to pixel-sized details offseting the comparison
|
|
|
|
if(this->useDSF){
|
|
ss << "#define depth_epsilon 0.001" << std::endl;
|
|
ss << "#define normal_epsilon 0.2" << std::endl;
|
|
}
|
|
ss << "void MergeFP(" << std::endl;
|
|
ss << " half3 iNormal : TEXCOORD0," <<std::endl;
|
|
//use the pixel position to index the LBuffer; this is more precise than
|
|
//computing tex coords based on the view matrix(it's slightly more expensive
|
|
//as well).
|
|
ss << " float2 pixpos: WPOS";
|
|
if(this->useDSF){
|
|
ss<< ","<<std::endl<<" uniform float cFarDistance";
|
|
ss<< ","<<std::endl<<" uniform half cObjectId";
|
|
}
|
|
int texCoordNum = 1;
|
|
if (permutation & MergeMaterialGenerator::MP_NORMAL_MAP )
|
|
{
|
|
ss << ',' << std::endl << " half3 iTangent : TEXCOORD" << texCoordNum++ ;
|
|
ss << ',' << std::endl << " half3 iBiNormal : TEXCOORD" << texCoordNum++ ;
|
|
}
|
|
|
|
Ogre::uint32 numTexCoords = (permutation & MergeMaterialGenerator::MP_TEXCOORD_MASK) >> 8;
|
|
for (Ogre::uint32 i = 0; i < numTexCoords; i++)
|
|
{
|
|
ss << ',' << std::endl<< " half2 iUV" << i << " : TEXCOORD" << texCoordNum++ ;
|
|
}
|
|
if(this->useDSF)
|
|
ss << ',' << std::endl<< " float3 iViewPos: TEXCOORD" << texCoordNum++ ;
|
|
|
|
ss << ',' << std::endl<< " out half4 oColor0 : COLOR0" ;
|
|
|
|
int samplerNum = 0;
|
|
|
|
if (permutation & MergeMaterialGenerator::MP_NORMAL_MAP)
|
|
{
|
|
ss << "," << std::endl << " uniform sampler sNormalMap : register(s" << samplerNum++ << ")";
|
|
}
|
|
|
|
Ogre::uint32 numTextures = permutation & MergeMaterialGenerator::MP_TEXTURE_MASK;
|
|
|
|
|
|
for (Ogre::uint32 i = 0; i<numTextures; i++) {
|
|
ss << "," <<std::endl << " uniform sampler sTex" << i << " : register(s" << samplerNum++ << ")";
|
|
}
|
|
ss << "," <<std::endl<<" uniform sampler LBuffer : register(s"<< samplerNum++ <<")";
|
|
if(this->useDSF){
|
|
ss << "," <<std::endl<<" uniform sampler DSFBuffer : register(s"<< samplerNum++ <<")";
|
|
}
|
|
if (numTextures == 0 || permutation & MergeMaterialGenerator::MP_HAS_DIFFUSE_COLOUR)
|
|
{
|
|
ss<<","<< std::endl << " uniform half4 cDiffuseColour" ;
|
|
}
|
|
ss <<","<<std::endl<< " uniform half cSpecularity" ;
|
|
ss <<","<<std::endl<< " uniform half cHeight";
|
|
ss <<","<<std::endl<< " uniform half cWidth";
|
|
ss <<","<<std::endl<< " uniform half cFlip";
|
|
ss << " )" << std::endl;
|
|
|
|
|
|
ss << "{" << std::endl;
|
|
ss << " pixpos = fixUV(pixpos,cFlip);"<<std::endl;
|
|
if(this->useDSF)
|
|
ss <<" float2 LBuffpos_frac = frac(pixpos*0.75);"<<std::endl;
|
|
//ss <<" pixpos+=float2(0.5/0.75,0.5/0.75);"<<std::endl;
|
|
ss <<" pixpos.x/=cWidth;"<<std::endl;
|
|
ss <<" pixpos.y/=cHeight;"<<std::endl;
|
|
if(this->useDSF){
|
|
//calculate sample positions in order to reconstruct bilinear filtering
|
|
ss <<" float depth = length(iViewPos) / cFarDistance;"<<std::endl;
|
|
ss <<" float2 sample0 = float2(1/cWidth,- 1/cHeight) /(2*0.75);"<<std::endl;
|
|
ss <<" float2 sample1 = float2(-1/cWidth,- 1/cHeight) /(2*0.75);"<<std::endl;
|
|
ss <<" float2 sample2 = float2(1/cWidth ,+ 1/cHeight )/(2*0.75);"<<std::endl;
|
|
ss <<" float2 sample3 = float2(-1/cWidth,+ 1/cHeight) /(2*0.75);"<<std::endl;
|
|
|
|
|
|
//get the values of the Discontinuity Sensible Filter
|
|
ss <<" float4 DSF0 = tex2D(DSFBuffer,pixpos + sample0);"<<std::endl;
|
|
ss <<" float4 DSF1 = tex2D(DSFBuffer,pixpos + sample1);"<<std::endl;
|
|
ss <<" float4 DSF2 = tex2D(DSFBuffer,pixpos + sample2);"<<std::endl;
|
|
ss <<" float4 DSF3 = tex2D(DSFBuffer,pixpos + sample3);"<<std::endl;
|
|
//normalize the input normal for proper comparison
|
|
ss <<" iNormal=normalize(iNormal);"<<std::endl;
|
|
|
|
//get the usual bilinear interpolation weights
|
|
ss <<" float4 w = float4((1-LBuffpos_frac.x)*(1-LBuffpos_frac.y),LBuffpos_frac.x*(1-LBuffpos_frac.y),"<<std::endl
|
|
<<"(1-LBuffpos_frac.x)*LBuffpos_frac.y,LBuffpos_frac.x*LBuffpos_frac.y);"<<std::endl;
|
|
|
|
//see if each sample is on the same surface or not
|
|
ss <<" float w0 = saturate(100*(depth_epsilon - abs(depth-DSF0.r))) *"<<std::endl
|
|
<<" saturate((1-1000*abs(DSF0.g - cObjectId)))*saturate(1000*(normal_epsilon - abs(iNormal.x-DSF0.b)))*saturate(1000*(normal_epsilon - abs(iNormal.y-DSF0.a)));"<<std::endl;
|
|
ss <<" float w1 = saturate(100*(depth_epsilon - abs(depth-DSF1.r))) *"<<std::endl
|
|
<<" saturate((1-1000*abs(DSF1.g - cObjectId)))*saturate(1000*(normal_epsilon - abs(iNormal.x-DSF1.b)))*saturate(1000*(normal_epsilon - abs(iNormal.y-DSF1.a)));"<<std::endl;
|
|
ss <<" float w2 = saturate(100*(depth_epsilon - abs(depth-DSF2.r))) *"<<std::endl
|
|
<<" saturate((1-1000*abs(DSF2.g - cObjectId)))*saturate(1000*(normal_epsilon - abs(iNormal.x-DSF2.b)))*saturate(1000*(normal_epsilon - abs(iNormal.y-DSF2.a)));"<<std::endl;
|
|
ss <<" float w3 = saturate(100*(depth_epsilon - abs(depth-DSF3.r))) *"<<std::endl
|
|
<<" saturate((1-1000*abs(DSF3.g - cObjectId)))*saturate(1000*(normal_epsilon - abs(iNormal.x-DSF3.b)))*saturate(1000*(normal_epsilon - abs(iNormal.y-DSF3.a)));"<<std::endl;
|
|
//TODO: find a better way to check if at least a sample is on the surface
|
|
ss <<" if(w0+w1+w2+w3 > 0)"<<std::endl;
|
|
//bias bilinear filtering
|
|
ss <<" w *= float4(w0,w1,w2,w3);"<<std::endl;
|
|
//get the light's value
|
|
ss <<"half4 lightVal = (w.x * tex2D(LBuffer,pixpos+sample0) + w.y * tex2D(LBuffer,pixpos + sample1) +w.z * tex2D(LBuffer,pixpos + sample2)+w.w * tex2D(LBuffer,pixpos + sample3))/(w.x+w.y+w.z+w.w);"<<std::endl;
|
|
}
|
|
else{
|
|
ss <<" half4 lightVal = tex2D(LBuffer,pixpos);"<<std::endl;
|
|
}
|
|
|
|
ss << " half3 diffuseCol;"<<std::endl;
|
|
if (numTexCoords > 0 && numTextures > 0 )
|
|
{
|
|
ss << " diffuseCol = tex2D(sTex0, iUV0);" << std::endl;
|
|
if (permutation & MergeMaterialGenerator::MP_HAS_DIFFUSE_COLOUR)
|
|
{
|
|
ss << " diffuseCol *= cDiffuseColour.rgb;" << std::endl;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ss << " diffuseCol = cDiffuseColour.rgb;" << std::endl;
|
|
}
|
|
//use the luminance as an aproximation of the intensity of the NL*attenuation term
|
|
ss <<" half luminance = dot(lightVal.rgb, float3(0.2126, 0.7152, 0.0722));"<<std::endl;
|
|
//reconstruct HV^n_light based on that, and get the specular term
|
|
ss <<" half3 specular = diffuseCol*max(0,pow(lightVal.a/luminance,1.0+cSpecularity));"<<std::endl;
|
|
//get the final lighting value
|
|
ss <<" half4 color = float4(lightVal.rgb*(diffuseCol + specular),1);"<<std::endl;
|
|
ss <<" oColor0 = color;"<<std::endl;
|
|
ss << "}" << std::endl;
|
|
|
|
Ogre::String programSource = ss.str();
|
|
Ogre::String programName = this->baseName + "FP_" + Ogre::StringConverter::toString(permutation);
|
|
|
|
std::cout << programSource << "\n";
|
|
//#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,
|
|
"cg", Ogre::GPT_FRAGMENT_PROGRAM);
|
|
ptrProgram->setSource(programSource);
|
|
ptrProgram->setParameter("entry_point","MergeFP");
|
|
ptrProgram->setParameter("profiles","ps_3_0 arbfp1");
|
|
|
|
const Ogre::GpuProgramParametersSharedPtr& params = ptrProgram->getDefaultParameters();
|
|
|
|
|
|
if (numTextures == 0 || permutation & MergeMaterialGenerator::MP_HAS_DIFFUSE_COLOUR)
|
|
{
|
|
params->setNamedAutoConstant("cDiffuseColour", Ogre::GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
|
}
|
|
params->setNamedAutoConstant("cSpecularity", Ogre::GpuProgramParameters::ACT_SURFACE_SHININESS);
|
|
//params->setNamedAutoConstant("cSpecularColour", Ogre::GpuProgramParameters::ACT_SURFACE_SPECULAR_COLOUR);
|
|
params->setNamedAutoConstant("cWidth", Ogre::GpuProgramParameters::ACT_VIEWPORT_WIDTH);
|
|
params->setNamedAutoConstant("cHeight", Ogre::GpuProgramParameters::ACT_VIEWPORT_HEIGHT);
|
|
params->setNamedAutoConstant("cFlip", Ogre::GpuProgramParameters::ACT_RENDER_TARGET_FLIPPING);
|
|
if(this->useDSF){
|
|
params->setNamedAutoConstant("cFarDistance", Ogre::GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
|
|
params->setNamedAutoConstant("cObjectId",Ogre::GpuProgramParameters::ACT_CUSTOM,0);
|
|
}
|
|
ptrProgram->load();
|
|
return Ogre::GpuProgramPtr(ptrProgram);
|
|
}*/
|