package {
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import org.papervision3d.core.*;
import org.papervision3d.core.math.*;
import org.papervision3d.core.geom.* ;
import org.papervision3d.scenes.*;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.cameras.*;
import org.papervision3d.materials.*;
import org.papervision3d.materials.shadematerials.* ;
import org.papervision3d.materials.utils.*;
import org.papervision3d.view.*;
import org.papervision3d.render.*;
import org.papervision3d.lights.*;
import org.papervision3d.materials.special.LineMaterial ;
[SWF(width="600", height="400", backgroundColor="#ffffff", frameRate="15")]
public class Shadow4 extends Sprite{
private var renderer:BasicRenderEngine = new BasicRenderEngine();
private var viewport:Viewport3D = new Viewport3D(600, 600, false, true);
private var scene:Scene3D = new Scene3D();
private var camera:Camera3D = new Camera3D();
private var pointLight:PointLight3D;
private var cube1:Cube;
private var cube2:Cube;
private var childCube:Cube;
private var light:Sphere;
private var bd:BitmapData;
private var bd2:BitmapData;
private var LEN:Number = 80;
private var lastPoint:Point;
private var mouseDown:Boolean = false;
private var f:Number=0;
private var initialPoints:Array =
[new Number3D(LEN, +LEN, LEN),
new Number3D(LEN, +LEN, -LEN),
new Number3D(-LEN, +LEN, -LEN),
new Number3D(-LEN, +LEN, LEN),
new Number3D(LEN, -LEN, LEN),
new Number3D(LEN, -LEN, -LEN),
new Number3D(-LEN, -LEN, -LEN),
new Number3D(-LEN, -LEN, LEN)
];
public function Shadow4():void
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE ;
addChild(viewport);
camera.y = 1200;
camera.z = -4400;
camera.x = 0;
camera.focus = 4400;
camera.zoom = 1.5;
pointLight = new PointLight3D(true);
bd = new BitmapData(800, 800, false, 0xff);
cube1 = new Cube(new MaterialsList({top: new BitmapMaterial(bd)}),800,800,10);
cube1.y = 0;
scene.addChild(cube1);
bd2 = new BitmapData(800, 800, false, 0xff);
cube2 = new Cube(new MaterialsList({back: new BitmapMaterial(bd2)}),800,10,800);
cube2.y = 400;
cube2.z = 400;
scene.addChild(cube2);
childCube = new Cube(new MaterialsList({
all:new PhongMaterial(pointLight, 0xFF88FF, 0x111111, 1)}), LEN*2, LEN*2, LEN*2);
scene.addChild(childCube);
childCube.y = 200;
light = new Sphere(new ColorMaterial(0xff), 10);
scene.addChild(light);
pointLight.y = light.y = 350;
stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:*):void{
mouseDown = true;
lastPoint = new Point(stage.mouseX, stage.mouseY);
});
stage.addEventListener(MouseEvent.MOUSE_UP, function(e:*):void{
mouseDown = false;
lastPoint = new Point(stage.mouseX, stage.mouseY);
});
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.addEventListener(Event.ENTER_FRAME, function(e:*):void{
f++;
light.x = pointLight.x = Math.cos(-f/180*Math.PI)*300;
light.z = pointLight.z = Math.sin(-f/180*Math.PI)*300;
drawShadow(bd, new Number3D(0,1,0), new Number3D(0,0,0), 0xeeeeee);
drawShadow(bd2, new Number3D(0,0,-1), new Number3D(0,0,400), 0xdddddd, false);
renderer.renderScene(scene, camera, viewport);
});
}
private function onMouseMove(e:*):void{
if(!mouseDown)
return;
var xx:Number = stage.mouseX - lastPoint.x;
var yy:Number = -stage.mouseY + lastPoint.y;
if(yy == 00) return;
var rotAxis:Number3D = new Number3D();
rotAxis.z = 0;
rotAxis.x = yy;
rotAxis.y = -xx;
// calculate the amount of rotation
var rotAngle:Number = Math.sqrt(xx*xx + yy*yy)/200*Math.PI;
if(rotAngle == 0) return;
rotAxis.normalize();
var pos:Number3D = new Number3D(childCube.x, childCube.y, childCube.z);
var m:Matrix3D = Matrix3D.translationMatrix(-childCube.x, -childCube.y, -childCube.z);
m = Matrix3D.multiply(m, childCube.transform);
m = Matrix3D.multiply(Matrix3D.rotationMatrix(rotAxis.x, rotAxis.y, 0, rotAngle), m);
childCube.transform =
Matrix3D.multiply(Matrix3D.translationMatrix(pos.x, pos.y, pos.z), m);
lastPoint = new Point(stage.mouseX, stage.mouseY);
}
private function drawShadow(bd:BitmapData, n:Number3D, p0:Number3D, c:int, zy:Boolean=true):void{
var pointsShadow:Array = [];
for each (var pp:Number3D in initialPoints){
// 頂点の座標に変換
var p:Number3D = pp.clone();
Matrix3D.multiplyVector(childCube.transform, p);
// 光源と頂点を結ぶベクトル
var v:Number3D = new Number3D(p.x - pointLight.x, p.y - pointLight.y, p.z - pointLight.z);
// 直線の方程式 P = A + tv における媒介変数t
var t:Number = (n.x*p0.x + n.y*p0.y + n.z*p0.z -
(n.x*pointLight.x + n.y*pointLight.y + n.z*pointLight.z)) /
(n.x*v.x + n.y*v.y + n.z*v.z);
if(t > 0){
// ちょっと美しくない
if(zy)
pointsShadow.push(new Point((pointLight.x + t * v.x) + 400, 400 - (pointLight.z + t * v.z)));
else
pointsShadow.push(new Point((pointLight.x + t * v.x) + 400, 800 - (pointLight.y + t * v.y)));
}
}
var hulls:Array = ConvexHull.getConvexHull(pointsShadow);
if(hulls.length < 3)
return;
var sp:Sprite = new Sprite();
sp.graphics.lineStyle(5,0x0);
sp.graphics.beginFill(0x0);
sp.graphics.moveTo(hulls[i].x, hulls[i].y);
for (var i:int = 1 ; i < hulls.length; i++){
sp.graphics.lineTo(hulls[i].x, hulls[i].y);
}
sp.graphics.lineTo(hulls[0].x, hulls[0].y);
sp.graphics.endFill();
bd.fillRect(new Rectangle(0,0,800,800), c);
bd.draw(sp);
bd.applyFilter(bd, new Rectangle(0,0,800,800), new Point(0,0), new BlurFilter(40,40,BitmapFilterQuality.LOW));
}
}
}
import flash.geom.*;
internal class ConvexHull{
public static function getConvexHull(points:Array):Array {
var result:Array = [];
var index:int;
var topIndex:int;
if(points.length < 3)
return result;
// 先頭のインデックスを求める
var p1:Point = new Point(-10000,-10000);
var p2:Point = new Point(0,-10000);
topIndex = index = getNextIndex(points, p2, p1);
var cnt:int = 0;
while(cnt++ <= points.length){
p1 = p2;
p2 = points[index];
result.push(p2);
index = getNextIndex(points, p2, p1);
if(index == topIndex)
break;
}
return result;
}
private static function distance( p1:Point, p2:Point ):Number{
var dx:Number = p2.x - p1.x;
var dy:Number = p2.y - p1.y;
return Math.sqrt( dx*dx+ dy*dy );
}
private static function getNextIndex(points:Array, p2:Point, p1:Point):int{
var minIndex:int = 0;
var min:Number = Math.PI*2;
var minLen:Number = -1;
var v1:Point = new Point(p2.x - p1.x, p2.y - p1.y);
for( var j:int =0; j < points.length; j++ ) {
if(!(points[j].x == p2.x && points[j].y == p2.y)){
var v2:Point = new Point(points[j].x - p2.x, points[j].y - p2.y);
var rad:Number = getTheta(v1, v2);
// 角度が同じ場合、近いほうを優先
if(rad == min){
if(distance(points[j], p2) < minLen){
minIndex = j;
min = rad;
minLen = distance(points[j], p2);
}
}else if(rad < min){
minIndex = j;
min = rad;
minLen = distance(points[j], p2);
}
}
}
return minIndex;
}
private static function getTheta(p1:Point, p2:Point):Number{
var len1:Number = Math.sqrt(p1.x*p1.x + p1.y*p1.y);
var len2:Number = Math.sqrt(p2.x*p2.x + p2.y*p2.y);
if(len1 == 0 || len2==0)
return 0;
p1.x = p1.x/len1;
p1.y = p1.y/len1;
p2.x = p2.x/len2;
p2.y = p2.y/len2;
var dot:Number = p1.x*p2.x + p1.y*p2.y;
var theta:Number = Math.acos(dot);
return theta;
}
}
Author:yamasv@gmail.com
コメント、トラックバック、リンクはお気軽に
-->
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
|---|---|---|---|---|---|---|
| - | - | - | - | - | 1 | 2 |
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
| 31 | - | - | - | - | - | - |