osg解析系列-osgShadow::ShadowMap(深度纹理/RTT)实现中的几个细节

osgShadow::ShadowMap 和 osgShadow::ShadowTexture是osg中已实现的2种阴影技术,但是,请注意这2种技术的原理完全不同:
osgShadow::ShadowMap:首先是创建深度纹理 和 RTT相机,然后 RTT相机和深度缓存区绑定、将深度缓存区种的数据写入纹理。该纹理如何应用于片段(frag)呢?片段的深度测试。
osgShadow::ShadowTexture:首先是创建颜色纹理 和 RTT相机,然后 RTT相机和颜色缓存区绑定、将颜色缓存区种的数据写入纹理。该纹理如何应用于片段(frag)呢?直接应用于片段(纹理操作和雾),即片段操作阶段(深度测试之前)。

  1. 创建深度纹理
    _texture = new osg::Texture2D;
    _texture->setTextureSize(_textureSize.x(), _textureSize.y());
    _texture->setInternalFormat(GL_DEPTH_COMPONENT);
    _texture->setShadowComparison(true);
    _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE);
    _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
    _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);

    // the shadow comparison should fail if object is outside the texture
    _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
    _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
    _texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
注意这两行:
    _texture->setInternalFormat(GL_DEPTH_COMPONENT);
    _texture->setShadowComparison(true);

2.RTT相机绑定深度缓存区

        // attach the texture and use it as the Depth buffer.
        _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());

3.应用示例:

// M23.11.W3.Shadow.ShadowMap.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>

//osg
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <osg/Geometry>
#include <osg/Material>

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgGA/AnimationPathManipulator>


//osgShadow
#include <osgShadow/ShadowedScene>
#include <osgShadow/ShadowTexture>
#include <osgShadow/ShadowMap>
#include <osgShadow/SoftShadowMap>
#include <osgShadow/ParallelSplitShadowMap>
#include <osgShadow/LightSpacePerspectiveShadowMap>
#include <osgShadow/StandardShadowMap>
#include <osgShadow/ViewDependentShadowMap>

//osglib
#pragma comment(lib,"OpenThreads_d.lib")
#pragma comment(lib,"osg_d.lib")
#pragma comment(lib,"osgDB_d.lib")
#pragma comment(lib,"osgFX_d.lib")
#pragma comment(lib,"osgGA_d.lib")
#pragma comment(lib,"osgUtil_d.lib")
#pragma comment(lib,"osgViewer_d.lib")
#pragma comment(lib,"osgShadow_d.lib")

static int ReceivesShadowTraversalMask = 0x1;
static int CastsShadowTraversalMask = 0x2;


// for the grid data..
#include "terrain_coords.h"

namespace MyShadow
{
	osg::AnimationPath* createAnimationPath(const osg::Vec3& center, float radius, double looptime)
	{
		// set up the animation path
		osg::AnimationPath* animationPath = new osg::AnimationPath;
		animationPath->setLoopMode(osg::AnimationPath::LOOP);

		int numSamples = 40;
		float yaw = 0.0f;
		float yaw_delta = 2.0f*osg::PI / ((float)numSamples - 1.0f);
		float roll = osg::inDegrees(30.0f);

		double time = 0.0f;
		double time_delta = looptime / (double)numSamples;
		for (int i = 0;i < numSamples;++i)
		{
			osg::Vec3 position(center + osg::Vec3(sinf(yaw)*radius, cosf(yaw)*radius, 0.0f));
			osg::Quat rotation(osg::Quat(roll, osg::Vec3(0.0, 1.0, 0.0))*osg::Quat(-(yaw + osg::inDegrees(90.0f)), osg::Vec3(0.0, 0.0, 1.0)));

			animationPath->insert(time, osg::AnimationPath::ControlPoint(position, rotation));

			yaw += yaw_delta;
			time += time_delta;

		}
		return animationPath;
	}

	osg::Node* createBase(const osg::Vec3& center, float radius)
	{

		osg::Geode* geode = new osg::Geode;

		// set up the texture of the base.
		osg::StateSet* stateset = new osg::StateSet();
		osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile("D:\\osg365vs2015x64\\Data\\Images\\rockwall.png");//lz.rgb
		if (image)
		{
			osg::Texture2D* texture = new osg::Texture2D;
			texture->setImage(image);
			stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
		}

		geode->setStateSet(stateset);


		osg::HeightField* grid = new osg::HeightField;
		grid->allocate(38, 39);
		grid->setOrigin(center + osg::Vec3(-radius, -radius, 0.0f));
		grid->setXInterval(radius*2.0f / (float)(38 - 1));
		grid->setYInterval(radius*2.0f / (float)(39 - 1));

		float minHeight = FLT_MAX;
		float maxHeight = -FLT_MAX;


		unsigned int r;
		for (r = 0;r < 39;++r)
		{
			for (unsigned int c = 0;c < 38;++c)
			{
				float h = vertex[r + c * 39][2];
				if (h > maxHeight) maxHeight = h;
				if (h < minHeight) minHeight = h;
			}
		}

		float hieghtScale = radius*0.5f / (maxHeight - minHeight);
		float hieghtOffset = -(minHeight + maxHeight)*0.5f;

		for (r = 0;r < 39;++r)
		{
			for (unsigned int c = 0;c < 38;++c)
			{
				float h = vertex[r + c * 39][2];
				grid->setHeight(c, r, (h + hieghtOffset)*hieghtScale);
			}
		}

		geode->addDrawable(new osg::ShapeDrawable(grid));

		osg::Group* group = new osg::Group;
		group->addChild(geode);

		return group;

	}

	osg::Node* createMovingModel(const osg::Vec3& center, float radius)
	{
		float animationLength = 10.0f;

		osg::AnimationPath* animationPath = createAnimationPath(center, radius, animationLength);

		osg::Group* model = new osg::Group;

		osg::ref_ptr<osg::Node> cessna = osgDB::readRefNodeFile("D:\\osg365vs2015x64\\Data\\cessna.osgt");
		if (cessna)
		{
			const osg::BoundingSphere& bs = cessna->getBound();

			float size = radius / bs.radius()*0.3f;
			osg::MatrixTransform* positioned = new osg::MatrixTransform;
			positioned->setDataVariance(osg::Object::STATIC);
			positioned->setMatrix(osg::Matrix::translate(-bs.center())*
				osg::Matrix::scale(size, size, size)*
				osg::Matrix::rotate(osg::inDegrees(180.0f), 0.0f, 0.0f, 2.0f));

			positioned->addChild(cessna);

			osg::MatrixTransform* xform = new osg::MatrixTransform;
			//注释掉下面这行后,会呈现静态画面;开启后,为动画效果的。
			xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath, 0.0f, 2.0));
			xform->addChild(positioned);

			model->addChild(xform);
		}

		return model;
	}

	osg::Node* createModel(osg::ArgumentParser& /*arguments*/)
	{
		osg::Vec3 center(0.0f, 0.0f, 0.0f);
		float radius = 100.0f;
		// the shadower model
		osg::Node* shadower = createMovingModel(center, radius*0.5f);
		shadower->setNodeMask(CastsShadowTraversalMask);

		// the shadowed model
		osg::Node* shadowed = createBase(center - osg::Vec3(0.0f, 0.0f, radius*0.25), radius);
		shadowed->setNodeMask(ReceivesShadowTraversalMask);

		osg::Group* group = new osg::Group;

		group->addChild(shadowed);
		group->addChild(shadower);

		return group;
	}
}
int main(int argc, char** argv)
{
	// use an ArgumentParser object to manage the program arguments.
	osg::ArgumentParser arguments(&argc, argv);

	// construct the viewer.
	osgViewer::Viewer viewer;
	// ThreadModel
	viewer.setThreadingModel(osgViewer::Viewer::AutomaticSelection);
	// MasterCamera
	//using default

	// scene data
	osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new osgShadow::ShadowedScene;
	osgShadow::ShadowSettings* settings = shadowedScene->getShadowSettings();
	settings->setReceivesShadowTraversalMask(ReceivesShadowTraversalMask);
	settings->setCastsShadowTraversalMask(CastsShadowTraversalMask);
			osg::ref_ptr<osgShadow::ShadowMap> sm = new osgShadow::ShadowMap;
			// 注意:此次增加了1个空的片段着色器,因365版本种默认的片段着色代码似乎有问题,其他版本有无问题不确定
		osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT);
		sm->addShader(fragment_shader);
		shadowedScene->setShadowTechnique(sm.get());
osg::Vec4 lightpos(0.0, 1.0, 1, 0.0);
	osg::ref_ptr<osg::LightSource> ls = new osg::LightSource;
	ls->getLight()->setPosition(lightpos);

	shadowedScene->addChild(MyShadow::createModel(arguments));
	shadowedScene->addChild(ls.get());

	viewer.setSceneData(shadowedScene);
	viewer.setCameraManipulator(new osgGA::TrackballManipulator());

	viewer.run();
	return 0;
}
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值