如何通过透视投影获取 DisplayObject 的可见大小

发布于 2024-08-31 17:05:37 字数 828 浏览 4 评论 0原文

下面完全是一道数学题。

众所周知,PerspectiveProjection 根据以下公式提供由 fieldOfViewfocalLength 相互依赖的值表示的 3D 透视变换:

focalLength = stageWidth/2 * (cos(fieldOfView/2) / sin(fieldOfView/2)

Bjørn Gunnar Staal 插图
(来源:bgstaal.net

DisplayObject(上面链接图像上的立方体)的可见屏幕尺寸?

问:如何获取已应用 PerspectiveProjection的 ActionScript 3 中的问题缺乏功能对于 DisplayObject 的可见边界

The following is entirely a math question.

As we know, PerspectiveProjection delivers perspective transformations in 3D represented by the interdependent values of fieldOfView and focalLength according to the following formula:

focalLength = stageWidth/2 * (cos(fieldOfView/2) / sin(fieldOfView/2)

Illustration by Bjørn Gunnar Staal
(source: bgstaal.net)

Q: How to get the visible on-screen size of the DisplayObject (Cube on the above-linked image) to which PerspectiveProjection has been applied?

A more thorough description and illustrative code on the issue in ActionScript 3 lacks functionality for visible bounds of DisplayObject.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

君勿笑 2024-09-07 17:05:37

我想我没有抓住要点。

我在ide中做了一个简单的测试,将3个剪辑放在一起,如下所示:
3d size

宽度和高度报告可见 3d 区域的大小,
正如您在财产检查员中也可以看到的那样。
您可以像在运行时一样简单地访问

trace(cube.width + ' by ' + cube.height);

,或者使用一些 jsfl:

var doc = fl.getDocumentDOM();
fl.outputPanel.clear();
fl.trace(doc.selection[0].width + ' by ' + doc.selection[0].height);

在 IDE 中访问创作时选定的剪辑。

我用一些动作脚本做了类似的测试:

//draw faces
var front:Sprite = drawFace();
var back:Sprite = drawFace();
var left:Sprite = drawFace();
var right:Sprite = drawFace();
var top:Sprite = drawFace();
var bottom:Sprite = drawFace();
//transform faces
front.z  = -50;
back.z   =  50;
left.x   = -50;
right.x  =  50;
top.y    = -50;
bottom.y =  50;
left.rotationY = right.rotationY = 90;
top.rotationX = bottom.rotationX = 90;
//putem them all together
var cube:Sprite = new Sprite();
cube.addChild(front);
cube.addChild(back);
cube.addChild(left);
cube.addChild(right);
cube.addChild(top);
cube.addChild(bottom);
addChild(cube);
cube.x = stage.stageWidth * .5;
cube.y = stage.stageHeight* .5;
cube.z = -100;
cube.rotationX = cube.rotationY = 30;

trace(cube.width + ' by ' + cube.height);
trace(cube.getBounds(this));
trace(cube.transform.pixelBounds);
this.addEventListener(Event.ENTER_FRAME, loop);
function loop(event:Event):void {
    cube.rotationY += 3;
    var b:Rectangle = cube.getBounds(this);
    graphics.clear();
    graphics.lineStyle(1,0x009900);
    graphics.drawRect(b.x,b.y,b.width,b.height);
}

function drawFace():Sprite{
    var s:Sprite = new Sprite();
    s.graphics.beginFill(0x000099,.5);
    s.graphics.drawRect(-50,-50,100,100);
    s.graphics.endFill();
    return s;
}

这是来自编程动作脚本3.0的修改示例,

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

    public class Triangles extends Sprite {  
        var x1:Number = -100,y1:Number = -100,z1:Number = 0,t1:Number = 0;  
        var x2:Number = 100,y2:Number = -100,z2:Number = 0,t2:Number = 0;  
        var x3:Number = 100,y3:Number = 100,z3:Number = 0,t3:Number = 0;  
        var x4:Number = -100,y4:Number = 100,z4:Number = 0,t4:Number = 0;  
        var v1 = new Vector3D(-100,-100,0,0);
        var v2 = new Vector3D(100,-100,0,0);
        var v3 = new Vector3D(100,100,0,0);
        var v4 = new Vector3D(-100,100,0,0);
        var focalLength:Number = 200;   
        var indices:Vector.<int>;  

        var container:Sprite;  

        var bitmapData:BitmapData; // texture  
        var imageLoader:ImageLoader;  

        public function Triangles():void {  
            indices =  new Vector.<int>();  
            indices.push(0,1,3, 1,2,3);  

            container = new Sprite(); // container to draw triangles in  
            container.x = 200;  
            container.y = 200;  
            addChild(container);  

            imageLoader = new ImageLoader("head.jpg");  
            imageLoader.addEventListener(Event.COMPLETE, onImageLoaded);  
        }  

        function onImageLoaded(event:Event):void {  
            bitmapData = imageLoader.bitmap.bitmapData; 
            addEventListener(Event.ENTER_FRAME, rotatePlane);  
        }  
        function rotatePlane(event:Event):void {  
            var ticker = getTimer()/1600;  
            z2 = z3 = -(z1 = z4 = 100*Math.sin(ticker));  
            x2 = x3 = -(x1 = x4 = 100*Math.cos(ticker));  

            v2.z = v3.z = -(v1.z = v4.z = 100*Math.sin(ticker));
            v2.x = v3.x = -(v1.x = v4.x = 100*Math.cos(ticker));


            t1 = focalLength/(focalLength + z1);  
            t2 = focalLength/(focalLength + z2);  
            t3 = focalLength/(focalLength + z3);  
            t4 = focalLength/(focalLength + z4);  

            v1.w = focalLength/(focalLength + v1.z);  
            v2.w = focalLength/(focalLength + v2.z);  
            v3.w = focalLength/(focalLength + v3.z);  
            v4.w = focalLength/(focalLength + v4.z);  

            // determine triangle vertices based on t values  
            var vertices:Vector.<Number> = new Vector.<Number>();  
            //vertices.push(x1*t1,y1*t1, x2*t2,y2*t2, x3*t3,y3*t3, x4*t4,y4*t4);  

            vertices.push(v1.x*v1.w,v1.y*v1.w, v2.x*v2.w,v2.y*v2.w, v3.x*v3.w,v3.y*v3.w, v4.x*v4.w,v4.y*v4.w);  
            var uvtData:Vector.<Number> = new Vector.<Number>();  
            uvtData.push(0,0,v1.w, 1,0,v2.w, 1,1,v3.w, 0,1,v4.w);  

            // draw  
            container.graphics.clear();  
            container.graphics.beginBitmapFill(bitmapData);  
            container.graphics.drawTriangles(vertices, indices, uvtData);  
            var b:Rectangle = container.transform.pixelBounds;
            graphics.clear();
            graphics.lineStyle(1,0x009900);
            graphics.drawRect(b.x,b.y,b.width,b.height);
        }  
    }  
} 

像素边界在这里工作得很好,但它是一个简单的平面。 PixelBounds 在前面的示例中不起作用,但 getBounds() 似乎工作正常。

I think I'm missing the point.

I did a simple test in the ide, put 3 clips together like so:
3d size

The width and height report the size of the visible 3d area,
as you can see in the property inspector as well.
You can access just as simple as

trace(cube.width + ' by ' + cube.height);

at runtime or with a bit of jsfl:

var doc = fl.getDocumentDOM();
fl.outputPanel.clear();
fl.trace(doc.selection[0].width + ' by ' + doc.selection[0].height);

for one selected clip at authortime, within the IDE.

I did a similar test with a bit of actionscript:

//draw faces
var front:Sprite = drawFace();
var back:Sprite = drawFace();
var left:Sprite = drawFace();
var right:Sprite = drawFace();
var top:Sprite = drawFace();
var bottom:Sprite = drawFace();
//transform faces
front.z  = -50;
back.z   =  50;
left.x   = -50;
right.x  =  50;
top.y    = -50;
bottom.y =  50;
left.rotationY = right.rotationY = 90;
top.rotationX = bottom.rotationX = 90;
//putem them all together
var cube:Sprite = new Sprite();
cube.addChild(front);
cube.addChild(back);
cube.addChild(left);
cube.addChild(right);
cube.addChild(top);
cube.addChild(bottom);
addChild(cube);
cube.x = stage.stageWidth * .5;
cube.y = stage.stageHeight* .5;
cube.z = -100;
cube.rotationX = cube.rotationY = 30;

trace(cube.width + ' by ' + cube.height);
trace(cube.getBounds(this));
trace(cube.transform.pixelBounds);
this.addEventListener(Event.ENTER_FRAME, loop);
function loop(event:Event):void {
    cube.rotationY += 3;
    var b:Rectangle = cube.getBounds(this);
    graphics.clear();
    graphics.lineStyle(1,0x009900);
    graphics.drawRect(b.x,b.y,b.width,b.height);
}

function drawFace():Sprite{
    var s:Sprite = new Sprite();
    s.graphics.beginFill(0x000099,.5);
    s.graphics.drawRect(-50,-50,100,100);
    s.graphics.endFill();
    return s;
}

Here is a modified sample from Programming Actionscript 3.0

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

    public class Triangles extends Sprite {  
        var x1:Number = -100,y1:Number = -100,z1:Number = 0,t1:Number = 0;  
        var x2:Number = 100,y2:Number = -100,z2:Number = 0,t2:Number = 0;  
        var x3:Number = 100,y3:Number = 100,z3:Number = 0,t3:Number = 0;  
        var x4:Number = -100,y4:Number = 100,z4:Number = 0,t4:Number = 0;  
        var v1 = new Vector3D(-100,-100,0,0);
        var v2 = new Vector3D(100,-100,0,0);
        var v3 = new Vector3D(100,100,0,0);
        var v4 = new Vector3D(-100,100,0,0);
        var focalLength:Number = 200;   
        var indices:Vector.<int>;  

        var container:Sprite;  

        var bitmapData:BitmapData; // texture  
        var imageLoader:ImageLoader;  

        public function Triangles():void {  
            indices =  new Vector.<int>();  
            indices.push(0,1,3, 1,2,3);  

            container = new Sprite(); // container to draw triangles in  
            container.x = 200;  
            container.y = 200;  
            addChild(container);  

            imageLoader = new ImageLoader("head.jpg");  
            imageLoader.addEventListener(Event.COMPLETE, onImageLoaded);  
        }  

        function onImageLoaded(event:Event):void {  
            bitmapData = imageLoader.bitmap.bitmapData; 
            addEventListener(Event.ENTER_FRAME, rotatePlane);  
        }  
        function rotatePlane(event:Event):void {  
            var ticker = getTimer()/1600;  
            z2 = z3 = -(z1 = z4 = 100*Math.sin(ticker));  
            x2 = x3 = -(x1 = x4 = 100*Math.cos(ticker));  

            v2.z = v3.z = -(v1.z = v4.z = 100*Math.sin(ticker));
            v2.x = v3.x = -(v1.x = v4.x = 100*Math.cos(ticker));


            t1 = focalLength/(focalLength + z1);  
            t2 = focalLength/(focalLength + z2);  
            t3 = focalLength/(focalLength + z3);  
            t4 = focalLength/(focalLength + z4);  

            v1.w = focalLength/(focalLength + v1.z);  
            v2.w = focalLength/(focalLength + v2.z);  
            v3.w = focalLength/(focalLength + v3.z);  
            v4.w = focalLength/(focalLength + v4.z);  

            // determine triangle vertices based on t values  
            var vertices:Vector.<Number> = new Vector.<Number>();  
            //vertices.push(x1*t1,y1*t1, x2*t2,y2*t2, x3*t3,y3*t3, x4*t4,y4*t4);  

            vertices.push(v1.x*v1.w,v1.y*v1.w, v2.x*v2.w,v2.y*v2.w, v3.x*v3.w,v3.y*v3.w, v4.x*v4.w,v4.y*v4.w);  
            var uvtData:Vector.<Number> = new Vector.<Number>();  
            uvtData.push(0,0,v1.w, 1,0,v2.w, 1,1,v3.w, 0,1,v4.w);  

            // draw  
            container.graphics.clear();  
            container.graphics.beginBitmapFill(bitmapData);  
            container.graphics.drawTriangles(vertices, indices, uvtData);  
            var b:Rectangle = container.transform.pixelBounds;
            graphics.clear();
            graphics.lineStyle(1,0x009900);
            graphics.drawRect(b.x,b.y,b.width,b.height);
        }  
    }  
} 

pixelBounds work well here, but it's a simple plane. pixelBounds wouldn't work in the previous example, but getBounds() seems to work fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文