In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

forked from: 視線とポリゴンメッシュの交差判定

視線とメッシュの交差判定のテスト(処理が重い版)
(追記)176行目のgetWorldTransform()の第二引数書き忘れてました。。
/**
 * Copyright tepe ( http://wonderfl.net/user/tepe )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/ntHC
 */

// forked from tencho's 視線とポリゴンメッシュの交差判定
/**
 * 視線とメッシュの交差判定のテスト(処理が重い版)
 * (追記)176行目のgetWorldTransform()の第二引数書き忘れてました。。
 */
package  {
    import flash.events.*;
    import flash.utils.*;
    import org.papervision3d.core.geom.*;
    import org.papervision3d.core.geom.renderables.*;
    import org.papervision3d.core.math.*;
    import org.papervision3d.materials.*;
    import org.papervision3d.materials.special.*;
    import org.papervision3d.materials.utils.*;
    import org.papervision3d.objects.*;
    import org.papervision3d.objects.primitives.*;
    import org.papervision3d.view.*;
    import org.papervision3d.view.stats.*;
    public class CollideRayToMesh extends BasicView {
        private var cube:Cube;
        private var point:Sphere;
        private var lines:Lines3D;
        private var line:Line3D;
        private var wire:WireframeMaterial;
        private var color:ColorMaterial;
        //コンストラクタ
        public function CollideRayToMesh() {
            stage.frameRate = 60;
            opaqueBackground = 0x000000;
            addChild(new StatsView(renderer));
            wire = new WireframeMaterial(0xFF8800);//キューブの色
            color = new ColorMaterial(0xFF88ff, 0.7);//交差面の色
            lines = new Lines3D(new LineMaterial());
            lines.addNewLine(2, 0, 0, 0, 0, 550, 0);
            line = lines.lines[0] as Line3D;
            cube = new Cube(new MaterialsList( { all:wire } ), 200, 200, 200, 2, 2, 2);
            point = new Sphere(new ColorMaterial(0xFFFF00), 10, 8, 6);//接点
            cube.position = new Number3D(0, 200, 0);
            var plane:Plane = new Plane(new WireframeMaterial(0x007700), 1000, 1000, 5, 5);//グリッド
            plane.rotationX = 90;
            scene.addChild(cube);
            scene.addChild(point);
            scene.addChild(plane);
            scene.addChild(lines);
            camera.position = new Number3D(0, 700, -400);
            addEventListener(Event.ENTER_FRAME, onEnter);
        }
        /**
         * 毎フレーム処理
         */
        private function onEnter(e:Event):void {
            //キューブを回転・変形させる
            var tm:int = getTimer();
            cube.scaleY = (Math.cos(Math.PI/180 * tm / 30) + 1) *0.8;
            cube.rotationZ = tm/25;
            cube.rotationX = tm/25;
            cube.rotationY = tm/25;
            //視線用ライン
            line.v0.x = (mouseX - stage.stageWidth/2)*2; 
            line.v0.z = (-mouseY + stage.stageHeight/2)*2;
            //line.v1.x = (mouseX - stage.stageWidth/2)*2;
            //line.v1.y = (-mouseY + stage.stageHeight/2)*2;
            var ray:Number3D = line.v0.toNumber3D()
            ray.minusEq(line.v1.toNumber3D());
            //交差判定
            var res:Array = collideRayToMeshList(line.v1.toNumber3D(), ray, [cube], false, true);
            for each(var face:Triangle3D in cube.geometry.faces) face.material = wire;
            if (res.length == 0) {
                //交差なし
                point.visible = false;
            } else {
                //交差あり
                res[0].triangle.material = color;
                point.visible = true;
                point.position = new Number3D(res[0].position.x, res[0].position.y, res[0].position.z);
            }
            renderer.renderScene(scene, camera, viewport);
        }
        /**
         * 視線と複数メッシュの交差判定をする
         * @param    pos    レイ放射地点
         * @param    vec    レイの方向
         * @param    meshes    メッシュオブジェクトの配列
         * @param    isDoubleSided    裏向きのポリゴンも交差判定する
         * @param    updateTransform    モデルが回転・変形していたらtrueにする
         * @return
         */
        private function collideRayToMeshList(pos:Number3D, vec:Number3D, meshes:Array, isDoubleSided:Boolean = false, updateTransform:Boolean = false):Array {
            var res:Array = new Array();
            for each(var mesh:TriangleMesh3D in meshes) {
                //モデルのワールド空間における変形情報
                var transform:Matrix3D = getWorldTransform(mesh, updateTransform);
                //メッシュモデル内の全三角ポリゴンをチェック
                for each(var face:Triangle3D in mesh.geometry.faces) {
                    var ps:Array = new Array();
                    for each(var v:Vertex3D in face.vertices) {
                        var n:Number3D = v.toNumber3D();
                        Matrix3D.multiplyVector4x4(transform, n);
                        ps.push(n);
                    }
                    var hit:Object = collideRayToTriangle(pos, vec, ps[0], ps[1], ps[2], isDoubleSided);
                    if (hit != null) {
                        hit.triangle = face;
                        res.push(hit);
                    }
                }
            }
            res.sortOn("distance", Array.NUMERIC);
            return res;
        }
        /**
        * 視線と三角ポリゴンの交差判定をする(ポリゴンは頂点反時計周りで構成)
        * @param    pos    視線の開始地点
        * @param    vec    視線の方向ベクトル
        * @param    p0    三角ポリゴンの頂点1
        * @param    p1    三角ポリゴンの頂点2
        * @param    p2    三角ポリゴンの頂点3
        * @param    isDoubleSided    裏向きのポリゴンも交差判定する
        * @return
        */
        private function collideRayToTriangle(pos:Object, vec:Object, p0:Object, p1:Object, p2:Object, isDoubleSided:Boolean = false):Object {
            //視線ベクトルの正規化
            var v:Object = { x:vec.x, y:vec.y, z:vec.z };
            normalize(v);
            //法線ベクトルを求める
            var n:Object = cross3D( { x:p1.x - p0.x, y:p1.y - p0.y, z:p1.z - p0.z }, { x:p2.x - p0.x, y:p2.y - p0.y, z:p2.z - p0.z } );
            normalize(n);
            var vn:Number = dot3D(v, n);
            //視線に対して面が表向きか
            var isRightSide:Boolean = (vn < 0);
            //1.視線が平面と平行なら交差なし
            //2.片面チェックON時に視線と法線が同じ向き(面が裏向き)なら交差なし
            if ((isRightSide? -vn : vn) < 0.0000001 || (!isRightSide && !isDoubleSided)) return null;
            var xpn:Number = dot3D( { x:pos.x - p0.x, y:pos.y - p0.y, z:pos.z - p0.z }, n);
            var distance:Number = -xpn / vn;
            //3.交点が視線の後ろなら交差なし
            if (distance < 0) return null;
            //平面との交点座標を求める
            var hit:Object = { x:v.x * distance + pos.x, y:v.y * distance + pos.y, z:v.z * distance + pos.z };
            //4.交点が三角形内にあるかチェック
            var cross0:Object = cross3D( { x:hit.x - p0.x, y:hit.y - p0.y, z:hit.z - p0.z }, { x:p1.x - p0.x, y:p1.y - p0.y, z:p1.z - p0.z } );
            if (dot3D(cross0, n) > 0.000000001) return null;
            var cross1:Object = cross3D( { x:hit.x - p1.x, y:hit.y - p1.y, z:hit.z - p1.z }, { x:p2.x - p1.x, y:p2.y - p1.y, z:p2.z - p1.z } );
            if (dot3D(cross1, n) > 0.000000001) return null;
            var cross2:Object = cross3D( { x:hit.x - p2.x, y:hit.y - p2.y, z:hit.z - p2.z }, { x:p0.x - p2.x, y:p0.y - p2.y, z:p0.z - p2.z } );
            if (dot3D(cross2, n) > 0.000000001) return null;
            //交差情報を返す{position:交差点、isRightSide:交差面が視線に対して表向きかどうか、distance:視点から交点までの距離}
            return { position:hit, isRightSide:vn < 0, distance:distance };
        }
        /**ベクトルの正規化*/
        private function normalize(v:Object):void {
            var mod:Number = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
            if (mod != 0 && mod != 1) {
                mod = 1 / mod;
                v.x *= mod;
                v.y *= mod;
                v.z *= mod;
            }
        }
        /**2つの3Dベクトルの外積を返す*/
        private function cross3D(v1:Object, v2:Object):Object {
            return { x:v2.y * v1.z - v2.z * v1.y, y:v2.z * v1.x - v2.x * v1.z, z:v2.x * v1.y - v2.y * v1.x };
        }
        /**2つの3Dベクトルの内積を返す*/
        private function dot3D(vec1:Object, vec2:Object):Number {
            return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
        }
        /**
         * オブジェクトのワールド空間での変形情報を取得
         * @param    obj    変形情報を取得するモデル
         * @param    updateTransform    モデルが回転・変形していたらtrueにする
         * @return
         */
        private function getWorldTransform(obj:DisplayObject3D, updateTransform:Boolean = false):Matrix3D {
            if (updateTransform) obj.updateTransform();
            var res:Matrix3D = new Matrix3D();
            res.copy(obj.transform);
            var parent3D:DisplayObject3D = obj.parent as DisplayObject3D;
            if (parent3D != null) res.calculateMultiply(getWorldTransform(parent3D, updateTransform), res);
            return res;
        }
    }
}