actionscript-3texturespixel-shaderstage3dagal

Render to texture not functioning


I'm trying to test Stage3D's setRenderToTexture function, but my test code is not providing any output. I was hoping someone could tell me why - I've tried practically everything to get this working. The code I've created is below:

import flash.events.Event;
import flash.display.*;
import flash.display3D.*;
import flash.display3D.textures.Texture;
import AGALMiniAssembler;

//using stage size in several locations for simplicity - needs to be square, 2^n
[SWF(width='512', height='512', backgroundColor='0x000000', frameRate='60')]

//vars
var context0:Context3D;
var vBuff:VertexBuffer3D;
var iBuff:IndexBuffer3D;
var tex0:Texture;
var tex1:Texture;
var vShader:AGALMiniAssembler = new AGALMiniAssembler();
var fShader:AGALMiniAssembler = new AGALMiniAssembler();
var program:Program3D;

//create a square
var square:Shape = new Shape();
square.graphics.beginFill(0xaa00ff,1);
square.graphics.drawRect(10, 10, stage.stageWidth - 20, stage.stageHeight - 20);

//draw square to bitmapdata and create one blank bitmapdata
var tex0data:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0);
tex0data.draw(square);
var tex1data:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0);

//initialize stage3d
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, initStage3D);
stage.stage3Ds[0].requestContext3D();

function initStage3D(e:Event):void {
    context0 = stage.stage3Ds[0].context3D;
    context0.configureBackBuffer(stage.stageWidth, stage.stageHeight, 0);

    //create buffers - simple quad
    var vBuff_vec:Vector.<Number> = new <Number>[-1, -1, 0, 0, 1,
                                                 -1, 1, 0, 0, 0,
                                                 1, 1, 0, 1, 0,
                                                 1, -1, 0, 1, 1];
    var iBuff_vec:Vector.<uint> = new <uint>[0, 1, 2, 0, 2, 3]
    vBuff = context0.createVertexBuffer(4, 5);
    vBuff.uploadFromVector(vBuff_vec, 0, 4);
    iBuff = context0.createIndexBuffer(6);
    iBuff.uploadFromVector(iBuff_vec, 0, 6);

    //load bitmapdata into textures - square to tex0 and blank to tex1
    tex0 = context0.createTexture(tex0data.width,tex0data.height,'bgra',false);
    tex0.uploadFromBitmapData(tex0data);    
    tex1 = context0.createTexture(tex1data.width, tex1data.height,'bgra',true);
    tex1.uploadFromBitmapData(tex1data);

    //create and upload simple shader program
    vShader.assemble('vertex', 'mov v0, va1 \n'+ //uv coords to v0
                                 'mov op, va0'); //output xyz coords
    fShader.assemble('fragment', 'tex oc, v0, fs0 <2d, linear, nomip>'); //output texture at fs0
    program = context0.createProgram();
    program.upload(vShader.agalcode, fShader.agalcode);
    context0.setProgram(program);

    //set buffers
    context0.setVertexBufferAt(0, vBuff, 0, 'float3');
    context0.setVertexBufferAt(1, vBuff, 3, 'float2');

    //prep rendering
    addEventListener(Event.ENTER_FRAME, render);
}

function render(e:Event):void {
    context0.clear();

    //render tex0 onto tex1
    context0.setRenderToTexture(tex1);
    context0.setTextureAt(0, tex0);
    context0.drawTriangles(iBuff);

    //render tex1 to back buffer and present
    context0.setTextureAt(0, tex1);
    context0.setRenderToBackBuffer();
    context0.drawTriangles(iBuff);
    context0.present();
}

EDIT: I have noticed that changing the color of the blank bitmap does change the color of the final output - it's being displayed, but the square isn't being rendered to it.


Solution

  • FINALLY figured this out! There is a subtle, but important, step that must be taken before a texture is viable as a render target - it must be cleared after the render target is switched. Revising the render function as follows causes the program to function as expected:

    function render(e:Event):void {
        //render tex0 onto tex1
        context0.setRenderToTexture(tex1);
        context0.clear();
        context0.setTextureAt(0, tex0);
        context0.drawTriangles(iBuff);
    
        //render tex1 to back buffer and present
        context0.setTextureAt(0, tex1);
        context0.setRenderToBackBuffer();
        context0.clear();
        context0.drawTriangles(iBuff);
        context0.present();
    }