着色器和效果——2.5 样例应用程序:卡通渲染(下)

原创 2004年05月17日 23:05:00

2.5 样例应用程序:卡通渲染(下)

阅读此文表明您已同意文末的声明

2.5.3 轮廓勾勒

要完成卡通效果,我们还需要勾勒outline轮廓边silhouette edge)。这比卡通着色复杂一点。

2.5.3.1 边的表示法

我们将一个网格的一条边表示为一个四元组(从两个三角形构建)——参见图2.5

2.5:表示边的四元组

我们选择四元组有两个原因:我们可以通过调整四元组的维容易的改变边的厚度,并且我们可以渲染退化的四元组来隐藏某些边,也即轮廓边。在Direct3D中,我们从两个三角形来构建一个四元组。退化四元组degenerate quad)是从两个退化三角形构建而来的四元组。退化三角形degenerate triangle)是一个面积为零的三角形,或者换句话说,是一个三点位于一线上的三角形。如果我们传入一个退化三角形到渲染管线,则该三角形显示为空。这是很有用的,因为如果我们希望隐藏特定三角形,我们可以简单的退化它而不需要实际的从三角形列表(顶点缓冲)移除它。回想一下,我们只需要显示轮廓边——而不是网格的每一条边。

当我们首先创建一条边的时候,我们指定其四个顶点,并使其退化,这意味着边将会被隐藏(渲染时不显示)。

2.6:由两个三角形共用边描述的退化四元组

注意图2.6中的两个顶点v0v1,我们设置其顶点法线向量为零向量。然后当我们将边的顶点送入顶点着色器的时候,顶点着色器将会检测顶点是否位于轮廓边上;如果是,则顶点着色器将按顶点法线的方向偏移顶点位置的标量。观察法线向量为零的顶点,它不会被偏移。

因此,我们最终以一个非退化四元组non-degenerate quad)来表示轮廓边,如图2.7所示。

2.7:位于轮廓边上的顶点v2v3被按照其各自的顶点法线n2n3进行偏移。观察顶点v0v1仍然保持在其固定位置,因为其顶点法线等于零向量,因此对于它们来说没有偏移发生。按这种方式,四元组成功的重新生成来表示轮廓边。

备注:如果我们没有设置顶点v0v1的顶点法线为零向量,那么那些顶点就同样会被偏移。但是如果偏移描述轮廓边的所有四个顶点,那么我们仅是平移了该退化四元组。通过保持顶点v0v1固定并仅仅偏移顶点v2v3,我们重新生成了四元组。

2.5.3.2 轮廓边测试

若两个表面face0face1以与视图方向相异的方向共享边所在表面,则该边为轮廓边。也就是说,如果一个表面是前面front facing)而另一个表面是后面back facing),那么这条边就是一条轮廓边。图2.8给出了一个轮廓边和一个非轮廓边的例子。

2.8:在(a)中,由v0 v1定义的共享边的一个表面是前面,而共享边另一个表面是后面,因此该边是轮廓边。在(b)中,由v0 v1定义的这两个共享边的表面都是正面,因此该边不是轮廓边。

接下来,为了检测一个顶点是否在轮廓边上,我们必须以每个顶点为基础了解face0 face1的法线向量。我们的边的顶点数据结构反映如下:

struct VS_INPUT

{

     vector position    : POSITION;

     vector normal      : NORMAL0;

     vector faceNormal1 : NORMAL1;

     vector faceNormal2 : NORMAL2;

};

前两个分量很直接,但让我们看看两个额外的法线向量,它们是faceNormal1faceNormal2。这些向量描述了两个表面的表面法线,共享边的顶点位于这两个表面的共享边上,这两个表面是face0face1

实际检测顶点是否在共享边上的数学如下。假设我们在视图空间中,令v为一原点指向检测顶点的向量——图2.8,令n0face0的表面法线且n1face0的表面法线,若下面的不等式为真,则顶点位于轮廓边上:

1v·n0)(v·n1)<0

若两点积符号相异,则不等式为真,使得不等式左边为负。回想一下点积的性质,两个点积的符号相异意味着一个表面是前面而另一个是后面。

现在,考虑一条边只有一个三角形共享它的情况,如图2.9,其法线将会被存储在faceNormal1中。

2.9:顶点v0v1定义的边只有一个表面共享它

我们定义这种边为轮廓边。要确保顶点着色器将这种边作为轮廓边处理,我们要让faceNormal2 = -faceNormal1。因此,反向的表面法线和不等式(1)为真,表示该边为一轮廓边。

2.5.3.3 边的生成

生成网格的边是微不足道的;我们简单的遍历网格的每个表面并为表面上每条边计算一个四元组(退化的,如图2.6所示)。

注意:每个表面有三条边,因为每个三角形有三条边。

对于每条边的迭代,我们也许要知道共享边的两个表面。表面之一是边所在的三角形。例如,如果要计算第1个表面的一条边,那么第1个表面共享该边。共享该边的另一个表面可以使用网格的邻接信息找到。

2.5.4 轮廓边顶点着色器代码

我们现在呈现渲染轮廓边的顶点着色器代码。这个着色器的主要任务就是确定传入的顶点是否在轮廓边上。如果是,顶点着色器就按顶点法线的方向偏移顶点一定量的数值。

// File: outline.txt

// Desc: Vertex shader renders silhouette edges.

 

//

// Globals

//

 

extern matrix WorldViewMatrix;

extern matrix ProjMatrix;

 

static vector Black = {0.0f, 0.0f, 0.0f, 0.0f};

 

//

// Structures

//

 

struct VS_INPUT

{

     vector position : POSITION;

     vector normal : NORMAL0;

     vector faceNormal1 : NORMAL1;

     vector faceNormal2 : NORMAL2;

};

 

struct VS_OUTPUT

{

     vector position : POSITION;

     vector diffuse : COLOR;

};

 

//

// Main

//

 

VS_OUTPUT Main(VS_INPUT input)

{

      // zero out each member in output

      VS_OUTPUT output = (VS_OUTPUT)0;

 

      // transform position to view space

      input.position = mul(input.position, WorldViewMatrix);

 

      // Compute a vector in the direction of the vertex

      // from the eye. Recall the eye is at the origin

      // in view space - eye is just camera position.

      vector eyeToVertex = input.position;

 

      // transform normals to view space.  Set w

      // components to zero since we're transforming vectors.

      // Assume there are no scalings in the world

      // matrix as well.

      input.normal.w      = 0.0f;

      input.faceNormal1.w = 0.0f;

      input.faceNormal2.w = 0.0f;

 

      input.normal      = mul(input.normal,      WorldViewMatrix);

      input.faceNormal1 = mul(input.faceNormal1, WorldViewMatrix);

      input.faceNormal2 = mul(input.faceNormal2, WorldViewMatrix);

 

      // compute the cosine of the angles between

      // the eyeToVertex vector and the face normals.

      float dot0 = dot(eyeToVertex, input.faceNormal1);

      float dot1 = dot(eyeToVertex, input.faceNormal2);

 

      // if cosines are different signs (positive/negative)

      // then we are on a silhouette edge. Do the signs

      // differ?

      if( (dot0 * dot1) < 0.0f )

      {

           // yes, then this vertex is on a silhouette edge,

           // offset the vertex position by some scalar in the

           // direction of the vertex normal.

           input.position += 0.1f * input.normal;

      }

 

      // transform to homogeneous clip space

      output.position = mul(input.position, ProjMatrix);

 

 

      // set outline color

      output.diffuse = Black;

 

      return output;

}

[声明]:本文译自Frank Luna的《Introduction to 3D Game Programming with DirectX 9.0》,限于译者水平,文中难免错漏之处,欢迎各位网友批评指正;本文仅用于学习交流与参考用途,不得用于任何形式的商业用途;如需转载需事先征得作者本人和译者的同意,保持文章的完整性,并注明作者、译者和出处,作者保留对译文的所有权利。对于违反以上条款造成的后果,译者对此不负任何责任。我的MSNRaymond_King123@hotmail.com,欢迎热爱3D图形和游戏,并有一定图形编程经验的朋友与我进行交流。

Unity自带Shader(一)(卡通着色)

前言:最近有必要系统的学习下shader了,虽然平时也用着,原理什么的都懂,而且觉得应用层的shader特别简单,真的难的是隐藏在shader后面的算法,这里准备了一个系列,这个系列是对unity 标...
  • pdw_jsp
  • pdw_jsp
  • 2017年01月07日 15:12
  • 2407

【Unity Shader实战】卡通风格的Shader(二)

写在前面好久没写博客了,一定是因为课程作业比较多,一定不是因为我懒,恩恩。三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Shader中实现描边效果的弊端,也就是只对表面平...
  • candycat1992
  • candycat1992
  • 2014年11月14日 17:58
  • 19121

OpenGl中使用着色器的基本步骤及GLSL渲染简单示例

OpenGL着色语言(OpenGL Shading Language,GLSL)是用来在OpenGL中着色编程的语言,是一种具有C/C++风格的高级过程语言,同样也以main函数开始,只不过执行是在G...
  • dcrmg
  • dcrmg
  • 2016年12月14日 23:34
  • 5071

Irrlicht使用着色器渲染模型(演示程序+源代码)

  • 2013年11月29日 21:31
  • 1.44MB
  • 下载

以砖块着色器为例的NDK程序

  • 2015年04月26日 10:43
  • 3.42MB
  • 下载

基于threejs开发的卡通风格着色器(二)

上次给球体添加了卡通风格着色器之后觉得还少些什么,仔细观察网上卡通风格的游戏发现,卡通风格的3D任务往往除了明显不平滑过渡的色块以外,还都有着黑色描边,这次我们就来修改着色器实现描边的效果。    ...
  • srk19960903
  • srk19960903
  • 2017年04月04日 16:04
  • 373

基于threejs开发的卡通风格着色器

作为一个大学一直在玩3D的同学,还是应该多写写关于3D的东西,正好把原来做得着色器整理整理,供大家参考也供自己以后回顾吧~         一般的现实中的物体讲求一个平滑着色,能够使其看起来更加真实...
  • srk19960903
  • srk19960903
  • 2017年03月28日 20:49
  • 241

跨平台二维绘图程序(二)——着色器shader

学习使用GLES,首先要写着色器。       与OpenGL ES1.x渲染管线相比,OpenGL ES 2.0渲染管线中“顶点着色器”取代了OpenGL ES 1.x渲染管线中的“变换和光照”;...
  • wayright
  • wayright
  • 2017年08月02日 12:19
  • 108

Windows桌面应用程序(1-1-2-3rd) 使用着色器和着色器资源

现在是学习如何使用着色器和着色器资源开发Windows 8的Microsoft DirectX游戏的时候了。我们已经看到如何设置图形设备和资源,甚至可能已经开始修改其管道。所以现在让我们看看像素和顶点...
  • qq_37422196
  • qq_37422196
  • 2017年12月21日 20:12
  • 114

Hx Volumetric Lighting 着色器/全屏幕及相机效果

  • 2017年07月07日 01:01
  • 2.07MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:着色器和效果——2.5 样例应用程序:卡通渲染(下)
举报原因:
原因补充:

(最多只允许输入30个字)