要通过计算机创建真实可信的图像,形体,灯光,阴影,这三要素必不可少。这里介绍一下away3d中提供的阴影解决方案,以及每种方案的用法作为备忘录;
要使用阴影,首先需要知道已下几点:
1:away3d阴影是通过Material的shadowMethod属性添加的;
2:要添加阴影必须在场景中提供光源,away3d中提供了两种灯光类型-PointLight和DirectionalLight。只有DirectionalLight能产生阴影;
3:尽管多个光源能在场景中共同作用,但当PointLight和DirectionalLight混合使用时,产生的阴影可能会出现不正常的情况;
4:光源即使不添加到场景也可照亮场景物体,然而要产生正确的阴影效果就必须将光源添加到场景;
5:阴影相关的属性,产生:castsShadows:Boolean决定物体是否产生阴影;接受:shadowMethod:决定物体是否接受阴影(阴影附着在上面)光源的shadowMapper:默认情况下是DirectionalShadowMapper;
6:阴影贴图不受材质是否透明影响;即使完全透明的物体,仍然会产生阴影;
接下来将对各种阴影进行说明:
HardShadowMapMethod:用于创建边界清晰的投射阴影贴图;这种阴影不包含过滤算法,所以性能是最好的;一般制作对性能要求较高的游戏项目时用;
DitheredShadowMapMethod:通过随机采样的方式创建边沿柔和的阴影;这种阴影可通过range参数设置边沿的模糊度;range较大的时候阴影边界会有颗粒化效果;此阴影计算方式的优点在于边沿是可控的。
FilteredShadowMapMethod:通过双线插值算法计算清晰的阴影;这种阴影的边界相对于HardShadowMapMethod更加柔和;通过设置较高的反锯齿值貌似也可提高阴影的柔和度;
NearShadowMapMethod:这个阴影方法通过计算摄影机距离来淡化阴影;这种阴影用于产生一种均匀的阴影渐隐效果;相对来说算是最逼真的阴影模拟方法了;需要注意的是,想要使用这个方法需要传递给构造方法的不是DirectionalLight实例,而是SimpleShadowMapMethodBase的实例;同时需要DirectionalLight的shadowMapper属性是NearDirectionalShadowMapper的实例;
SoftShadowMapMethod:相对于DitheredShadowMapMethod的颗粒感十足的阴影边界,此阴影计算方法将得到更加柔和的阴影边界;这个方法提供了两个参数改变阴影的效果。采样(第二参数):值域1-32数值越大则越精确,越慢;范围(第三参数):值越大阴影的虚化范围越大;搭配NearShadowMapMethod并参数设置得当可以实现真实的阴影效果,当然,代价就是速度最慢;
TripleFilteredShadowMapMethod:此方法采用三重过滤算法计算阴影贴图;效果优于FilteredShadowMapMethod一些;由于SoftShadowMapMethod和FilteredShadowMapMethod的效果完全能替代它所以官方不推荐使用;这个方法的优点就是容易使用,和FilteredShadowMapMethod一样,此方法不需要参数设置直接作用;
以下是各种shadow对于性能的消耗,使用时应该心中有数,选择最合适的:
HardShadowMapMethod<DitheredShadowMapMethod<FilteredShadowMapMethod<TripleFilteredShadowMapMethod<SoftShadowMapMethod(粗略测试结果,如有错误请君指正)
NearShadowMapMethod不在里面是因为NearShadowMapMethod需要和其他Method合作运行;
以下记录阴影测试代码脚本便于测试:
测试环境提供了一个观察用的摄影机控制器,建立了直线灯光,一个地面和三个盒子分别采用colorMaterial和TextureMaterial;
import away3d.cameras.lenses.OrthographicOffCenterLens;
import away3d.cameras.Camera3D;
import away3d.materials.ColorMaterial;
import away3d.primitives.CubeGeometry;
import away3d.primitives.PlaneGeometry;
import away3d.entities.Mesh;
import away3d.containers.View3D;
import away3d.lights.PointLight;
import away3d.materials.lightpickers.StaticLightPicker;
//
import away3d.materials.methods.HardShadowMapMethod;
import away3d.materials.methods.DitheredShadowMapMethod;
import away3d.materials.methods.FilteredShadowMapMethod;
import away3d.materials.methods.NearShadowMapMethod;
import away3d.materials.methods.SoftShadowMapMethod;
import away3d.materials.methods.TripleFilteredShadowMapMethod;
import away3d.materials.TextureMaterial;
import away3d.textures.BitmapTexture;
//
import away3d.controllers.HoverController;
import away3d.lights.DirectionalLight;
import away3d.lights.shadowmaps.NearDirectionalShadowMapper;//处理阴影贴图程序 默认情况下DirectionalLight包含的是DirectionalShadowMapper
var v3d:View3D=new View3D();
addChild(v3d);
var pln:Mesh=new Mesh(new PlaneGeometry(10000,10000),new ColorMaterial(0x333333));
var box:Mesh=new Mesh(new CubeGeometry(200,200,200),new ColorMaterial(0xFFcc00));
var box2:Mesh=new Mesh(new CubeGeometry(200,400,200),new ColorMaterial(0x99cc00));
var box3:Mesh=new Mesh(new CubeGeometry(300,300,300),new TextureMaterial(new BitmapTexture(new BTM())));
TextureMaterial(box3.material).alphaThreshold=0.1;
v3d.scene.addChild(pln);
v3d.scene.addChild(box);
v3d.scene.addChild(box2);
v3d.scene.addChild(box3);
var dlight:DirectionalLight=new DirectionalLight(0.1,-1,0.2);//FilteredShadowMapMethod
dlight.y=1000;
dlight.z=-1000;
dlight.x=300;
v3d.scene.addChild(dlight);//灯光不添加到场景也能照亮物体,然而,不添加就无法使物体产生正确的阴影
trace(v3d.antiAlias);//默认是0
v3d.antiAlias=32;//模型反锯齿调试环境下无效
trace(v3d.antiAlias);
dlight.lookAt(box.position);
//dlight.castsShadows=true;
//dlight.shadowMapper=new NearDirectionalShadowMapper();//参数0-1 默认0.5 (使用NearShadowMapMethod就要使灯光具备配套的NearDirectionalShadowMaper)
var plight:PointLight=new PointLight();
plight.y=1000;
plight.z=-600;
plight.x=-600;
box.y=100;
box2.x=0;
box2.z=300;
box2.y=200;
box2.castsShadows=false;
box3.y=150;
box3.x=-300;
box3.z=-150;
var lp:Array=[dlight];//plight
var spk:StaticLightPicker=new StaticLightPicker(lp);
var HC:HoverController=new HoverController(v3d.camera,box);
trace(ColorMaterial(pln.material).gloss);
ColorMaterial(pln.material).gloss=100;
//ColorMaterial(pln.material).shadowMethod=new FilteredShadowMapMethod(dlight);HardShadowMapMethod
//var shadowMethod:DitheredShadowMapMethod=new DitheredShadowMapMethod(dlight);
//trace(shadowMethod.range);//DitheredShadowMapMethod 以采样方式创建阴影,边界(range)较大的时候阴影边界会有颗粒化效果
//var shadowMethod:HardShadowMapMethod=new HardShadowMapMethod(dlight);// HardMapShadowMethod 用于创建边界清晰的投射阴影(这种阴影的性能最好)
//var shadowMethod:FilteredShadowMapMethod=new FilteredShadowMapMethod(dlight);//FilteredShadowMapMethod 通过双线插值算法计算柔和的阴影(相对于HardMapShadowMethod边界更加柔和一些)通过设置较高的反锯齿值貌似也可提高阴影的柔和度
//var shadowMethod:NearShadowMapMethod=new NearShadowMapMethod(new FilteredShadowMapMethod(dlight));//根据摄影机与投影距离限制阴影的显示,产生柔和的半阴影轮廓,要是用这个类就必须在灯光上添加对应的NearDirectionalShadowMapper(默认的是DirectionalShadowMapper)
//var shadowMethod:SoftShadowMapMethod=new SoftShadowMapMethod(dlight,32,100);//通过随机样本分布获得边缘柔滑的投影效果 第二参数是采样数量 第三参数是采样范围(最小1 最大32) 采样越大越精确,越慢;范围越大阴影就越分散
//var shadowMethod:TripleFilteredShadowMapMethod=new TripleFilteredShadowMapMethod(dlight);//TripleFilteredShadowMapMethod (三重过滤阴影贴图)用于产生边缘柔和的阴影可能是由于效果和FilteredShadowMapMethod差不多所以不推荐使用了不过通过实际效果来看,相对于FilteredMethod边界更加柔和
//shadowMethod.range=8;
shadowMethod.alpha=0.8;
trace(shadowMethod.epsilon);//这个值用于调整阴影显示的,如果阴影出现了重叠斑块则增大此值 如果阴影出现断面 则减小此值,默认为0.02
ColorMaterial(pln.material).shadowMethod=shadowMethod;
ColorMaterial(box2.material).shadowMethod=shadowMethod;
TextureMaterial(box3.material).shadowMethod=shadowMethod;
/*ColorMaterial(box.material).shadowMethod=;FilteredShadowMapMethod//new NearShadowMapMethod(new DitheredShadowMapMethod(dlight)*/
ColorMaterial(pln.material).lightPicker=spk;
ColorMaterial(box.material).lightPicker=spk;
ColorMaterial(box2.material).lightPicker=spk;
TextureMaterial(box3.material).lightPicker=spk;
addEventListener(Event.ENTER_FRAME,run);
v3d.addEventListener(MouseEvent.MOUSE_DOWN,v3d_d);
v3d.addEventListener(MouseEvent.MOUSE_UP,v3d_u);
var nx:Number;
var ny:Number;
function v3d_d(e:MouseEvent){
nx=v3d.mouseX;
ny=v3d.mouseY;
addEventListener(MouseEvent.MOUSE_MOVE,v3d_m);
}
function v3d_m(e:MouseEvent){
var cx:Number=v3d.mouseX;
var cy:Number=v3d.mouseY;
HC.tiltAngle+=(cy-ny);
HC.panAngle+=(cx-nx);
nx=cx;
ny=cy;
}
function v3d_u(e:MouseEvent){
removeEventListener(MouseEvent.MOUSE_MOVE,v3d_m);
}
function run(e:Event){
v3d.render();
HC.update();
}