Pv3D7着色.docx
《Pv3D7着色.docx》由会员分享,可在线阅读,更多相关《Pv3D7着色.docx(29页珍藏版)》请在冰点文库上搜索。
Pv3D7着色
在第四章中,我们学习了如何贴图(将材质应用到物体上)。
选择合适的材质可以使物体显得更加细腻。
Shading(着色)可以让贴图呈现多个层次从而在纵深和真实感上增加立体感效果。
Papervision3D内置了多种Shading(着色器)类型。
统一称作shaders。
(放在org.papervision3d.materials.shaders包中)
这一章主要讲述一下主题
●Shading的介绍
●Shading(着色)和光线基础知识
●Bumpmapping(凹凸贴图)(译者注:
Bumpmapping是在像素级别扰动物体表面法向量的一种光照技术,它一般采用纹理映射作为输入表示扰动的大小。
在光照计算时考虑到扰动的法向量,不需要增加额外的几何信息就可以增强被渲染物体的表面细节。
)
●映射贴图
Shading(着色)的介绍
Shading往往用来处理光线在三维物体的材质上作用效果,由于光线的存在就会在物体表面形成或明或暗的区域。
可以想象一个单色的立方体。
当所有的面使用同一种颜色时,就像下面这个图例那样,这个立方体就很难被辨认出。
如果我告诉你他就是一个立方体,那么你只要用你的想象力,确实是可以觉得他是一个立方体。
但事实是,如果没有上下文的提示,是不太可能看出这是一个立方体的。
再看一看我们在立方体的材质上运用了阴影效果后的下图:
它看起来更像一个立方体了,不是吗?
由于物体的每一个面和光源存在角度,每个面上的颜色就会或明或暗。
为了达到这种效果你可以为每个面定义一种材质色。
在某些场合下,也许这就足够了。
但是实时着色可以提供更好的逼真度,当物体的外观参数由于动态的光源,或者物体,再或者照相机导致的改变时这点尤其重要。
依赖于物体的位置和旋转度的改变,使用了实时着色的物体的外观也就自动改变了。
上面的图中每个面上都是单色着色。
每一个三角形上的每一个像素的颜色被自动的测定,形成一个非常完美和光滑的纹理(阴影效果),遗憾的是做这样的处理很耗费CPU资源。
因此更高效的阴影处理被创造出来。
这些处理有些虽然精确度不高但仍然给你的物体增加了合适的逼真度。
Shading(着色)也包含了Bumpmaps(凹凸贴图)和environmentmaps(环境贴图)。
Bumpmaps常用于在你的3D物体上模拟出起伏不平的假象,environmentmaps用于将环境映射到一个3D物体上。
为了更好的理解每种着色类型的参数,可以去打开一个叫“shadingTypesDemo.swf”一个示例.这个示例演示了每一种着色类型,并且可以实时的调节它的参数。
这个示例中用了著名的Utah茶壶模型。
除了用于讲解3D概念,它的子对象有多种3D形状。
这个Utah茶壶可以让你更好的理解各种类型的着色效果在这个物体是如何实现的。
再接下来的段落中你可以随意设置每一种着色类型的参数来帮助你理解。
两种着色原理:
●完全基于光照对物体进行着色
●基于已存在的材质对物体进行着色
在接下来的部分我们将详细解释这些概念。
Flatshading(平面着色)
FlatShading(着色渲染)是最基础和最轻量级的作色方法.演示文件ShadingTypesDemo.swf一打开后看到的效果就是使用这种方式。
这种方式下,每一个对象的三角形面用某种颜色色来着色。
颜色由每一个三角形面法线和光位置之间的角度来确定。
由于相邻的两个三角形之间的颜色没有进行差值化处理,这样就会导致两个三角形面块颜色上有比较大的差异就像被一条线隔开了,真实度不太好。
在三维模型中使用的话这种不好的感觉就更强了。
拥有成对三角形的模型,他们共享相同的面法线。
基于多边形而非三角形的平面着色,使得物体给我们怪怪的感觉
面法线在这个例子中就是三角形面上的垂直向量。
法线表示了一个面的方向,下面的插图标明了六对三角形的法线,这些成对的三角形看上去更像一个个多边形
高级的着色使用顶点法线,它是取一个顶点的相邻的三角形面的法线的平均值。
在刚开始介绍着色时,提及到有两种方式创建着色效果。
接下来的例子我们用平面着色器来介绍这两种着色原理的差异和用法。
(提醒下此章节中有多个着色器,有两种作色原理)
●当你想用一种颜色对你的物体实施平面着色,你应该使用FlatShadeMaterial对象。
这种类型可以被当做材质而直接应用在任何3D物体上,而且它完全受光线参数来控制。
因此我们称之为“color-basedshader”(基于原色着色)。
●也许你想用位图材质(BitmapMaterial)来平面着色。
你可以用FlatShader对象和ShadedMaterial对象结合来使用。
ShadedMaterial对象将平面着色作用于位图素材上。
ShadedMaterial实例就能被当做物体的材质来使用了。
这时物体的外观就由光线和位图的组合来控制了。
Moivematerials(影片材质)也是bitmapmaterials(位图材质).
注意所有的材质都继承自(BitmapMaterial)位图材质。
这就意味着MovieMaterial,MovieAssetMaterial,BitmapAssetMaterial,VideoStreamMaterial这些材质实例都可以平面着色。
在写作本书的时候由于papervision3D的bug,BitmapFileMaterial材质对象不能被平面着色。
为了保持章节的一致性,我们在每一个例子中都将使用位图阴影材质,只要材质类型继承自位图材质(BitmapMaterial),你可以随意替换这些材质类型,除非你使用还存在bug的itmapFileMaterial对象。
注意接下来我即将出场的各种着色类型都会尝试有类似于基于颜色和基于位图的着色效果。
接下来我门将创建两个球来展示这两种平面着色原理的用法。
一种基于某种颜色,另一种基于一个位图。
一个成环形移动的光源为你在球面上展示出光对两个球外观的影响。
(译者注:
新手请将下面六页仔细的看看。
)
基于颜色的FlatShadeMaterial
这个例子需要导入一些额外的类,我们一会就会讨论到这些类。
importflash.display.Bitmap;
importflash.display.Loader;
importflash.events.Event;
import.URLRequest;
importorg.papervision3d.lights.PointLight3D;
importorg.papervision3d.materials.BitmapMaterial;
importorg.papervision3d.materials.shadematerials.FlatShadeMaterial;
importorg.papervision3d.materials.shaders.FlatShader;
importorg.papervision3d.materials.shaders.ShadedMaterial;
importorg.papervision3d.objects.primitives.Sphere;
创建一个灯光对象和一个角度变量以便在enterFrame事件中不断控制以调整灯光沿着圆运动。
privatevarlight:
PointLight3D;
privatevarangle:
Number=0;
在Papervision3D中唯一可用的光对象就是“点光源”。
可以简单的理解为三维空间中的某个点所发出的光。
在Papervision3D中每一种着色器都需要一个光源。
Papervision3D不提供任何其它类型的光源,比如聚光灯,平行光源。
如果要加入一个光源我们就要创建一个光源的实例(newPointLight3D())。
将这些操作放在init()方法中。
privatefunctioninit():
void{
light=newPointLight3D(true);
light.z=0;
light.y=300;
scene.addChild(light);
我们设置了第一个参数Boolean类型的变量为true,这样我们就可以清楚的看到光源所在的位置。
在正式使用时最好换成false,或者省略。
以上代码就将创建点光源放在了场景中。
为了表示出光源我们可以加入一个看得见位置的光源到场景中就像加入任何一种do3d(DisplayedObject3D)。
这在调试阶段是非常有用的,因为我们可以在3D空间中看到这个光源是被放在哪里。
点光源(PointLight3D)继承自3D显示对象(DisplayedObject3D),因此一个点光源对象拥有所有的do3D对象的所有属性和方法,比如localRotationX(旋转),yaw(偏转),lookAt()朝向。
但是这些属性和方法并不是都能奏效的。
只有涉及到点光源对象的位置变化的量发生改变时,才会影响到哪些使用此光源来处理的着色渲染(Shading)。
可以想象。
点光源在空间里只是一个点。
点的旋转和偏向等不会影响到光线的属性。
在光源的定义好后,我们继续创建基于颜色的平面着色材质。
创建FlatShadeMaterial对象时有四个参数。
让我们来看看它们分别是什么意思。
参数
数据类型
默认值
描述
1
light
点光源对象
LightObject3D
—
一个点光源对象的引用
2
lightColor
光源颜色
uint
0xFFFFFF
一个32位的16进制的颜色值,被用作点光源的光源色
3
ambientColor
环境色
uint
0x000000
一个32位的16进制颜色值,用来定义周围的环境色.这个增加的无方向性的光源往往体现在物体的某些三角形面上,这些三角形在光源背面不能发射来自点光源,这时候它就显示环境色。
4
specularLevel
反光度
uint
0
从0-255之间的一个数字。
表示反光度或者材质的光线反射率,数值越高物体吸收的光线就越多,默认为0,尽可能多的反射光线。
lightColor和ambientColor属性都可以表示成32位的颜色值,但是我们不能真正有效的使用光源的透明度,所以我们常常定义成24位的颜色值,省略了透明度的(0xAARRGGBB)AA就省略掉了,。
偶尔你也可能需要为其指定使用32位的颜色值。
以先前创建的light、白色光源、红色的环境色、反光度100作为参数新建一个FlatShadeMaterial实例,命名为:
shadeMaterial。
varshadeMaterial:
FlatShadeMaterial=newFlatShadeMaterial(light,0xFFFFFF,0xFF0000,100);
在Papervision3D中你只能设置一个光源作为着色器的光源。
虽然可以在一个场景中添加多个光源,但一个着色器只能使用一个光源。
将FlatShadeMaterial对象应用在一些规则材质上。
接下来就是创建一个使用刚刚创建的shadeMaterial材质的3d物体。
并加入到场景中。
varsphere:
Sphere=newSphere(shadeMaterial,250,10,10);
sphere.x=-300;
scene.addChild(sphere);
基于位图的平面着色渲染器
前面我们提到,有两种平面着色原理,我们现在已经成功的创建了一个平面着色的球,它完全是基于点光源着色的。
接下来我们就要创建一个位图着色材质。
为了使用位图,我们必须先手工导入它。
varimgLoader:
Loader=newLoader();
imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadComplete);
imgLoader.load(newURLRequest("assets/mill.jpg"));
}
一旦位图加载成功。
我们就创建一个位图材质的实例。
privatefunctionloadComplete(e:
Event):
void
{
varbitmap:
Bitmap=e.target.contentasBitmap;
varbitmapMaterial:
BitmapMaterial=newBitmapMaterial(bitmap.bitmapData);
这里我们创建一个FlatShader实例就如前面创建的FlatShadeMaterial实例,并且使用相似的参数来创建。
varshader:
FlatShader=newFlatShader(light,0xFFFFFF,0x000000,100);
对于这个着色渲染器我们传了个黑色环境光(0x000000)代替了先前使用的红色(0xff0000)。
我们不能将刚刚创建的FlatShader实例当做材质使用。
应以位图材质和着色器作为参数实例化一个ShadedMaterial对象。
如下所示:
varshadedMaterial:
ShadedMaterial=newShadedMaterial(bitmapMaterial,shader);
新创建的ShadeMaterial对象就可以用作物体的材质了。
然后我们创建另一个球。
第一个参数(材质)使用我们刚刚创建的对象,再加入场景中。
varsphere:
Sphere=newSphere(shadedMaterial,250,10,10);
sphere.x=300;
scene.addChild(sphere);
}
最后一步,为了让点光源绕着圆环运动,我们使用了正弦和余弦函数。
overrideprotectedfunctiononRenderTick(e:
Event=null):
void
{
light.z=Math.sin(angle)*400;
light.x=Math.cos(angle)*600;
angle+=0.01;
super.onRenderTick();
}
完整源码如下,并且译者加上了注解.也可以见本书的配套源文件。
当你编译你的代码后应该可以看到类似下面的效果
package{
//导入相关的类
importflash.display.Bitmap;
importflash.display.Loader;
importflash.display.StageAlign;
importflash.display.StageScaleMode;
importflash.events.Event;
import.URLRequest;
importorg.papervision3d.lights.PointLight3D;
importorg.papervision3d.materials.BitmapMaterial;
importorg.papervision3d.materials.shadematerials.FlatShadeMaterial;
importorg.papervision3d.materials.shaders.FlatShader;
importorg.papervision3d.materials.shaders.ShadedMaterial;
importorg.papervision3d.objects.primitives.Sphere;
importorg.papervision3d.view.BasicView;
publicclassFlatShadingExampleextendsBasicView
{
//声明一个私有属性点光源
privatevarlight:
PointLight3D;
//声明一个私有变量来记录点光源的当前角度
privatevarangle:
Number=0;
//构造函数
publicfunctionFlatShadingExample()
{
//舞台左上角对齐
stage.align=StageAlign.TOP_LEFT;
//舞台无缩放
stage.scaleMode=StageScaleMode.NO_SCALE;
//帧速为40
stage.frameRate=40;
//初始化
init();
//开始渲染
startRendering();
}
privatefunctioninit():
void
{//创建一个点光源,并设置点光源的初始位置
light=newPointLight3D(true);
light.z=0;
light.y=300;
//加入到场景中
scene.addChild(light);
//创建一个平面着色渲染材质
varshadeMaterial:
FlatShadeMaterial=newFlatShadeMaterial(light,0xFFFFFF,0xFF0000,100);
//创建一个球
varsphere:
Sphere=newSphere(shadeMaterial,250,10,10);
sphere.x=-300;
//将球加入到场景中
scene.addChild(sphere);
//加载一副位图
varimgLoader:
Loader=newLoader();
//加载好了后调用loadComplete事件
imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadComplete);
imgLoader.load(newURLRequest("assets/mill.jpg"));
}
privatefunctionloadComplete(e:
Event):
void
{//创建一个位图对象
varbitmap:
Bitmap=e.target.contentasBitmap;
//创建一个位图材质
varbitmapMaterial:
BitmapMaterial=newBitmapMaterial(bitmap.bitmapData);
//创建一个平面着色渲染器
varshader:
FlatShader=newFlatShader(light,0xFFFFFF,0x000000,100);
//创建一个着色渲染材质
varshadedMaterial:
ShadedMaterial=newShadedMaterial(bitmapMaterial,shader);
varsphere:
Sphere=newSphere(shadedMaterial,250,10,10);
sphere.x=300;
scene.addChild(sphere);
}
overrideprotectedfunctiononRenderTick(e:
Event=null):
void
{
light.z=Math.sin(angle)*400;
light.x=Math.cos(angle)*600;
angle+=0.01;
super.onRenderTick();
}
}
}
GouraudShading高洛德着色渲染法
(译者注:
高洛德着色渲染法:
用多边形顶点的颜色来进行插值得到多边形内部每个点颜色,得到平滑的颜色渐变)
高洛德着色渲染法相比平面着色渲染发是一项更为高级的渲染着色技巧。
相比平面着色渲染在每一个三角形面上使用同一种颜色,高洛德着色渲染法在一个三角形面上使用渐变色。
渐变色是通过环境色和由每个顶点法线计算的颜色来确定的。
确定每个顶点法线的颜色的方法与在用平面着色渲染时计算每个三角形面的颜色的方法是类似的,高洛德着色渲染计算顶点法线和光源之间的角度。
相对于在三角形上面计算法线和做有规则的填充,计算更多的顶点法线和做渐变色填充就会消耗更多的CPU资源。
所以高洛德着色渲染相比平面着色渲染对CPU更为苛刻。
看一下下面三个球,左边那个使用了平面着色渲染。
中间的球展示了用8个顶点形成的六个三角形面,示例中通过顶点计算出来的颜色值和环境色来确定对六个三角形填充颜色。
这种平面着色渲染的球体让我们一眼就能看出是由多个三角形组成的。
第三个图向我们展示了高洛德着色渲染的效果。
上例可看出高洛德着色的效果是很逼真的。
不像平面着色渲染那样看上去是一块块的而是过渡非常平滑。
尽管如此,高洛德着色渲染也有一些缺点。
再看一下ShadingTypeDemo.swf文件。
选择“gourandMaterial”选项,将反光度调高,比如调到200.得到一个类似下面图例所示的茶壶。
总体来讲,还是像预期的那样正常渲染。
光照时从顶点开始计算。
高光就围绕在了顶点周围部分,这样平滑度就降低了。
现在,我们了解下如何使用高洛德着色器。
由于使用方法跟平面着色很相似我们可以拷贝先前的代码,我们只需稍微改动下。
首先我们将FlasShadeMaterial实例替换成GourandMaterial实例。
如下面的代码:
varshadeMaterial:
FlatShadeMaterial=newFlatShadeMaterial(light,0xFFFFFF,0xFF0000,100);
将代码改成基于位图材质的高洛德着色也是很简单的,下面是原来创建材质的过程
varbitmapMaterial:
BitmapMaterial=newBitmapMaterial(bitmap.bitmapData);
varshader:
FlatShader=newFlatShader(light,0xFFFFFF,0x000000,100);
varshadedMaterial:
ShadedMaterial=newShadedMaterial(bitmapMaterial,shader);
将上面的代码替换成下面的代码。
中间的一行创建了高洛德着色对象:
varbitmapMaterial:
BitmapMaterial=newBitmapMaterial(bitmap.bitmapData);
varshader:
GouraudShader=newGouraudShader(light,0xFFFFFF,0x000000,100);
varshadedMaterial:
ShadedMaterial=newShadedMaterial(bitmapMaterial,shader);
两个实例中唯一不同的地方就是类名。
连每个参数都是一样的。
最后一步将用到的类导入,放在