actionscript-3 - AS3 Softbody 纹理八哥

标签 actionscript-3 textures vertex stage3d starling-framework

我在颈背处创建了一个柔软的 body 圆圈。现在我正在尝试让它变得有纹理。但我遇到了麻烦,我找不到答案。这就是为什么我向你们求助。

我正在尝试做他在这个 Objective C 教程中所做的事情:

http://www.uchidacoonga.com/2012/04/soft-body-physics-with-box2d-and-cocos2d-part-44/

关于如何使用 starling 和 stage3d 做到这一点有什么想法吗?

最佳答案

您必须编写一个自定义显示对象(请参阅 Starling manual )。这是一个基本示例:

package
{
    import com.adobe.utils.AGALMiniAssembler;

    import flash.display3D.Context3D;
    import flash.display3D.Context3DProgramType;
    import flash.display3D.Context3DVertexBufferFormat;
    import flash.display3D.IndexBuffer3D;
    import flash.display3D.VertexBuffer3D;
    import flash.geom.Point;
    import flash.utils.ByteArray;

    import starling.core.RenderSupport;
    import starling.core.Starling;
    import starling.display.DisplayObject;
    import starling.errors.MissingContextError;
    import starling.textures.Texture;

    public class Ball extends DisplayObject
    {
        private static const PROGRAM_NAME:String = "ball";

        private var _texture:Texture;

        private var _numSides:uint;

        private static const data32PerVertex:uint = 4;

        private var _vertices:Vector.<Number>;
        private var _indices:Vector.<uint>;

        private var _vertexBuffer:VertexBuffer3D;
        private var _indexBuffer:IndexBuffer3D;

        public function Ball(initialX:Number, initialY:Number, initialR:Number, texture:Texture, numSides:uint = 10) {
            _texture = texture;
            _numSides = numSides;

            // if the texture is a SubTexture (i.e. a texture from an atlas), then you need
            // to modify these values to match the sub-texture UV bounds.
            var minU:Number = 0, minV:Number = 0, maxU:Number = 1, maxV:Number = 1;

            setupGeometry(initialX, initialY, initialR, minU, minV, maxU, maxV);

            createBuffers();
            registerPrograms();
        }

        private function setupGeometry(initialX:Number, initialY:Number, initialR:Number, uMin:Number, vMin:Number, uMax:Number, vMax:Number):void {
            const numVertices:uint = _numSides + 1,
                  numSideVertices:uint = _numSides,
                  txtCu:Number = (uMin + uMax) / 2, // center of the circle in UV coords
                  txtCv:Number = (vMin + vMax) / 2,
                  txtRu:Number = uMax - txtCu,      // radiuses of the circle in UV coords
                  txtRv:Number = vMax - txtCv;

            _vertices = new Vector.<Number>(data32PerVertex * numVertices, true);
            _indices  = new Vector.<uint>(3 * _numSides, true);

            var centerVectexIndex:uint = _numSides;

            // side vertices

            for (var sideVertexI:uint = 0; sideVertexI < numSideVertices; ++sideVertexI) {
                var dataOffset:uint = sideVertexI * data32PerVertex,
                    angle:Number = 2 * Math.PI * sideVertexI / _numSides,
                    sinA:Number = Math.sin(angle),
                    cosA:Number = Math.cos(angle);

                _vertices[dataOffset    ] = initialX + initialR * cosA; // x
                _vertices[dataOffset + 1] = initialY + initialR * sinA; // y
                _vertices[dataOffset + 2] = txtCu + txtRu * cosA; // u
                _vertices[dataOffset + 3] = txtCv + txtRv * sinA; // v

                var indexOffset:uint = 3 * sideVertexI;

                _indices[indexOffset    ] = centerVectexIndex;
                _indices[indexOffset + 1] = sideVertexI;
                _indices[indexOffset + 2] = (sideVertexI + 1) % numSideVertices;
            }

            // center vertex

            dataOffset = centerVectexIndex * data32PerVertex;

            _vertices[dataOffset    ] = initialX; // x
            _vertices[dataOffset + 1] = initialY; // y
            _vertices[dataOffset + 2] = txtCu; // u
            _vertices[dataOffset + 3] = txtCv; // v
        }

        private function createBuffers():void {
            var context:Context3D = Starling.context;
            if (context == null) {
                throw new MissingContextError();
            }

            _vertexBuffer && _vertexBuffer.dispose();
            _indexBuffer  && _indexBuffer.dispose();

            const verticesCount:uint = _numSides + 1;

            _vertexBuffer = context.createVertexBuffer(verticesCount, 4);
            _vertexBuffer.uploadFromVector(_vertices, 0, verticesCount);

            const indicesCount:uint = 3 * _numSides; // _numSides triangles, 3 indices per each triangle

            _indexBuffer = context.createIndexBuffer(indicesCount);
            _indexBuffer.uploadFromVector(_indices, 0, indicesCount);
        }

        private function registerPrograms():void {
            var starling:Starling = Starling.current;
            if (starling.hasProgram(PROGRAM_NAME)) {
                return;
            }

            // va0.xy - position
            // va1.xy - UV coords
            // vc0-vc3 - mvp matrix

            var vertexAGAL:String =
                "m44 op, va0, vc0 \n" +
                "mov v0, va1";

            var fragmentAGAL:String =
                "tex oc, v0, fs0 <2d, clamp, linear, mipnone> \n"; // just sample texture color

            var asm:AGALMiniAssembler      = new AGALMiniAssembler(),
                vertexBytecode:ByteArray   = asm.assemble(Context3DProgramType.VERTEX,   vertexAGAL),
                fragmentBytecode:ByteArray = asm.assemble(Context3DProgramType.FRAGMENT, fragmentAGAL);

            starling.registerProgram(PROGRAM_NAME, vertexBytecode, fragmentBytecode);
        }

        override public function render(support:RenderSupport, parentAlpha:Number):void {
            var context:Context3D = Starling.context;
            if (context == null) {
                throw new MissingContextError();
            }

            support.finishQuadBatch();

            // setup

            support.applyBlendMode(_texture.premultipliedAlpha);
            context.setProgram(Starling.current.getProgram(PROGRAM_NAME));

            context.setVertexBufferAt(0, _vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2); // position, va0
            context.setVertexBufferAt(1, _vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2); // uv, va1
            context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, support.mvpMatrix3D, true); // mvp matrix, vc0-vc3

            context.setTextureAt(0, _texture.base); // texture, fs0

            // draw

            context.drawTriangles(_indexBuffer);
            support.raiseDrawCount();

            // clean up

            context.setVertexBufferAt(0, null);
            context.setVertexBufferAt(1, null);
            context.setTextureAt(0, null);
        }

        override public function hitTest(localPoint:Point, forTouch:Boolean = false):DisplayObject {
            var isHit:Boolean = false;

            // to achieve proper mouse handling, you need to place here the code
            // that checks if localPoint is contained inside any of triangles and
            // sets isHit flag accorgingly.

            return isHit ? this : null;
        }
    }
}

使用示例:

package
{
    import flash.display.BitmapData;
    import flash.display.GradientType;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.geom.Matrix;

    import starling.display.Sprite;
    import starling.textures.Texture;

    public class BallExperiment extends starling.display.Sprite
    {
        public function BallExperiment() {
        }

        public function start():void {
            const numSides:uint = 7;

            var txt:Texture = createBallTxt(numSides, true);
            var ball:Ball = new Ball(200, 200, 50, txt, numSides);

            addChild(ball);
        }

        private function createBallTxt(numSides:uint, debugFillBcgr:Boolean = false):Texture {
            var canvas:flash.display.Sprite = new flash.display.Sprite(),
                g:Graphics = canvas.graphics;

            // as we don't want to use sub-textures in this simple example, we need this
            // number to be a power of two: otherwise Starling will internally create
            // a power-of-two-sized texture and return a sub-texture of this bigger texture.
            const size:Number = 512;

            // we need to make the radius of a ball texture to be smaller than size/2 in order
            // to prevent the texture from extending beyond our triangles.
            var rScale:Number = Math.cos(Math.PI / numSides),
                r:Number = rScale * (size / 2);

            g.lineStyle(0, 0, 0);

            // draw uniform background to show actual triangulation

            if (debugFillBcgr) {
                g.beginFill(0xBB4400, 0.2);
                g.drawRect(0, 0, size, size);
                g.endFill();
            }

            // draw the ball

            g.beginFill(0x0000DD);
            g.drawCircle(size / 2, size / 2, r);

            var m:Matrix = new Matrix();
                m.createGradientBox(size, size);

            g.beginGradientFill(GradientType.LINEAR, [0x00DD00, 0x00DD00], [0, 1], [0, 255], m);
            g.drawCircle(size / 2, size / 2, r);
            g.endFill();

            const smallCircleR:Number = r / 10,
                  smallCircleCR:Number = r - 2 * smallCircleR;

            g.beginFill(0xBB0000);

            for (var i:uint = 0; i < numSides; ++i) {
                var angle:Number = 2 * Math.PI * i / numSides,
                    cx:Number = size / 2 + smallCircleCR * Math.cos(angle),
                    cy:Number = size / 2 + smallCircleCR * Math.sin(angle);
                g.drawCircle(cx, cy, smallCircleR);
            }

            g.drawCircle(size / 2, size / 2, smallCircleR);
            g.endFill();

            // create and return the texture

            var bmd:BitmapData = new BitmapData(size, size, true, 0);
                bmd.draw(canvas);

            return Texture.fromBitmapData(bmd);
        }
    }
}

运行者示例:

package
{
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;

    import starling.core.Starling;
    import starling.events.Event;

    [SWF(width = 600, height = 500, frameRate = 60)]

    public class StarlingTestRunner extends Sprite
    {

        public function StarlingTestRunner() {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            Starling.multitouchEnabled = false;
            Starling.handleLostContext = false;

            var starling:Starling = new Starling(BallExperiment, stage);
            starling.showStats = true;
            starling.simulateMultitouch = true;
            starling.enableErrorChecking = true;
            starling.addEventListener(Event.ROOT_CREATED, onTestCreated);
            starling.start();
        }

        private function onTestCreated(e:Event, test:BallExperiment):void {
            test.start();
        }
    }
}

结果:

enter image description here

要使球变形,只需修改 _vertices 向量中与 xy 坐标相对应的元素(即索引为 的元素) >4n4n + 1,其中 n = 0 .. numSides),然后将 _vertices 数组重新上传到顶点缓冲区。

或者,您可以使用 VertexData 辅助类实现球几何形状,如 Starling 手册中所示。

关于actionscript-3 - AS3 Softbody 纹理八哥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14568132/

相关文章:

actionscript-3 - as3中的动画 "blob"

cocoapods - SCNScene 加载来自 pod 的纹理

python - Canvas 上的 Kivy 插值

c++ - 在 OpenGL 中处理顶点的最佳技术? C++

algorithm - 最小顶点覆盖的验证算法?

flash - 如何绘制正弦线图?

actionscript-3 - 减小 SWF 文件大小

apache-flex - 仅使用实例调用类的静态方法

javascript - WebGL 纹理调整大小意外输出

c++ - 如何正确填充顶点数组