http://www.cnblogs.com/lancidie/category/222816.html
这个人写了很多D3D的东西,有空过去看看
可编程管道下的相机裁剪(这个问别人的,也不知道对不对)
有一个方法是根据世界矩阵,相机矩阵,投影矩阵计算出视锥体(可以是模型坐标系下的,可以是世界坐标系下的,也可以是相机坐标系下的),关于怎么求这个视锥体
http://www.cnblogs.com/lancidie/archive/2010/10/11/1847764.html,用这个视锥体对场景进行裁剪,裁剪后的点送到vertex shader里面,这个是程序主动裁剪的,
还有一部分是程序自动裁剪的
在过去的固定渲染管道时代,剪裁平面的实现较为简单,比如在DirectX 9中,可以先设定剪裁平面在世界坐标系下的方程(ax+by+cz+d=0),再调用SetClipPlane(DWORD Index,CONST float * pPlane)这个API函数就可以了。
附上例子程序:
vPosition=D3DXVECTOR3(0,0,0);//平面上一个点
vNormal=D3DXVECTOR3(0,1,0);//法向量
D3DXPlaneFromPointNormal( &clipplane, &vPosition, &vNormal );//生成剪裁平面
m_pDevice()->SetClipPlane( 0, (float*)clipplane);
这么做的话平面下方的点都会被裁剪,
但是如果在可编程管道的情况下,你设置的裁剪平面方程会被认为是在裁剪坐标系下的,所以当你在可编程管道的情况下调用SetClipPlane函数的时候会发生错误,
这个时候如果你把你的裁剪平面方程变换到裁剪坐标系下,然后调用SetClipPlane的时候就会正确了,这个时候vertex shader会自动的裁剪掉所有裁剪平面以下的点
如果使用的是固定渲染管线(没有使用着色器),裁剪面的方程式(也就是ax+by+cz+d=0中的a、b、c、d),被认为是世界空间中的。
如果使用顶点着色器代替了固定管线,裁剪面的方程式就被当成裁剪空间中的,个人觉得所谓的裁剪空间也就是透视投影空间。
方法2:不管那么多,直接定义裁剪平面方程,将这个平面传到shader里面,直接在shader里面计算每一个点是否应该被裁剪掉,
或者直接根据裁剪平面方程,定义一个矩阵,使位于平面以下的点经过这个矩阵变换后被裁剪掉,然后直接把这个矩阵传到shader里面,
在vertex shader里面进行这个矩阵的变换来裁剪掉你不需要的点
当" locking vertex buffers_锁定顶点缓存"时:
如果顶点缓存的创建标志是POOL_DEFAULT:
如果没有指定任何标志,程序将被暂停,因为它强制程序和GPU同步操作。->低效
如果指定D3DLOCK_NOOVERWRITE 标志,应用程序不会改变缓存区已存在的内容,运行库会在以后继续使用这块缓存。当应用程序调用这个函数时,驱动程序立即返回。->高效
如果指定D3DLOCK_DISCARD 标志,程序将会更新整个缓存的值,实际上是分配一块新的缓存,即驱动程序重命名它。->高效
[注解:因为CPU和GPU是异步的操作,所以当CPU通过系统总线和GPU同步时,需要等到GPU把当前的工作做完。例如,当GPU正在对一块缓存进行DMA操作时,但往往CPU并不对GPU操作的那块缓存进行操作,所以CPU可以和GPU一起工作。当不指定操作标志时,CPU等待GPU完成绘制工作才更新顶点缓存,所以低效。如果指定D3DLOCK_NOOVERWRITE,表示CPU只更新顶点缓存中剩余的缓存,不考虑是否有其他图形绘制是正在使用这个的缓冲区段绘制图形,强制更新那段缓存并返回,而不像默认参数0那样等待前面的绘制结束,而不更新已经写入的顶点值,所以在CPU写入的时候,GPU可以并行的对那些已经存在的顶点值进行DMA等操作,所以高效;如果使用D3DLOCK_DISCARD 标志,说明当前分配的缓存大小不够了,需要重新使用缓存,CPU对这些新分配的缓存区域进行写操作,GPU这时可能还在异步处理旧的缓存区,所以这种调用也是高效的。调用完毕,收回释放的缓存。]
D3DLOCK_NOOVERWRITE:表示你的程序可以肯定,对于你将要锁定的buffer中进行修改的那部分数据,绝对之前没有在提交的dp范围内,就是绝对不会over write已经dp的数据,这样GPU的DMA操作不会被打断,它可以放心把这个大buffer交给你控制,而你只写入一部分,同时gpu可以读取同一buffer的其他部分(你刚才dp提交的),这样保证gpu和cpu协同工作,没有idle产生。D3DLOCK_DISCARD:当你对于这个buffer已经有的内容不感兴趣,比如对于cpu驱动的骨骼动画,你cpu保留了所有数据,cpu计算完毕,准备上传新一帧的动画,那就discard原先的数据,那gpu如果用完了buffer,那它直接把这个buffer返回给你,如果它正忙着使用这个buffer,那它给你创建个新buffer,对于而言,这些透明。
这俩flags非常关键,不用不行。特别对于粒子系统这样需要频繁更新的系统,一定要慎重。
一点理解仅供参考。
lock和unlock是为了CPU和GPU的同步设计的
//将光源位置转换成ARGB的辅助函数:
DWORD Vector2ARGB(D3DXVECTOR3 *v,float height)
{
DWORD r=(DWORD)(127.0f*v->x+128.0f);
DWORD g=(DWORD)(127.0f*v->y+128.0f);
DWORD b=(DWORD)(127.0f*v->z+128.0f);
DWORD a=(DWORD)(255.0f*height);
return((a<<24L)+(r<<16L)+(g<<8L)+b);
}
//生成法线图:
D3DXComputeNormalMap(pNormalMap,pHeightMap,NULL,0,D3D_CHANNEL_RED,1.0f);//pHeightMap为原高度图的指针,pNormalMap为一张空纹理,用于存放法线图
//在渲染程序段中实现:
{
DWORD F=Vector2ARGB(&light,0.0f); //light是单位化的光源向量
pD->SetRenderState(D3DRS_TEXTUREFACTOR,F);//pD是D3D的设备指针,这句将光源法线参数输入
pD->SetTexture(1,pTEXTURE);//设置原纹理,如上面的球,如有需要可以贴上纹理样式
pD->SetTexture(0,pNormalMap);//使用上面生成好的法线图
pD->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);//设置“来源1”为法线图
pD->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3);//将“来源1”(法线图)与“来源2”(光源法线)进行点乘
pD->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_TFACTOR);//设置“来源2”为光线的光源法线参数
pD->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_TEXTURE);//这步和下面几步将图片的原纹理加上
pD->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_MODULATE);
pD->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_CURRENT);
}
下面是发线图的生成方法(根据高度图生成的)
//将光源位置转换成ARGB的辅助函数:
DWORD Vector2ARGB(D3DXVECTOR3 *v,float height)
{
DWORD r=(DWORD)(127.0f*v->x+128.0f);
DWORD g=(DWORD)(127.0f*v->y+128.0f);
DWORD b=(DWORD)(127.0f*v->z+128.0f);
DWORD a=(DWORD)(255.0f*height);
return((a<<24L)+(r<<16L)+(g<<8L)+b);
}
//生成法线图:
D3DXComputeNormalMap(pNormalMap,pHeightMap,NULL,0,D3D_CHANNEL_RED,1.0f);//pHeightMap为原高度图的指针,pNormalMap为一张空纹理,用于存放法线图
//在渲染程序段中实现:
{
DWORD F=Vector2ARGB(&light,0.0f); //light是单位化的光源向量
pD->SetRenderState(D3DRS_TEXTUREFACTOR,F);//pD是D3D的设备指针,这句将光源法线参数输入
pD->SetTexture(1,pTEXTURE);//设置原纹理,如上面的球,如有需要可以贴上纹理样式
pD->SetTexture(0,pNormalMap);//使用上面生成好的法线图
pD->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);//将纹理层0的纹理颜色作为第一个颜色来源
pD->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3);//将“来源1”(法线图)与“来源2”(光源法线)点乘
pD->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_TFACTOR);//将D3DRS_TEXTUREFACTOR作为第二个颜色来源
pD->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_TEXTURE);//将纹理层1的纹理颜色作为第一个颜色来源
pD->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_MODULATE);
pD->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_CURRENT);//将上一个纹理层的输出颜色作为第二个颜色来源
}
不要混淆了法线映射和凸凹映射这两种技术。虽然这两种技术都使用一种名为“凸凹贴图”或“法线贴图”的图像,但它们还是存有差别。差别在于图像的创建方式。凸凹映射技术使用的图像创建于灰度(从黑到白)2D纹理图像,有时候这个图像也称为“高度图”。
法线映射技术使用的图像创建于高分辨率模型(角色、物体等)中的细节,并将其保存到纹理中,这样在凸凹映射中使用时,低分辨率模型看上去就像是或是类似于高分辨率模型。这两个主题都已经超出了本书的讨论范围,但要注意的是法线映射是一种凸凹映射,它用于使低分辨率模型看上去像是高分辨率模型,而凸凹映射提取所有的2D图像,并从中创建法线。
而凹凸贴图本身就是一张2D的黑白图(又叫高度图),他并不会改变物体的表面,而只是影响光照的结果
最简单的做法是,直接把Bump Map叠加在已经渲染好的表面上,造成亮度上的扰动,从而让人以为是凹凸的,只是做简单的加减法
法线贴图里存储的是高分辨率下模型的法向量,而当我们想要渲染低分辨率下的模型的时候,用法线贴图里面的法向量来代替模型的法向量进行光照计算,这个是从根本上改变了物体的表面,所以法线贴图更真实
Stencil buffer,中文翻译为“模板缓冲区”,它是一个额外的buffer,通常附加
到z buffer 中,例如:15 位的z buffer 加上1 位的stencil buffer(总共2 个字节);
或者24 位的z buffer 加上8 位的stencil buffer(总共4 个字节)。每个像素对应
一个stencil buffer(其实就是对应一个Z buffer)。 Z buffer 和stencil buffer 通常在
显存中共享同一片区域。Stencil buffer 对大部分人而言应该比较陌生,这是一个
用来“做记号”的buffer,例如:在一个像素的stencil buffer 中存放1,表示该像素
对应的空间点处于阴影体(shadow volume)中。
被放在内存区域(general main memory)
一般情况下着色器分为两种:顶点着色器和像素着色器,有时候又会有个叫片段着色器的东东Fragment Shader
附:什么是片断?片断和像素有什么不一样?所谓片断就是所有的三维顶点
在光栅化之后的数据集合,这些数据还没有经过深度值比较,而屏幕显示的像素
都是经过深度比较的。