您的位置:首页 > 其它

Ogre shader中定义 param_named_auto custom, 材质中纹理操作

2018-01-10 00:38 381 查看
转载自: https://www.cnblogs.com/flytrace/archive/2012/05/14/2499733.html

ogre 扩展模型描绘轮廓及实现自阴影明暗

Posted on 2012-05-14 18:03 饭后温柔 阅读(1184) 评论(1) 编辑 收藏

项目中的轮廓描绘使用了扩展模型的方法,即偏移法向量然后重绘.角色自阴影使用shadow map.
轮廓通过寻边(object空间方法)实现的话,算法复杂,留待以后实现.
.h

#ifndef __CartoonRenderManager_H__
#define __CartoonRenderManager_H__
#include "Loki/Singleton.h"
#include "SeerBaseConfig.h"
/*
CartoonRenderManager是一个单例类,用于描绘entity的轮廓.
用法:
Orz::CartoonRenderManager::Instance().setOutline(entity, color);
其中entity为欲描绘的实体,color为一个颜色的枚举值.请查看函数注释.
*/

namespace Orz
{
enum CartoonOutlineType { CT_WIREFRAME, CT_EXTENDMODEL };
enum CartoonOutLineColor { CT_OL_BLACK, CT_OL_RED, CT_OL_WHITE };

class _OrzSeerBaseExport CartoonRenderManager
{
enum CartoonRenderConstant { SP_OFFSET = 1, SP_COLOR };
public:
~CartoonRenderManager();
public:
void init(Ogre::SceneManager* psm);

/*
@功能                    描绘entity的轮廓.
@entity                    欲描绘的实体
@colour                    轮廓颜色的枚举值:CT_OL_BLACK, CT_OL_RED, CT_OL_WHITE分别为黑,红,白.
@CartoonOutlineType        描绘轮廓的方法.目前支持扩展描绘法.
*/
void setOutline(Ogre::Entity* entity, Ogre::ColourValue colour = Ogre::ColourValue::Black, Ogre::Real offset = 1.0, CartoonOutlineType type = CT_EXTENDMODEL);
void setOutLineOffset(Ogre::Entity* entity, Ogre::Real offset);
void setOutLineColour(Ogre::Entity* _entity, Ogre::ColourValue colour);
void destroyMeshPass(Ogre::Entity* entity);
void setMipmapsBias(Ogre::Entity* entity, Ogre::Real bias = 0.0);

private:
typedef Loki::SingletonHolder<CartoonRenderManager> MySingleton;
public:
inline static CartoonRenderManager& Instance()
{
return MySingleton::Instance();
}

private:
void setOutlineExtendModel(Ogre::Entity* entity, Ogre::ColourValue colour, Ogre::Real offset);

Ogre::SceneManager* m_psm;
};
}
#endif


.cpp

#include "SeerBaseStableHeaders.h"
#include "CartoonRenderManager.h"

namespace Orz
{

CartoonRenderManager::~CartoonRenderManager()
{
//m_psm->destroyShadowTextures();
}

void CartoonRenderManager::init(Ogre::SceneManager* psm)
{
m_psm = psm;

if (Ogre::Root::getSingletonPtr()->getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_HWRENDER_TO_TEXTURE))
{
m_psm->setShadowTextureSettings(1024, 1);
}
else
{
m_psm->setShadowTextureSettings(512, 1);
}

m_psm->setShadowTextureSelfShadow(true);

m_psm->setShadowTextureCasterMaterial("CelShading/Caster/Float");

m_psm->setShadowTexturePixelFormat(Ogre::PF_FLOAT32_R);

m_psm->setShadowTechnique(Ogre::SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED);
m_psm->setShadowCameraSetup(Ogre::ShadowCameraSetupPtr(new Ogre::FocusedShadowCameraSetup));
//m_psm->setShadowCameraSetup(ShadowCameraSetupPtr(new Ogre::LiSPSMShadowCameraSetup));

Ogre::Light* light = m_psm->createLight("shadowLight");
light->setType(Ogre::Light::LightTypes::LT_DIRECTIONAL);
light->setCastShadows(true);
light->setDirection(0, 0, -1);
m_psm->getRootSceneNode()->attachObject(light);
}

void CartoonRenderManager::setOutline(Ogre::Entity* entity, Ogre::ColourValue colour /* = Ogre::ColourValue::Black */, Ogre::Real offset /* = 1.0 */, CartoonOutlineType type /* = CT_EXTENDMODEL */)
{
switch (type)
{
case CT_WIREFRAME:
{
//setOutlineWirefrme(entity, colour);
}
break;
case CT_EXTENDMODEL:
{
setOutlineExtendModel(entity, colour, offset);
}
break;
}
}

void CartoonRenderManager::setOutlineExtendModel(Ogre::Entity* _entity,    Ogre::ColourValue colour, Ogre::Real offset)
{
if(!_entity) return;
//destroyMeshPass(_entity);
int subMeshNum = _entity->getNumSubEntities();
int NumTechniques = _entity->getSubEntity(0)->getMaterial()->getNumTechniques();
for (int i = 0; i < subMeshNum; i++)
{

Ogre::SubEntity* sub =  _entity->getSubEntity(i);
sub->setCustomParameter(SP_OFFSET, Ogre::Vector4(offset, 0, 0, 0));
sub->setCustomParameter(SP_COLOR, Ogre::Vector4(colour.r, colour.g, colour.b, colour.a));

for (int j = 0; j < NumTechniques; j ++)
{
Ogre::Pass* pass = NULL;
pass = sub->getMaterial()->getTechnique(j)->getPass("Edges");

if(pass == NULL)
{
pass =sub->getMaterial()->getTechnique(j)->createPass();
pass->setName("Edges");
}

pass->setVertexProgram("CelShading/OutlineVP");
pass->setFragmentProgram("CelShading/OutlineFP");
pass->setCullingMode(Ogre::CULL_ANTICLOCKWISE);

//
pass = sub->getMaterial()->getTechnique(j)->getPass(0);
if(pass == NULL) return;
pass->setVertexProgram("CelShading/ReceiverVP");
pass->setFragmentProgram("CelShading/ReceiverFP");

Ogre::TextureUnitState* state = NULL;
state = pass->getTextureUnitState("1");
if(state == NULL) {
state = pass->createTextureUnitState();
state->setTextureCoordSet(1);
state->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
state->setTextureFiltering(Ogre::TFO_NONE);
state->setContentType(Ogre::TextureUnitState::CONTENT_SHADOW);
}

state = pass->getTextureUnitState("2");
if(state == NULL) {
state = pass->createTextureUnitState();
state->setTextureCoordSet(2);
state->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
state->setTextureFiltering(Ogre::TFO_BILINEAR);
state->setTextureName("Effect/shader_texture/celshading_diffuse.gif", Ogre::TEX_TYPE_1D);
}
}
}
}

void CartoonRenderManager::setOutLineOffset(Ogre::Entity* _entity, Ogre::Real offset)
{
if(!_entity) return;
int subMeshNum = _entity->getNumSubEntities();
for (int i = 0; i < subMeshNum; i++)
{
Ogre::SubEntity* sub =  _entity->getSubEntity(i);
sub->setCustomParameter(SP_OFFSET, Ogre::Vector4(offset, 0, 0, 0));
}
}

void CartoonRenderManager::setOutLineColour(Ogre::Entity* _entity, Ogre::ColourValue colour)
{
if(!_entity) return;
int subMeshNum = _entity->getNumSubEntities();
for (int i = 0; i < subMeshNum; i++)
{
Ogre::SubEntity* sub =  _entity->getSubEntity(i);
sub->setCustomParameter(SP_COLOR, Ogre::Vector4(colour.r, colour.g, colour.b, colour.a));
}
}

void CartoonRenderManager::setMipmapsBias(Ogre::Entity* _entity, Ogre::Real bias /* = 0.0 */)
{
if(!_entity) return;

//临时固定纹理层次mipmaps
int subMeshNum = _entity->getNumSubEntities();
for (int i = 0; i < subMeshNum; i++)
{
Ogre::SubEntity* sub =  _entity->getSubEntity(i);
unsigned short NumTechniques = sub->getMaterial()->getNumTechniques();
for (unsigned short j = 0; j < NumTechniques; j++)
{
Ogre::Technique* tech = sub->getMaterial()->getTechnique(j);
for (unsigned short k = 0; k < tech->getNumPasses(); k++)
{
Ogre::Pass * tempPass = tech->getPass(k);
for (unsigned short l = 0; l < tempPass->getNumTextureUnitStates(); l++)
tempPass->getTextureUnitState(l)->setTextureMipmapBias(bias);
}
}
}
}

void CartoonRenderManager::destroyMeshPass(Ogre::Entity* _entity)
{
int subMeshNum = _entity->getNumSubEntities();

for (int i = 0; i < subMeshNum; i++)
{
int NumTechniques = _entity->getSubEntity(i)->getMaterial()->getNumTechniques();
for (int j = 0; j < NumTechniques; j++)
{
Ogre::Pass* pass = _entity->getSubEntity(i)->getMaterial()->getTechnique(j)->getPass("Edges");
if(pass)
_entity->getSubEntity(i)->getMaterial()->getTechnique(j)->removePass(pass->getIndex());

}
}
}

}


需要注意阴影pass及轮廓pass因为特殊原因在代码中添加.更好的做法应该在.material文件中添加.
轮廓cg

void outline_vp(float4 position    : POSITION,
float3 normal        : NORMAL,
float2 uvIn        : TEXCOORD0,
// outputs
out float4 oPosition    : POSITION,
// parameters
uniform float4 modelOffset,
uniform float4x4 worldViewProj)
{
float3 N = normalize(normal);
position.xyz += modelOffset.x*N;
oPosition = mul(worldViewProj, position);
}

void outline_fp(out float4 color : COLOR,
uniform float4 edgeColor : COLOR)
{
color = edgeColor;
}

////////////////////////////////////////////////////
void outline_wireframe_vp(  float4 position : POSITION,
// outputs
out float4 oPosition : POSITION,
// parameters
uniform float4x4 worldViewProj  )
{
oPosition = mul(worldViewProj, position);
}

void outline_wireframe_fp(  out float4 color : COLOR,
uniform float4 edgeColor : COLOR    )
{
color = edgeColor;
}


轮廓.program

vertex_program CelShading/OutlineVP cg
{
source CelShading.cg
entry_point outline_vp
profiles vs_1_1 arbvp1

default_params
{
param_named_auto worldViewProj worldviewproj_matrix
param_named_auto modelOffset custom 1
}
}

fragment_program CelShading/OutlineFP cg
{
source CelShading.cg
entry_point outline_fp
profiles ps_1_1 arbfp1 fp20

default_params
{
param_named_auto edgeColor custom 2
}
}

//////////////////////////////////////////////////////////
vertex_program CelShading/OutlineVP_Wireframe cg
{
source CelShading.cg
entry_point outline_wireframe_vp
profiles vs_1_1 arbvp1

default_params
{
param_named_auto worldViewProj worldviewproj_matrix
}
}

fragment_program CelShading/OutlineFP_Wireframe cg
{
source CelShading.cg
entry_point outline_wireframe_fp
profiles ps_1_1 arbfp1 fp20

default_params
{
param_named_auto edgeColor custom 2
}
}


阴影cg

// Shadow caster vertex program.
void casterVP(
float4 position            : POSITION,

out float4 outPosition    : POSITION,
out float2 outDepth        : TEXCOORD0,

uniform float4x4 worldViewProj,
uniform float4 texelOffsets,
uniform float4 depthRange
)
{
outPosition = mul(worldViewProj, position);

// fix pixel / texel alignment
outPosition.xy += texelOffsets.zw * outPosition.w;
// linear depth storage
// offset / scale range output
#if LINEAR_RANGE
outDepth.x = (outPosition.z - depthRange.x) * depthRange.w;
#else
outDepth.x = outPosition.z;
#endif
outDepth.y = outPosition.w;
}

// Shadow caster fragment program for high-precision single-channel textures
void casterFP(
float2 depth            : TEXCOORD0,
out float4 result        : COLOR
)
{
#if LINEAR_RANGE
float finalDepth = depth.x;
#else
float finalDepth = depth.x / depth.y;
#endif
// just smear across all components
// therefore this one needs high individual channel precision
result = float4(finalDepth, finalDepth, finalDepth, 1);
}

void receiverVP(
float4 position        : POSITION,
float4 normal        : NORMAL,
float2 uv            : TEXCOORD0,

out float4 outPosition    : POSITION,
out float2 outUV        : TEXCOORD0,
out float4 outShadowUV    : TEXCOORD1,
out float outDiffuse    : TEXCOORD2,
#if SPECULAR
out float outSpecular    : TEXCOORD3,

uniform float4 eyePosition,
uniform float shininess,
#endif
uniform float4x4 world,
uniform float4x4 worldViewProj,
uniform float4x4 texViewProj,
uniform float4 lightPosition,
uniform float4 shadowDepthRange,
uniform float4 lightPositionObjectSpace
)
{
outPosition = mul(worldViewProj, position);

outUV = uv;

// calculate shadow map coords
float4 worldPos = mul(world, position);
outShadowUV = mul(texViewProj, worldPos);
#if LINEAR_RANGE
// adjust by fixed depth bias, rescale into range
outShadowUV.z = (outShadowUV.z - shadowDepthRange.x) * shadowDepthRange.w;
#endif

// calculate light vector
float3 N = normalize(normal.xyz);

#if DIRECTIONAL
// used in directional light source
float3 L = normalize(lightPositionObjectSpace.xyz);
#else
// use this line if used in point light source
float3 L = normalize(lightPositionObjectSpace.xyz - position.xyz);
#endif

// Calculate diffuse component
outDiffuse = max(dot(N, L) , 0);
#if SPECULAR
// Calculate specular component
float3 E = normalize(eyePosition.xyz - position.xyz);
float3 H = normalize(L + E);
outSpecular = pow(max(dot(N, H), 0), shininess);
#endif
}

void receiverFP(
float4 position            : POSITION,
float2 uv                : TEXCOORD0,
float4 shadowUV            : TEXCOORD1,
float diffuse            : TEXCOORD2,
#if SPECULAR
float specular            : TEXCOORD3,
#endif

uniform sampler2D myTexture        : register(s0),
uniform sampler2D shadowMap        : register(s1),
uniform sampler1D diffuseRamp    : register(s2),
#if SPECULAR
uniform sampler1D specularRamp    : register(s3),
#endif
uniform float inverseShadowmapSize,
uniform float fixedDepthBias,
uniform float gradientClamp,
uniform float gradientScaleBias,
//uniform float shadowFuzzyWidth,
uniform float darken,
#if SPECULAR
uniform float lighten,
#endif

out float4 result        : COLOR
)
{
// point on shadowmap
#if LINEAR_RANGE
shadowUV.xy = shadowUV.xy / shadowUV.w;
#else
shadowUV = shadowUV / shadowUV.w;
#endif

float centerdepth = tex2D(shadowMap, shadowUV.xy).x;

// gradient calculation
float pixeloffset = inverseShadowmapSize;
float4 depths = float4(
tex2D(shadowMap, shadowUV.xy + float2(-pixeloffset, 0)).x,
tex2D(shadowMap, shadowUV.xy + float2(+pixeloffset, 0)).x,
tex2D(shadowMap, shadowUV.xy + float2(0, -pixeloffset)).x,
tex2D(shadowMap, shadowUV.xy + float2(0, +pixeloffset)).x);

float2 differences = abs( depths.yw - depths.xz );
float gradient = min(gradientClamp, max(differences.x, differences.y));
float gradientFactor = gradient * gradientScaleBias;

// visibility function
float depthAdjust = gradientFactor + (fixedDepthBias * centerdepth);
float finalCenterDepth = centerdepth + depthAdjust;

// shadowUV.z contains lightspace position of current object

float shadow;
#if FUZZY_TEST
// fuzzy test - introduces some ghosting in result and doesn't appear to be needed?
//shadow = saturate(1 + delta_z / (gradient * shadowFuzzyWidth));
shadow = saturate(1 + (finalCenterDepth - shadowUV.z) * shadowFuzzyWidth * shadowUV.w);
#else
// hard test
#if PCF
// use depths from prev, calculate diff
depths += depthAdjust.xxxx;
shadow = (finalCenterDepth > shadowUV.z) ? 1.0f : 0.0f;
shadow += (depths.x > shadowUV.z) ? 1.0f : 0.0f;
shadow += (depths.y > shadowUV.z) ? 1.0f : 0.0f;
shadow += (depths.z > shadowUV.z) ? 1.0f : 0.0f;
shadow += (depths.w > shadowUV.z) ? 1.0f : 0.0f;

shadow *= 0.2f;
#else
shadow = (finalCenterDepth > shadowUV.z) ? 1.0f : 0.0f;
#endif

#endif
float4 vertexColour = tex2D(myTexture, uv);
//result = float4(vertexColour.xyz * shadow, 1);

diffuse = tex1D(diffuseRamp, diffuse).x;
float darkness = (shadow > diffuse) ? diffuse : shadow;

float final = (darkness - 1) * darken;
#if SPECULAR
// if there is already a shadow, no specular will be casted
final += (shadow > 0.0f) ? tex1D(specularRamp, specular).x * lighten : 0;
#endif

// then darken the original texture.
result = float4(vertexColour.xyz + float3(final), 1);
//result = float4(float3(final),1);
}


// Generic Shadow caster material (floating point shadowmap)
material CelShading/Caster/Float
{
technique
{
pass
{
vertex_program_ref CelShading/CasterVP
{
}
fragment_program_ref CelShading/CasterFP
{
}
}
}
}

material CelShading/Base
{
lod_distances 300.0 800.0
// ultra-high scheme technique uses cel-shading with texture shadow support
technique
{
scheme ultrahigh
lod_index 0
pass
{
lighting off

// Vertex program reference
vertex_program_ref CelShading/ReceiverVP
{
}

// Fragment program
fragment_program_ref CelShading/ReceiverFP
{
}

texture_unit
{
texture_alias textureUnit_0
tex_address_mode clamp
filtering bilinear
tex_coord_set 0
}
texture_unit
{
content_type shadow
tex_address_mode clamp
filtering none
tex_coord_set 1
}
texture_unit
{
texture Effect/shader_texture/celshading_diffuse.gif 1d
tex_address_mode clamp
filtering bilinear
tex_coord_set 2
}
}
}
}

// Basic material with specular which support shadows as a seperate scheme
// material Lolo/CelShadingV4/Specular/Base
// {
// lod_distances 300.0 800.0
// // ultra-high scheme technique uses cel-shading with texture shadow support
// technique
// {
// scheme ultrahigh
// lod_index 0
// pass ShadeWithShadow
// {
// lighting off

// // Vertex program reference
// vertex_program_ref CelShading/Specular/ReceiverVP
// {
// }

// // Fragment program
// fragment_program_ref CelShading/Specular/ReceiverFP
// {
// }

// texture_unit
// {
// texture_alias MainTexture
// tex_address_mode clamp
// filtering bilinear
// tex_coord_set 0
// }
// texture_unit
// {
// content_type shadow
// tex_address_mode clamp
// filtering none
// tex_coord_set 1
// }
// texture_unit
// {
// texture celshading_diffuse.gif 1d
// tex_address_mode clamp
// filtering bilinear
// tex_coord_set 2
// }
// texture_unit
// {
// texture celshading_specular.gif 1d
// tex_address_mode clamp
// filtering bilinear
// tex_coord_set 3
// }
// }
// }
// }


 
阴影.program

vertex_program CelShading/CasterVP cg
{
source CelShadingShadow.cg
entry_point casterVP
profiles arbvp1 vs_2_0

compile_arguments -DLINEAR_RANGE=0

default_params
{
param_named_auto worldViewProj worldviewproj_matrix
param_named_auto texelOffsets texel_offsets
param_named_auto depthRange scene_depth_range
}
}

fragment_program CelShading/CasterFP cg
{
source CelShadingShadow.cg
entry_point casterFP
profiles arbfp1 ps_2_0 fp20

compile_arguments -DLINEAR_RANGE=0

default_params
{
}
}

vertex_program CelShading/ReceiverVP cg
{
source CelShadingShadow.cg
entry_point receiverVP
profiles arbvp1 vs_2_0

// set DDIRECTIONAL=1 if used with directional light
compile_arguments -DDIRECTIONAL=1 -DLINEAR_RANGE=0 -DSPECULAR=0

default_params
{
param_named_auto world world_matrix
param_named_auto worldViewProj worldviewproj_matrix
param_named_auto texViewProj texture_viewproj_matrix
//param_named_auto lightPosition light_position 0
param_named_auto shadowDepthRange shadow_scene_depth_range 0
param_named_auto lightPositionObjectSpace light_position_object_space 0
}
}

fragment_program CelShading/ReceiverFP cg
{
source CelShadingShadow.cg
entry_point receiverFP
profiles arbfp1 ps_2_0 fp20

compile_arguments -DLINEAR_RANGE=0 -DSPECULAR=0 -DFUZZY_TEST=0 -DPCF=1

default_params
{
param_named inverseShadowmapSize float 0.0009765625
param_named fixedDepthBias float 0.01
param_named gradientClamp float 0.0098
param_named gradientScaleBias float 1
//param_named shadowFuzzyWidth float 0.3
param_named darken float 0.15
}
}


阴影部分的cg需要注意平行光源与聚光灯光源的区别,设定cg的编译常量来决定.

标签: ogreoutline, shadow
map
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: