网页功能: 加入收藏 设为首页 网站搜索  
VB中应用卡通渲染
发表日期:2007-01-26作者:[转贴] 出处:  

卡通渲染有很多样式,这里仅介绍轮廓中最常用的线框渲染。

我们先判断网格中那些边是轮廓边那些不是,将是轮廓边的渲染出来就得到效果了。究竟那些边才是轮廓边那?——如果与边相邻的两个面相对于视线的方向有不同的方向,也就说是如果一个面向观察者前面而另一个面是面向后面,那么它就是轮廓边。下面的图表示了轮廓边和非轮廓边:



一条边是由两个顶点组成的,为了计算边是否是轮廓边,我们必须为其两个顶点的定义中加入两个法线向量,再送到顶点渲染中处理,(对于输入的数据VS并不知道那些是顶点那些是法线信息,只有输出的数据才是有意义的。这里我们选用VS1.0,显卡会进行高速计算,即使显卡不支持CPU也能快速模拟)

自定义顶点类型如下:
Type CUSTOMVERTEX
postion As D3DVECTOR
normal1 As D3DVECTOR
normal2 As D3DVECTOR
End Type

我们定义两个额外的法线向量,Normal1和Normal2。这两个向量表示共用这个边的两个面(face0和face1)的法线。


下面是验证的数学方程。假设我们在view空间里,令v为从原点到我们要测试的顶点的向量--如上图,n0为面face0的法线,n1为面face1的法线。那么满足下面的不等式的顶点就是轮廓:

(v*n1)(v*n2)<0

现在还有两个问题,如果线段在边界或在棱角上,绘图上通常也是将它画出的,如下图:




我们总是让这两种边为可见轮廓边。

边界的判断方法:只有一个三角形与其相邻

棱边的判断方法:如果它的2个法线点积小于一阀值(-1到1之间),我们就可认为它算是一条棱边。

为了让VS处理,令Normal2=-Normal1,这样,不等式总是为真

寻找轮廓边可以这样:

for I=0 to 网格面数

计算当前面的法线

normal1=当前面的法线

Normal2=-Normal1

for J=0 to 网格三角面数

if 第1条边有与其相邻的三角面(除本身) then

if 与其相邻面的夹角<阀值 then normal2=相邻面的法线

endif

next

 

处理第2条边......

处理第3条边......

next

 

Vertex Shader定义:

Dim shaderCode As D3DXBuffer
decl(0) = D3DVSD_STREAM(0)
decl(1) = D3DVSD_REG(0, D3DVSDT_FLOAT3) 'v0输入寄存器为顶点位置,三位浮点数
decl(2) = D3DVSD_REG(3, D3DVSDT_FLOAT3) 'v3输入寄存器为法线向量1,三位浮点数
decl(3) = D3DVSD_REG(6, D3DVSDT_FLOAT3) 'v6输入寄存器为法线向量2,三位浮点数
decl(4) = D3DVSD_END()

'创建顶点渲染

device.CreateVertexShader decl(0), shaderArray(0), shader, D3DUSAGE_SOFTWAREPROCESSING
device.SetVertexShader shader '设置顶点渲染

...

D3DXMatrixMultiply m, matWorld, matView
D3DXMatrixTranspose m, m
device.SetVertexShaderConstant 1, m, 3 'c3常量寄存器为world * view 来计算view空间里的法线
D3DXMatrixMultiply m, matWorld, matView
D3DXMatrixMultiply m, m, matProj
D3DXMatrixTranspose m, m
device.SetVertexShaderConstant 5, m, 4'c5常量寄存器为world * view * proj
registroC(0) = 0
registroC(1) = 0.5
registroC(2) = 0
registroC(3) = 0
device.SetVertexShaderConstant 0, registroC(0), 1 'c0常量寄存器为一些常量
registroC(0) = -0.4
registroC(1) = 0.1
registroC(2) = -0.5
registroC(3) = -0.0001
device.SetVertexShaderConstant 10, registroC(0), 1 'c10常量寄存器为灯光方向和Z偏差
With cubo.mateX.diffuse
coloreM(0) = .r: coloreM(1) = .g: coloreM(2) = .B: coloreM(3) = 0
device.SetVertexShaderConstant 9, coloreM(0), 1 'c9常量寄存器为颜色

End With


'设置只有ALPHA值小于等于0时才向屏幕输出:

device.SetRenderState D3DRS_ALPHATESTENABLE, True
device.SetRenderState D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL
device.SetRenderState D3DRS_ALPHAREF, (0)

device.DrawIndexedPrimitive D3DPT_TRIANGLELIST, ......

 
VS代码(shver2.txt):

; Inputs: v0 = Positi
; v3 = Normali1
; v6 = Normali2
; c0 = Costanti utili (0,0.5,xxx,xxx)
; c1-4 = WorldView matrix
; c5-9 = WorldViewProjection matrix


vs.1.0 ; 版本声明

m4x4 r6, v0 , c5
add r6.z,r6.z,c10.w ; 设置Z偏差
mov oPos,r6 ; 输出顶点位置


m4x4 r0 , v0 , c1 ; r0 = view空间的位置
m3x3 r1 , v3 , c1 ; r1 = view空间的法线1
m3x3 r4 , v6 , c1 ; r6 = view空间的法线2
dp3 r3.x , r0 , r1 ; 计算v*n1
dp3 r5.x , r0 , r4 ; 计算v*n2
dp3 r3.x , r3.x, r5.x ; 计算(v*n1)(v*n2)
max r3.x ,r3.x , c0.x ; 将 r3.x 限制到0,(这样所有满足(v*n1)(v*n2)<0会成为0)
mov oD0.w , r3.x ; 输出ALPHA值
mov oD0.xyz , c0.x ; 输出反射光颜色(0,黑色)
 
最后可以看一下代码,本人未作多少优化,加之VB本身原因所以速度较慢,但能处理材质。你可根据情况随意修改。

档案下载
我来说两句】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 VB中应用卡通渲染
本类热点文章
  DDraw和D3D立即模式编程手册
  矩阵求逆的快速算法
  本地化支持:OGRE+CEGUI中文输入:OGRE方..
  Direct3D中实现图元的鼠标拾取
  3D场景中的圆形天空顶
  OpenGL显卡编程
  一种高效的基于大规模地形场景的OCCLUS..
  一个完善的读取3DS文件例子
  如何制作一个可控制的人体骨骼模型
  Direct3D 入门之我见
  Slope(斜坡) 法线生成算法,在地形渲染..
  新手翻译的FAQ--可视和转换(学opengl两..
最新分类信息我要发布 
最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放  
Copyright ©2003-2024 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00552