スポンサーサイト

-------- | --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

鏡面反射光+拡散反射光+影

2007-11-28 | 20:51

前回のものに球の影がつくようにしてみました。
クリックすると光源が移動します。
影の明るさ(暗さ)が一様なのでリアルさには欠けます。

package {
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;

    import org.papervision3d.core.*;    
    [SWF(width="400", height="400", backgroundColor="#ffffff")]
        public class Light3 extends Sprite
        {
            private var bmd:BitmapData;
            private var center:Number3D;
            private var radius:int;
            private var lightPos:Number3D;
            public function Light3()
            {
                stage.frameRate = 5;
                radius = stage.stageWidth/2*0.6;
                center = new Number3D(stage.stageWidth/2,stage.stageHeight /2,-radius);

                bmd = new BitmapData(stage.stageWidth,stage.stageHeight,false,0x010101);
                addChild(new Bitmap(bmd));

                render(new Point(stage.stageWidth/2*1.5, stage.stageWidth /2*0.75));
                stage.addEventListener(MouseEvent.CLICK, function(e:*):void{
                        render(new Point(stage.mouseX, stage.mouseY)); });
            }

            private function render(p:Point):void{
                lightPos = new Number3D(p.x, stage.stageHeight-p.y, -1000);
                // ハイライト係数
                var h:Number = 2;
                // Y座標を左下が原点となる座標に変換
                for(var x:int = 0 ; x < stage.stageWidth ; x++){
                    for(var y:int = 0 ; y < stage.stageHeight ; y++){
                        var xx:int = x-center.x;
                        var yy:int = y-center.y;
                        // x,y,zの法線ベクトル
                        var n:Number3D;
                        // x,yに対応するz
                        var z:Number;
                        // 光線ベクトル
                        var light:Number3D;

                        if( Math.sqrt(xx*xx+yy*yy) > radius){
                            n = new Number3D(0, 0, -1);
                            z = 0;
                            light= new Number3D(x - lightPos.x, y - lightPos.y , z - lightPos.z);
                            light.normalize();

                            // 光源とこの位置を球が遮るか調べる
                            // 球の中心を原点に置いた時の光源の位置ベクトル
                            var p0:Number3D =
                                new Number3D(lightPos.x - center.x,
                                        lightPos.y - center.y,
                                        lightPos.z - center.z);
                            if( Math.pow(Number3D.dot(p0, light),2) - Number3D.dot(light,light)*
                                    (Number3D.dot(p0,p0) - radius*radius) >= 0){
                                bmd.setPixel(x, stage.stageHeight-y , 0x080808);
                                continue;
                            }
                        }else{
                            // x,yに対応するz
                            z = -Math.sqrt(radius*radius - xx*xx + yy*yy) + center.z;
                            // x,y,zの法線ベクトル
                            n = new Number3D(xx, yy, z);
                            n.normalize();

                            // 光線ベクトル
                            light = new Number3D(x - lightPos.x, y - lightPos.y , z - lightPos.z);
                            light.normalize();
                        }

                        // 逆光線ベクトル
                        var lightDash:Number3D =
                            new Number3D(lightPos.x - x, lightPos.y - y ,lightPos.z - z);
                        lightDash.normalize();
                        var temp:Number = 2*(Number3D.dot(lightDash, n));
                        // 光線の正反射ベクトル
                        var reflection:Number3D =
                            Number3D.sub(new Number3D(temp*n.x, temp*n.y, temp*n.z), lightDash);
                        reflection.normalize();
                        // 視線ベクトル(逆向き)
                        var eye:Number3D = new Number3D(center.x-x,center.y-y,-1000-z);
                        eye.normalize();

                        var dot:Number = Number3D.dot(reflection,eye);
                        dot = Math.max(dot,0);
                        var strength:Number = Math.pow(dot, h);

                        // 拡散反射光
                        var diff:Number = -Number3D.dot(n,light);
                        diff = Math.max(diff,0);

                        // 鏡面反射と拡散反射
                        strength = (strength + diff) / 2;

                        bmd.setPixel(x, stage.stageHeight-y, 0xff*strength);
                    }
                }
            }
        }
}



メモ
どの位置に影がくるかは、光源と床の点を結ぶ直線を球が遮るかどうかを考えればいい。

直線pの方程式を
p = P0+tv
p0: 直線の開始位置
v: 直線の方向ベクトル

半径rの球を原点に置いた時の球Pの方程式を
P^2=r^2
とすると

(p0・v)^2 - v^2(p0^2 - r^2)
の値が負のときは交点を持たない。(つまり光源と床を結ぶ直線を球が遮らない)
スポンサーサイト

Comment

Post a comment

Secret

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。