平面阴影虽然不能满足所有的阴影要求,但是如果是相对简单的场景的话,用平面阴影也是个不错的选择,它的优点是速度快,并不需占用多少运算时间。
步骤如下:
1. 定位需要渲染阴影的物体,和阴影所在平面
2. 计算出平面上阴影的物体定点,定义一定透明度,如50%透明度
3. 渲染
一、首先解决问题是如何计算
方法就是利用向量代数和空间解析几何的知识,知道了光照的方向向量,物体定点,和平面位置,就可以计算了。这里就不给出具体的计算了,基础不好的恶补下,这里主要讲图形学的技术,而且大多数的API,如DirectX和OpenGL都有现场的API去自动计算,记得目的就是为了定义出在平面上的阴影的定点。图形学中一般的做法就是先计算出这个转变向量,然后利用这个转变向量,把原物体转换成阴影物体,就可以把阴影渲染在平面上了。
而在DirectX中就是可以调用现成的API生成所需要的矩阵:
D3DXMATRIX *D3DXMatrixShadow(
D3DXMATRIX *pOut, //我们所需要的矩阵
CONST D3DXVECTOR4 *pLight, // 光源
CONST D3DXPLANE *pPlane // 阴影所在的平面
);
利用Stencil 缓冲技术来防止多重Blending
我们画阴影需要再一个平面上画的,但是原图形是立体的,那么会发生多个几何图形重叠的情况,比如一个物体的正反面重叠子一起,那么通过多次画图就会使得阴影物体更加黑。为了得到正确明暗程度的阴影就要用到Stencil技术了。当然如果不用也可以画出来,不过就是阴影部分更加黑罢了。
具体做法就是:我们把阴影部分标记到stencil buffer中,然后如果第二次再次写像素到同样的阴影部分的时候就拒绝写入,也就是stencil test会失败。(当然程序还是正常运行的)。这样的话,我们就只画了一次阴影部分。
Direct3D代码示例:
1.参数设置
gd3dDevice->SetRenderState(D3DRS_STENCILENABLE, true);//开启Stencil buffer
HR(gd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);//设置stencil测试函数为等于函数
HR(gd3dDevice->SetRenderState(D3DRS_STENCILREF, 0x0);//设置ref的值为0
HR(gd3dDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff);//Mask蒙蔽层的值为1
HR(gd3dDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);//写入蒙蔽层也为1
HR(gd3dDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);//stencil测试失败则保持原有的颜色
HR(gd3dDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
HR(gd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);//这要设置,已经写入一次的像素位置就不能再次写入其他像素了
2. 计算和定位阴影
// Position shadow.
D3DXVECTOR4 lightDirection(0.577f, -0.577f, 0.577f, 0.0f);
D3DXPLANE groundPlane(0.0f, -1.0f, 0.0f, 0.0f);
D3DXMATRIX S;
D3DXMatrixShadow(&S, &lightDirection, &groundPlane);//这里得出阴影的转换矩阵
// Offset the shadow up slightly so that there is no
// z-fighting with the shadow and ground.
D3DXMATRIX eps;
D3DXMatrixTranslation(&eps, 0.0f, 0.001f, 0.0f);//这里是Z-fighting技术,简单的来说就是当两个物体(这里是指阴影和平面)的深度测试(depth testing)发生重复的时候,就可能会出问题,例如像素会闪烁,这个时候,可以稍微把其中一个物体(这里是阴影)的位置移一点点。但是据我的实验可知,问题不会很大,还是可以正常显示的,无闪烁,不过为了安全起见,那么移动一下吧。
// Save the original teapot world matrix.
D3DXMATRIX oldTeapotWorld = mTeapotWorld;
// Add shadow projection transform.
mTeapotWorld = mTeapotWorld * S * eps;//这里进行正式转换
3. 最后我们设置颜色,黑色,透明度50%,然后恢复原来的参数设置:
// Alpha blend the shadow.
gd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);//开启Alpha blending
gd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA));
gd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
drawTeapot();//这里是画一个茶壶
// Restore settings.
mTeapotWorld = oldTeapotWorld;
gd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
gd3dDevice->SetRenderState(D3DRS_STENCILENABLE, false);
总结:
这里是平面阴影技术,如果要做复杂的阴影的话,比如水面上的,和乱石中的阴影那就要用更加深的技术了,需要更多的知识,后续在继续贴出来吧。
Reference:
Introduction to 3D Game Programming with DirectX9.0C Shader Approach (DirectX 的 龙书 封面是条红龙的)
分享到:
相关推荐
C# DirectX 小例子2,大家可以看看
在vs2005环境下,用directX实现用户控制方格位置的简单功能
DirectX 11高级图形开发技术实战 pdf
directx写的阴影例子源码,带汇编,带.x模型文件,极好的3d参考源码
DirectX 11高级图形开发技术实战 PDF电子书下载 带书签目录 完整版.7z.002
开发工具: Microsoft Visual Studio 2005 Microsoft DirectX 9.0 SDK Update
DirectX9:平面阴影示例程序,包括灯光,地面世界矩阵,圆柱世界矩阵等详细说明
精通directx3d图形与动画程序设计光盘
精通DirectX 3D图形与动画程序设计 光盘内容运行测试后再上传
关于DirectX 3D图形与动画程序设计,对DirectX 3D编程进行深入剖析。
精通directx3d图形与动画程序设计光盘.part02
精通DirectX 3D图形与动画程序设计电子版 pdf,书已经绝版了,文件有100多M,分成两部分
DirectX 3D图形与动画程序设计附带光盘源代码,拿出来与大家一起学习分享,第三部分
这个是用DirectX做的阴影效果,是从一位C++的源代码翻译过来的,非常不错。 我翻译的也比较辛苦呵呵。 原来的代码的主人是来自这里的吧。是C++做的。 ...
精通DirectX 3D图形与动画程序设计(源代码) 第二十一章 HLSL高级应用王德才编著
详细介绍directx9的三维图形动画程序开发方法
对图形学的概括 介绍图形学方向 如何进入图形学领域 DirectX Dec2005 SDK
很好的讲解DX9进行3D图形开发的书籍,适合一步步的学习,PDG格式。
阴影映射,DirectX,Shadow,书本源码,很不错,VS下调试通过!
directx显示部分教程,每一章都有例子,语言精练不枯燥,偶然发现的非常不错的教程,大家快下.