TransparentBox [Alternativa3D 7.6 TIPS]
透明なBOXを表現したいとき、
ただ、Boxに使うFillMaterialのalphaを設定しても、意図した半透明な箱を作る事はできません。
以下のサンプルの様な、半透明な箱を作るには、
1.BoxのFaceの両面が必要
(現VerのBoxでは、reverse(反転)は出来るがTwoSide(両面)は無いので、normalBoxと、reverseしたinnerBoxの2つを重ねて使用)
2.各面の陰影が必要なので、OriginalのFlatShadingを使用しています。
なお、http://wonderfl.net/c/485bで作成したFlatShadingBoxはTextureMaterialを使用していたので、今回FillMaterialはFillMaterialとして、alphaが利く様に改造しています。
2011/01/12 7.5から7.6仕様に変更
/**
* Copyright narutohyper ( http://wonderfl.net/user/narutohyper )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/6qQ3
*/
// forked from narutohyper's Alternativa3D 7.5 Template
package
{
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.loaders.MaterialLoader;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.materials.TextureMaterial;
import alternativ7.engine3d.primitives.Box;
import alternativ7.engine3d.primitives.GeoSphere;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
/**
*
* Alternativa3D 7.5
*
* テンプレート
*
* ...
* @author narutohyper
*/
[SWF(backgroundColor="#000000", frameRate="60", width="800", height="600")]
public class Main extends Sprite
{
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
//テスト表示
var bm:Bitmap=new Bitmap();
//Materialの作成
addChild(bm);
//AlternativaTemplate作成
var scene:AlternativaTemplate = new AlternativaTemplate(this);
addChild(scene.camera.diagram);
//回転させる為のContainer
var objectContainer:Object3DContainer = new Object3DContainer();
scene.container.addChild(objectContainer);
//色つき球
//6面ぬり分けた箱
var material:FillMaterial = new FillMaterial(0x6666FF,0.8);
var box:FlatShadingBox = new FlatShadingBox(new Box(500,500,500,1,1,1,false,false));
box.setMaterialToAllFaces(material);
objectContainer.addChild(box);
box.x = 0;
box.y = 0;
//var material:FillMaterial = new FillMaterial(0x0000FF,0.5);
var innerBox:FlatShadingBox = new FlatShadingBox(new Box(500,500,500,1,1,1,true,false));
innerBox.setMaterialToAllFaces(material);
objectContainer.addChild(innerBox);
innerBox.x = 0;
innerBox.y = 0;
var RADIAN:Number = Math.PI / 180;
var lightContainer:Object3DContainer = new Object3DContainer();
scene.container.addChild(lightContainer);
var light:Light = new Light(0xFFFFFF,0.8);
lightContainer.addChild(light);
lightContainer.rotationY = 30 * RADIAN;
light.x = 400;
//カメラの調整
//カメラはControllerに関連付けている為、x,y,zで直接位置を指定できないので
//SimpleController.setObjectPosXYZを使用
scene.cameraController.setObjectPosXYZ(0,-1000,0);
scene.cameraController.lookAtXYZ(0, 0, 0);
//ObjectControllerの作成
//MouseDragで、Objectを回転させる為のController
var objectController:SimpleObjectController = new SimpleObjectController(stage,objectContainer,100);
objectController.unbindAll();
//描画開始
var angle:Number=0;
scene.onPreRender = function():void {
objectController.update();
angle+=1;
light.x = Math.cos(angle * RADIAN) * 700;
light.y = Math.sin(angle * RADIAN) * 700;
//引数の2番目には、回転するObject3D
box.calculateLight(light,[objectContainer]);
innerBox.calculateLight(light,[objectContainer]);
//bm.bitmapData = sphere2.bmd;
}
scene.startRendering();
}
}
}
import alternativ7.engine3d.core.Face;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.materials.Material;
import alternativ7.engine3d.materials.TextureMaterial;
import alternativ7.engine3d.objects.Mesh;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.Shape;
import flash.geom.Matrix3D;
import flash.geom.Point;
import flash.geom.Vector3D;
/**
* BoxオブジェクトをFlatShadingする、Meshに変更するクラス
*
* サーフェースの概念がなくなったので、ちょっと面倒・・・
*
* @author narutohyper
*/
class FlatShadingBox extends Mesh
{
private var _materialTypes:Vector.<String> = new Vector.<String>(6, true);;
private var _materials:Vector.<Material> = new Vector.<Material>(6, true);
private var _tempMaterials:Vector.<Material> = new Vector.<Material>(6, true);
private var _textures:Vector.<BitmapData> = new Vector.<BitmapData>(6, true);
private var _bmds:Vector.<BitmapData> = new Vector.<BitmapData>(6, true);
private var _normals:Vector.<Number> = new Vector.<Number>();
private var _bmd:BitmapData;
private var _loadeds:Vector.<Boolean> = new Vector.<Boolean>(6, true);
private var _fills:Shape = new Shape();
private var _sp:Point;
public function FlatShadingBox(mesh:Mesh)
{
var face:Face;
var item:*;
//引数のMeshのgeometryをコピー
//takeGeometryFrom(mesh.geometry);
clonePropertiesFrom(mesh);
//left左
_normals.push(1, 0, 0);
//right右
_normals.push( -1, 0, 0);
//back奥
_normals.push(0, 1, 0);
//front前
_normals.push(0, -1, 0);
//top上
_normals.push(0, 0, 1);
//bottom下
_normals.push(0, 0, -1);
//textureの取り込み
var i:uint;
var normal:Vector3D;
for (item in faces) {
face = faces[item];
for (i = 0; i < 6; i++)
{
normal = new Vector3D(_normals[i * 3], _normals[i * 3 + 1], _normals[i * 3 + 2]);
if (face.normal.x == normal.x && face.normal.y == normal.y && face.normal.z == normal.z) {
//この時点でTextureが設定されていたら、差し替え
if (!_textures[i] && face.material) {
setTexture(i, face.material);
}
}
}
}
var RADIAN:Number = Math.PI / 180;
_sp = new Point(0, 0);
}
override public function setMaterialToAllFaces(material:Material):void {
var i:int;
for (i = 0; i < 6; i++)
{
setTexture(i,material);
}
}
private function setTexture(id:uint,material:Material):void {
var tempMaterial:TextureMaterial = material as TextureMaterial;
if (tempMaterial) {
_materialTypes[id] = 'Texture';
if (tempMaterial.texture) {
_textures[id] = tempMaterial.texture;
_bmds[id] = new BitmapData(_textures[id].width, _textures[id].height, true, 0xFF666666);
_loadeds[id] = true;
_materials[id] = new TextureMaterial(_bmds[id]);
setFaceTexture(id);
} else {
//Textureが読み込まれていなかったら、差し替えしない
_materials[id] = tempMaterial;
}
} else {
var tempFillMaterial:FillMaterial = material as FillMaterial
_materialTypes[id]='Fill';
_textures[id] = new BitmapData(400, 400, false, FillMaterial(material).color);
_bmds[id] = new BitmapData(400, 400, false, FillMaterial(material).color);
_materials[id] = new FillMaterial(tempFillMaterial.color, tempFillMaterial.alpha, tempFillMaterial.lineThickness, tempFillMaterial.lineColor);
setFaceTexture(id);
}
}
private function setFaceTexture(id:uint):void {
//該当IDのフェースを差し替える
var face:Face;
var normal:Vector3D;
for (var item:* in faces) {
face = faces[item];
normal = new Vector3D(_normals[id * 3], _normals[id * 3 + 1], _normals[id * 3 + 2]);
if (face.normal.x == normal.x && face.normal.y == normal.y && face.normal.z == normal.z) {
face.material=_materials[id];
}
}
}
public function calculateLight(light:Light, rotaObject:Array = null):void {
var i:int;
var j:int;
//Textureをloadしている場合、load完了までは、Textureなし
//読み込まれて、適用された段階で反映する
var normal:Vector3D;
//光源の位置ベクトル
var lv:Vector3D = new Vector3D(light.x, light.y, light.z);
lv = light.localToGlobal(lv);
//自身の位置ベクトル
var target:Vector3D = new Vector3D(x, y, z);
target = localToGlobal(target);
//光源に対する方向(単位ベクトル)
var axis:Vector3D = lv.subtract(target);
var m:Number = axis.normalize();
//1フェースごとにMatrix変換は、負荷大なので、まとめて変換
var v3:Vector.<Vector3D>;
var mtr3D:Matrix3D = new Matrix3D();
var tempNormals:Vector.<Number> = new Vector.<Number>();
var count2:int;
tempNormals = _normals.concat() as Vector.<Number>;
if (rotaObject.length)
{
count2 = rotaObject.length;
for (i = 0; i < count2; i++)
{
//回転だけ取り出す
v3 = rotaObject[i].matrix.decompose();
v3[0] = new Vector3D(0, 0, 0);
v3[2] = new Vector3D(1, 1, 1);
trace(v3[1])
mtr3D.recompose(v3);
mtr3D.transformVectors(tempNormals, tempNormals);
}
} else {
v3 = matrix.decompose();
v3[0] = new Vector3D(0, 0, 0);
v3[2] = new Vector3D(1, 1, 1);
mtr3D.recompose(v3);
mtr3D.transformVectors(tempNormals, tempNormals);
}
for (i = 0; i < 6; i++)
{
if (_materialTypes[i] == 'Texture') {
var tempTextureMaterial:TextureMaterial= _materials[i] as TextureMaterial
if (!_loadeds[i] && tempTextureMaterial.texture) {
_textures[i] = tempTextureMaterial.texture;
_bmds[i] = new BitmapData(_textures[i].width, _textures[i].height, true, 0xFF666666);
_loadeds[i] = true;
_materials[i] = new TextureMaterial(_bmds[i]);
setFaceTexture(i);
}
}
//面の法線を得る
normal = new Vector3D(tempNormals[i*3],tempNormals[i*3+1],tempNormals[i*3+2]);
//光源との内積で強さを決定
var strength:Number = normal.dotProduct(axis);
//lightの色成分を分解
var r:int = light.colorR / 2 * strength * light.strength + light.colorR / 2;
var g:int = light.colorG / 2 * strength * light.strength + light.colorG / 2;
var b:int = light.colorB / 2 * strength * light.strength + light.colorB / 2;
var color:int = r << 16 | g << 8 | b;
_fills.graphics.clear();
if (_bmds[i]) {
_fills.graphics.beginFill(color);
_fills.graphics.drawRect(0, 0, _bmds[i].width, _bmds[i].height);
_bmds[i].copyPixels(_textures[i], _textures[i].rect, _sp);
_bmds[i].draw(_fills, null, null, BlendMode.HARDLIGHT);
if (_materialTypes[i] != 'Texture') {
var tempFillMaterial:FillMaterial
tempFillMaterial = _materials[i] as FillMaterial;
tempFillMaterial.color = BitmapData(_bmds[i]).getPixel(1,1)
}
}
}
}
public function get bmd():BitmapData { return _bmd; }
}
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.primitives.GeoSphere;
/**
*
* Lightを表現するクラス
*
* @author narutohyper
*/
class Light extends GeoSphere
{
private var _color:int;
private var _colorR:int;
private var _colorG:int;
private var _colorB:int;
private var _strength:Number;
private var _material:FillMaterial;
public function Light(color:Number,strength:Number=1)
{
_color = color;
_strength = strength;
_colorR = ( _color & 0xff0000 ) >> 16;
_colorG = ( _color & 0xff00 ) >> 8;
_colorB = ( _color & 0xff );
_material = new FillMaterial(color);
super(20, 2, false, _material);
}
public function get colorR():int { return _colorR; }
public function get colorG():int { return _colorG; }
public function get colorB():int { return _colorB; }
public function get strength():Number { return _strength; }
public function set strength(value:Number):void
{
_strength = value;
}
public function get color():int { return _color; }
public function set color(value:int):void
{
_color = value;
}
}
/**
* BasicTemplate for Alternativa3D 7.5
* Alternativa3D 7.5を扱いやすくするためのテンプレートです
* @author narutohyper & clockmaker
*
*/
import alternativ7.engine3d.containers.BSPContainer;
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.containers.DistanceSortContainer;
import alternativ7.engine3d.containers.KDContainer;
import alternativ7.engine3d.containers.LODContainer;
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.View;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
class AlternativaTemplate extends Sprite
{
/**
* 子オブジェクトを最適な方法でソートするコンテナ
* (ConflictContainer)
*/
public static const CONFLICT:String = 'conflict';
/**
* 子オブジェクトをBSP(バイナリ空間分割法)によってソートするコンテナ
* (BSPContainer)
*/
public static const BSP:String = 'bsp';
/**
* 子オブジェクトをカメラからのZ値でソートするコンテナ
* (DistanceSortContainer)
*/
public static const ZSORT:String = 'zsort';
/**
* KDツリー(http://ja.wikipedia.org/wiki/Kd%E6%9C%A8)によってソートするコンテナ
* (KDContainer)
*/
public static const KD:String = 'kd';
/**
* detalizationと子オブジェクトの距離でソートするコンテナ(詳細は調査中)
* (LODContainer)
*/
public static const LOD:String = 'lod';
/**
* 3dオブジェクト格納するコンテナインスタンス。
*/
public var container:Object3DContainer;
/**
* ビューインスタンスです。
*/
public var view:View;
/**
* カメラインスタンスです。
*/
public var camera:Camera3D;
/**
* カメラコントローラーです。
*/
public var cameraController:SimpleObjectController;
private var _mc:DisplayObjectContainer;
private var _viewWidth:int;
private var _viewHeight:int;
private var _scaleToStage:Boolean;
private var _containerType:String;
/**
* 新しい Alternativa3DTemplate インスタンスを作成します。
* @param mc
* @param containerType
* @param viewWidth
* @param viewHeight
* @param scaleToStage
*/
public function AlternativaTemplate(mc:DisplayObjectContainer,containerType:String=CONFLICT,viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true)
{
_mc = mc;
_mc.addChild(this);
_containerType = containerType;
_viewWidth = viewWidth;
_viewHeight = viewHeight;
_scaleToStage = scaleToStage;
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理をオーバーライドして記述します。
*/
protected function atInit():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
protected function atPreRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
private var _onPreRender:Function = function():void{};
public function get onPreRender():Function { return _onPreRender; }
public function set onPreRender(value:Function):void
{
_onPreRender = value;
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理をオーバーライドして記述します。
*/
protected function atPostRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理を記述します。
*/
private var _onPostRender:Function = function():void{};
public function get onPostRender():Function { return _onPostRender; }
public function set onPostRender(value:Function):void
{
_onPostRender = value;
}
/**
* レンダリングを開始します。
*/
public function startRendering():void
{
addEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* レンダリングを停止します。
*/
public function stopRendering():void
{
removeEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* シングルレンダリング(レンダリングを一回だけ)を実行します。
*/
public function singleRender():void
{
onRenderTick();
}
/**
* @private
*/
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
//Root objectの作成
if (_containerType == CONFLICT) {
container = new ConflictContainer();
} else if (_containerType == BSP) {
container = new BSPContainer();
} else if (_containerType == ZSORT) {
container = new DistanceSortContainer();
} else if (_containerType == KD) {
container = new KDContainer();
} else if (_containerType == LOD) {
container = new LODContainer();
}
//Viewの作成
view = new View(stage.stageWidth, stage.stageHeight);
_mc.addChild(view);
//cameraの作成
camera = new Camera3D();
camera.view = view;
camera.x = 0;
camera.y = -500;
camera.z = 0;
container.addChild(camera);
// Camera controller
cameraController = new SimpleObjectController(stage, camera, 10);
cameraController.mouseSensitivity = 0;
cameraController.unbindAll();
cameraController.lookAtXYZ(0, 0, 0);
onResize();
stage.addEventListener(Event.RESIZE, onResize);
atInit();
}
/**
* @private
*/
private function onResize(e:Event = null):void
{
if (_scaleToStage)
{
view.width = stage.stageWidth;
view.height = stage.stageHeight;
}
else
{
view.width = _viewWidth;
view.height = _viewHeight;
}
}
/**
* @private
*/
private function onRenderTick(e:Event = null):void
{
atPreRender();
_onPreRender();
cameraController.update();
camera.render();
atPostRender();
_onPostRender();
}
}