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


    项目中的轮廓描绘使用了扩展模型的方法,即偏移法向量然后重绘.角色自阴影使用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的编译常量来决定.

  • 相关阅读:
    ES head安装笔记, 还没有试
    sed用法笔记
    Kibana笔记
    ElasticSearch笔记
    Mongo聚合笔记
    java 判断是否为数字
    Redis 一:安装篇
    make问题:make[1] entering directory
    Java 多线程 简单实例 (消费者与生成者)的关系
    Java 多线程 简单实例 (Runnable)
  • 原文地址:https://www.cnblogs.com/flytrace/p/2499733.html
Copyright © 2020-2023  润新知