3D衝突判定 3dtext.in API DEMO
参考
* http://kaiho-16.seesaa.net/article/77825349.html
* clockmaker's [PV3D] Vector Font on 3D World
/**
* 参考
* http://kaiho-16.seesaa.net/article/77825349.html
* clockmaker's [PV3D] Vector Font on 3D World
*/
package
{
import flash.net.*;
import flash.utils.*;
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import org.papervision3d.core.geom.renderables.*;
import org.papervision3d.core.math.*;
import org.papervision3d.core.clipping.FrustumClipping;
import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.materials.*;
import org.papervision3d.materials.special.CompositeMaterial;
import org.papervision3d.objects.*;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.view.BasicView;
import org.papervision3d.cameras.*;
import org.papervision3d.core.effects.view.ReflectionView;
import caurina.transitions.properties.CurveModifiers;
import caurina.transitions.Tweener;
import org.papervision3d.core.math.Number3D;
import org.papervision3d.core.geom.TriangleMesh3D;
import org.papervision3d.materials.BitmapFileMaterial;
[SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "0x001122")]
public class Main extends ReflectionView
{
private var REF:Number = 1;
private var GRAV:Number = - 9.8;
private var MASS:int = 10; // ブロックの質量
private var objArray : Array = new Array();
private var COL_X : int = 1400; // x軸方向の壁の位置
private var COL_Z : int = 1400; // y軸方向の壁の位置
private var rootNode:DisplayObject3D;
private var mat:MaterialObject3D;
private var chg:Boolean ;
public function Main():void
{
super(0, 0, true , false, CameraType.TARGET);
camera.zoom = 1.5;
camera.focus = 200;
// refrection
surfaceHeight = 10;
viewportReflection.filters = [new BlurFilter(2, 2, 3)];
viewportReflection.alpha = .8;
// safe polygon
renderer.clipping = new FrustumClipping(FrustumClipping.NEAR)
// add material
var compMat:CompositeMaterial = new CompositeMaterial();
compMat.addMaterial(new WireframeMaterial(0xEEEEEE));
compMat.addMaterial(new ColorMaterial(0xEEEEEE, 0.1));
var planeB:Plane = new Plane(compMat, 3000, 3000, 4, 4);
planeB.pitch(90)
scene.addChild(planeB);
rootNode = scene.addChild(new DisplayObject3D());
var val:URLVariables = new URLVariables();
val.text="ABCDEFGHIJKLMN";//作成する立体文字
val.depth=2; //文字の厚さ
val.bevel=0; //文字べベル
val.font = "ITEM"; //フォント名
var req:URLRequest = new URLRequest("http://www.3dtext.in/api/for_wonderfl_demo_key");
req.method = URLRequestMethod.POST;req.data=val;
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE, completeHandler);
loader.load(req);
}
private function completeHandler(event:Event):void
{
var data:ByteArray = event.target.data;
data.endian = Endian.LITTLE_ENDIAN
var q:int;var sum:int=0
try {
while (q = data.readUnsignedShort()) {
var t:TriangleMesh3D = new TriangleMesh3D(new BitmapFileMaterial("http://www.3dtext.in/image/" + (18 * Math.random() | 0) + ".jpg"), new Array(), new Array());
var arr: Array = new Array();
if(q>1)for (var a:int = 0; a < q; a++) {
var v1:Vertex3D = new Vertex3D(data.readFloat(), data.readFloat(),data.readFloat())
var v2:Vertex3D = new Vertex3D(data.readFloat(), data.readFloat(),data.readFloat())
var v3:Vertex3D = new Vertex3D(data.readFloat(), data.readFloat(),data.readFloat())
t.geometry.vertices.push(v1);t.geometry.vertices.push(v2);t.geometry.vertices.push(v3);
t.geometry.faces.push(new Triangle3D(t, [v1,v2,v3],mat, [new NumberUV(data.readFloat(),data.readFloat()),new NumberUV(data.readFloat(),data.readFloat()),new NumberUV(data.readFloat(),data.readFloat())]));
}
for (var i:int = 0; i < 9; i++) {arr.push(data.readFloat());}
var e1:Number3D = new Number3D(arr[0]/2, 0, 0);
var e2:Number3D = new Number3D(0, arr[1]/2, 0);
var e3:Number3D = new Number3D(0, 0, arr[2]/2);
var e4:Number3D = new Number3D((Math.random() - 0.5) * 60, (Math.random() - 0.5) * 60, (Math.random() - 0.5) * 60);
t.extra = { stat:arr,e1:e1,e2:e2,e3:e3,v:e4};
t.x=(Math.random() - 1) * 1200;
t.y = Math.random() * 1000;
t.z = (Math.random() - 1) * 1200;
objArray.push(t);
rootNode.addChild(t);
}
} catch (err:Error) {
}finally {
stage.addEventListener(Event.ENTER_FRAME, loop)
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
}
}
// ベクトルをスカラー倍にする
private function multiNumber3D(n:Number3D, S:Number):void{
n.x *= S;
n.y *= S;
n.z *= S;
}
// 衝突後の物理演算
private function Col_Vel(obj1:TriangleMesh3D, obj2:TriangleMesh3D):void{
// 2つのobjの中心間のベクトル obj1 → obj2
var c:Number3D = new Number3D(obj1.x-obj2.x, obj1.y-obj2.y, obj1.z-obj2.z);
c.normalize();
var obj1_v_tmp:Number = MASS/(MASS*2)*(1+REF)*Number3D.dot(Number3D.sub(obj2.extra.v, obj1.extra.v), c);
var obj2_v_tmp:Number = MASS/(MASS*2)*(1+REF)*Number3D.dot(Number3D.sub(obj1.extra.v, obj2.extra.v), c);
var obj1_v_af:Number3D = c.clone();
var obj2_v_af:Number3D = c.clone();
multiNumber3D(obj1_v_af, obj1_v_tmp);
multiNumber3D(obj2_v_af, obj2_v_tmp);
obj1.extra.v = Number3D.add(obj1_v_af, obj1.extra.v);
obj2.extra.v = Number3D.add(obj2_v_af, obj2.extra.v);
}
private function mouseDown(e:MouseEvent):void {
for (var i:int = 0; i < objArray.length; i++) {
objArray[i].material = (chg)?
new BitmapFileMaterial("http://www.3dtext.in/image/" + (18 * Math.random() | 0) + ".jpg"):
new WireframeMaterial(0xFFFFFF * Math.random())
}
chg = !chg;
}
private function loop(event:Event = null):void
{
for(var i:int = 0;i < objArray.length;i++){
// オブジェクトの位置の移動
objArray[i].x += objArray[i].extra.v.x;
objArray[i].y += objArray[i].extra.v.y;
objArray[i].z += objArray[i].extra.v.z;
// オブジェクトの回転
objArray[i].rotationZ -= objArray[i].extra.v.x / 3;
objArray[i].rotationX += objArray[i].extra.v.z / 3;
// 重力
objArray[i].extra.v.y += GRAV / 4;
}
// objectと壁、床との当たり判定
for(i = 0;i < objArray.length;i++){
if(objArray[i].x > COL_X){
objArray[i].x = COL_X;
objArray[i].extra.v.x *= -REF;
}else if(objArray[i].x < -COL_X){
objArray[i].x = -COL_X;
objArray[i].extra.v.x *= -REF;
}
if(objArray[i].z > COL_Z){
objArray[i].z = COL_Z;
objArray[i].extra.v.z *= -REF;
}else if(objArray[i].z < -COL_Z){
objArray[i].z = -COL_Z;
objArray[i].extra.v.z *= -REF;
}
if(objArray[i].y < 100){
objArray[i].y = 100;
objArray[i].extra.v.y *= -0.9;
}
}
// ブロック同士の衝突判定
for(i = 0;i < objArray.length - 1;i++){
for(var j:int = i + 1; j < objArray.length;j++){
if( objArray[i].distanceTo(objArray[j]) < 150 ){
if( Col_OBB.OBB_Cube(objArray[i], objArray[j]) ){
Col_Vel(objArray[i], objArray[j]);
}
}
}
}
camera.x += (2000 * Math.sin(mouseX / stage.stageWidth * 360 * Math.PI / 180) - camera.x) * .1;
camera.z += (2000 * Math.cos(mouseX / stage.stageWidth * 360 * Math.PI / 180) - camera.z) * .1;
camera.y += (2000 * mouseY / stage.stageHeight - camera.y) * .1;
singleRender();
}
}
}
import org.papervision3d.core.geom.*;
import org.papervision3d.core.proto.*;
import org.papervision3d.core.math.*;
class Col_OBB{
public static function OBB_Cube(obj1:TriangleMesh3D, obj2:TriangleMesh3D):Boolean{
var obj1_e:Array = new Array(); // obj1の分離軸保存用配列
var obj2_e:Array = new Array(); // obj2の分離軸保存用配列
// 各軸の方向ベクトルを保存
obj1_e[0] = obj1.extra.e1.clone();
obj1_e[1] = obj1.extra.e2.clone();
obj1_e[2] = obj1.extra.e3.clone();
obj2_e[0] = obj2.extra.e1.clone();
obj2_e[1] = obj2.extra.e2.clone();
obj2_e[2] = obj2.extra.e3.clone();
// オブジェクトが回転しているだけ各軸の方向ベクトルも回転させる
for(var i:int = 0;i < obj1_e.length; i++){
Matrix3D.multiplyVector( Matrix3D.rotationX(obj1.rotationX * Math.PI / 180), obj1_e[i]);
Matrix3D.multiplyVector( Matrix3D.rotationX(obj2.rotationX * Math.PI / 180), obj2_e[i]);
}
for(i = 0;i < obj1_e.length; i++){
Matrix3D.multiplyVector( Matrix3D.rotationY(obj1.rotationY * Math.PI / 180), obj1_e[i]);
Matrix3D.multiplyVector( Matrix3D.rotationY(obj2.rotationY * Math.PI / 180), obj2_e[i]);
}
for(i = 0;i < obj1_e.length; i++){
Matrix3D.multiplyVector( Matrix3D.rotationZ(obj1.rotationZ * Math.PI / 180), obj1_e[i]);
Matrix3D.multiplyVector( Matrix3D.rotationZ(obj2.rotationZ * Math.PI / 180), obj2_e[i]);
}
// 分離軸上でのオブジェクトの中心の距離を求める時に使用
var tmp_interval:Number3D = new Number3D(obj1.x-obj2.x, obj1.y-obj2.y, obj1.z-obj2.z);
var col:Boolean;
// obj1の方向ベクトルを分離軸にする場合の処理
for(i = 0; i < obj1_e.length; i++){
col = OBBs(obj1_e[i], obj2_e, tmp_interval);
if(col == false)break;
}
// obj2の方向ベクトルを分離軸にする場合の処理
if(col == true){
for(var j:int = 0; i < obj2_e.length; j++){
col = OBBs(obj2_e[j], obj1_e, tmp_interval);
if(col == false)break;
}
}
if(col == true)col = C_OBBs(obj1_e, obj2_e, tmp_interval);
return col;
}
private static function OBBs(D_origin:Number3D, obj_e:Array, tmp_interval:Number3D):Boolean{
var rA:Number = D_origin.modulo; // 分離軸の元になるベクトルはOBBの投影線分の長さはそのまま
var D:Number3D = D_origin.clone(); // 分離軸としてコピー
D.normalize(); // 正規化
var rB:Number = abs_dot(obj_e[0], D) + abs_dot(obj_e[1], D) + abs_dot(obj_e[2], D);
var interval:Number = abs_dot(tmp_interval, D);
return rA + rB >= interval;
}
private static function C_OBBs(obj1_e:Array, obj2_e:Array, tmp_interval:Number3D):Boolean{
var C:Number3D;
var interval:Number;
var rA:Number = 0;
var rB:Number = 0;
for(var i:int = 0; i < obj1_e.length; i++){
for(var j:int = 0; j < obj2_e.length; j++){
C = Number3D.cross(obj1_e[i],obj2_e[j]); // 外積により分離軸を求める
C.normalize(); // 正規化
interval = abs_dot(tmp_interval, C);
if(i == 0){
rA = abs_dot(obj1_e[1], C) + abs_dot(obj1_e[2], C);
}else if(i == 1){
rA = abs_dot(obj1_e[0], C) + abs_dot(obj1_e[2], C);
}else if(i == 2){
rA = abs_dot(obj1_e[0], C) + abs_dot(obj1_e[1], C);
}
if(j == 0){
rB = abs_dot(obj2_e[1], C) + abs_dot(obj2_e[2], C);
}else if(j == 1){
rB = abs_dot(obj2_e[0], C) + abs_dot(obj2_e[2], C);
}else if(j == 2){
rB = abs_dot(obj2_e[0], C) + abs_dot(obj2_e[1], C);
}
if(rA + rB <= interval)break;
}
if(rA + rB <= interval)break;
}
return rA + rB >= interval;
}
private static function abs_dot(v:Number3D, w:Number3D):Number{
var num:Number = v.x * w.x + v.y * w.y + v.z * w.z;
var abs:Number = num < 0 ? -num : num;
return abs;
}
}