【问题标题】:How to get visible size of DisplayObject with perspective projection如何通过透视投影获得 DisplayObject 的可见大小
【发布时间】:2011-02-14 17:59:20
【问题描述】:

以下完全是一道数学题。

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

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


(来源:bgstaal.net

问:如何获取已应用 PerspectiveProjection 的 DisplayObject(上面链接图像上的立方体)的可见屏幕尺寸?

ActionScript 3 lacks functionality for visible bounds of DisplayObject 中有关该问题的更详尽描述和说明性代码。

【问题讨论】:

  • 按大小,你是指立方体在投影到舞台上的面积吗?
  • 我相信 Flex 的 UIComponent 有这些测量能力:help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/… 你可以查看 UIComponent 的源代码,看看它是如何实现的。
  • @贾斯汀是的。 @James 好建议。当我创建这个问题时,我正在学习数学。 Colin Moock 在bugs.adobe.com/jira/browse/FP-741 提到的编程方法已经存在,我已经成功部署了它,但它仍然不是问题。数学方法可以在不输出到 Stage 的情况下知道尺寸。
  • 如果您愿意自己进行计算,则应按此处所述与您的视图投影矩阵相乘。 gamedev.net/community/forums/topic.asp?topic_id=426094(数学在 Flash 中应该是一样的)。这就是 gluProject 所做的。

标签: flash actionscript-3 math 3d projection


【解决方案1】:

我想我没有抓住重点。

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

宽度和高度报告可见 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;
}

这是来自 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 在这里工作得很好,但它是一个简单的平面。 pixelBounds 在前面的示例中不起作用,但 getBounds() 似乎可以正常工作。

【讨论】:

  • 问题是关于透视投影和数学相关的特别是。关于元素的可见尺寸。 getBounds 和 pixelBounds 方法都返回一个不考虑转换的值。
  • @Ain 我更新了一些代码,getBounds() 似乎在立方体上工作正常,pixelBounds 报告剪辑的未转换边界。有一个使用 drawTriangles() 的简单测试,它似乎工作正常。你有一个简单的例子,或者你能重新创建你的问题的最小版本吗?
  • 参见tekkie.flashbit.net/flash/as/… 获取代码片段。我不能在这里过去所以我写了一个详细的文章。
  • @Ain 你的数字和我的不一样。我不是在谈论舞台大小,而是在谈论两个边界框之间的明显差异。我在这里用红色绘制了 visibleBounds,用绿色绘制了边界:i984.photobucket.com/albums/ae330/orgicus/Picture8.png 两者看起来都很近。是我使用的舞台尺寸还是其他?您使用什么 Flash Player 版本?
  • 透视投影是根据舞台大小计算的,因此上述代码中的可见边界会有所不同。可见边界是您在屏幕上看到的,这意味着它们是许多场合所需要的,例如布局计算,如果您手动测量,它们是正确的。令人担忧的是,Adobe 应该引入一种方法来检索这些边界,而无需进行任何额外的数学运算或操作。
猜你喜欢
  • 1970-01-01
  • 2015-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多