Author Archive: pixel-bender

Preview 3 and the future of PB3D

We have just released preview 3 of Pixel Bender 3D (PB3D) http://labs.adobe.com/technologies/pixelbender3d. This is the best preview to date in terms of reliability and stability. Please look at the release notes (http://labs.adobe.com/technologies/pixelbender3d/releasenotes.html) for the details.

PB3D remains an experiment, where we are exploring the utility of the language for high-level authoring of Stage 3D shaders. Workflows remain command-line based, and it is still easy to write programs that exceed the limitations of Stage 3D. To spend the resources to address the workflow issue would require a significant investment from Adobe, and to justify that we would need extraordinary uptake from the developer community. Please regard the current state of the system as an opportunity to evaluate whether the language is a useful design for your needs, and let us know if you would adopt it for main-line use given a more convenient workflow or language changes, or if it is useful in its current form. Unless PB3D gains significant momentum in the next few months, this is likely to be the last release.

Please note that this announcement only concerns Pixel Bender 3D. Pixel Bender 2D and Flash Player Stage 3D remain unchanged.

Prerelease 2 is now out

Prerelease 2 of the PixelBender3D API is now available on the Adobe labs site here:

http://labs.adobe.com/technologies/pixelbender3d/

There are a bunch of bug fixes, and some improvements to the public API to make it easier to set up input values. Check out the full release notes included with the prerelease.

Displaying numbers in a kernel

One of the problems with Pixel Bender is that it’s always been difficult to debug. This kernel helps out a little – it provides a way to display integers and floats on screen.

The value you’re trying to display must be the same for each invocation of the kernel – that means that it can’t depend on outCoord in any way. If you’re trying to debug something that only happens at a particular position you’ll need to hard code that position in for testing.

There are two functions – one for displaying integers and one for displaying floats:

bool
displayInt( int n, int2 topLeft, int scale, int width, bool displayleadingZeros );

bool
displayFloat( float f, int2 topLeft, int scale, int width, int precision, bool displayleadingZeros );

Each of them returns a bool – if the return value is true the pixel is part of the number to be displayed and should be highlighted in some manner.

The kernel here exposes most of the options as parameters just to make it easy to play around with them – in practice just set them to reasonable constant values.

<languageVersion : 1.0;>
kernel NumberDisplay
<   
    namespace : "AIF Test";
    vendor : "Adobe";
    version : 1;
    description : "Display numbers";
>
{
    input image4 src;
    output pixel4 dst;

    parameter int intValue
    <
        minValue : -150;
        maxValue : 50;
        defaultValue: 10;
    >;

    parameter float floatValue
    <
        minValue : -15.0;
        maxValue : 15.0;
        defaultValue: 0.0;
    >;

    parameter bool displayleadingZerosParam
    <
        defaultValue: false;
    >;
        
    parameter int intScale
    <
        minValue : 3;
        maxValue : 10;
        defaultValue: 5;
    >;
    
    parameter int nDigitsParam
    <
        minValue : 5;
        maxValue : 10;
        defaultValue: 5;
    >;
    
    parameter int floatWidth
    <
        minValue : 10;
        maxValue : 20;
        defaultValue: 10;
    >;
    
    parameter int floatPrecision
    <
        minValue : 2;
        maxValue : 7;
        defaultValue: 2;
    >;
    
    parameter int floatScale
    <
        minValue : 3;
        maxValue : 10;
        defaultValue: 5;
    >;
    
    
    const int digitXSpacing = 4;

    bool
    hitPosition( float4x4 m, int2 p )
    {
        return m[ p[ 1 ] ][ p[ 0 ] ] > 0.5;
    }

    bool displayNegativeSign( int digit, int2 gridPosition )
    {
        bool result = false;

        if( gridPosition.x >= 0 && gridPosition.x < 3 && gridPosition.y >= 0 && gridPosition.y < 5 )
        {
                int offset1D = gridPosition.y * 3 + gridPosition.x;
                
                int2 matrixPosition = int2( int( mod( float( offset1D ), 4.0 ) ), offset1D / 4 );

                result = hitPosition( float4x4( 0, 0, 0,  0, 0, 0,  1, 1, 1,  0, 0, 0,  0, 0, 0,  0 ), matrixPosition );
        }

        return result;
    }
    
    bool displayDecimalPoint( int2 gridPosition )
    {
        bool result = false;

        if( gridPosition.x >= 0 && gridPosition.x < 3 && gridPosition.y >= 0 && gridPosition.y < 5 )
        {
                int offset1D = gridPosition.y * 3 + gridPosition.x;
                
                int2 matrixPosition = int2( int( mod( float( offset1D ), 4.0 ) ), offset1D / 4 );

                result = hitPosition( float4x4( 0, 0, 0,  0, 0, 0,  0, 0, 0,  0, 0, 0,  0, 1, 0,  0 ), matrixPosition );
        }

        return result;
    }
    
    bool displayInt( int n, int digit, int2 gridPosition, int width, bool displayleadingZeros )
    {
        bool result = false;

        for( int i = 0; i < width - ( digit + 1 ); ++i )
        {
            n /= 10;
        }

        if( n != 0 || digit == width - 1 || displayleadingZeros )
        {
            n = int( mod( float( n ), 10.0 ) );

            int offset1D = gridPosition.y * 3 + gridPosition.x;
            
            int2 matrixPosition = int2( int( mod( float( offset1D ), 4.0 ) ), offset1D / 4 );

            if( n == 0 ) result = hitPosition( float4x4( 1, 1, 1,  1, 0, 1,  1, 0, 1,  1, 0, 1,  1, 1, 1, 0 ), matrixPosition );
            if( n == 1 ) result = hitPosition( float4x4( 0, 0, 1,  0, 0, 1,  0, 0, 1,  0, 0, 1,  0, 0, 1, 0 ), matrixPosition );
            if( n == 2 ) result = hitPosition( float4x4( 1, 1, 1,  0, 0, 1,  1, 1, 1,  1, 0, 0,  1, 1, 1, 0 ), matrixPosition );
            if( n == 3 ) result = hitPosition( float4x4( 1, 1, 1,  0, 0, 1,  1, 1, 1,  0, 0, 1,  1, 1, 1, 0 ), matrixPosition );
            if( n == 4 ) result = hitPosition( float4x4( 1, 0, 1,  1, 0, 1,  1, 1, 1,  0, 0, 1,  0, 0, 1, 0 ), matrixPosition );
            if( n == 5 ) result = hitPosition( float4x4( 1, 1, 1,  1, 0, 0,  1, 1, 1,  0, 0, 1,  1, 1, 1, 0 ), matrixPosition );
            if( n == 6 ) result = hitPosition( float4x4( 1, 1, 1,  1, 0, 0,  1, 1, 1,  1, 0, 1,  1, 1, 1, 0 ), matrixPosition );
            if( n == 7 ) result = hitPosition( float4x4( 1, 1, 1,  0, 0, 1,  0, 0, 1,  0, 0, 1,  0, 0, 1, 0 ), matrixPosition );
            if( n == 8 ) result = hitPosition( float4x4( 1, 1, 1,  1, 0, 1,  1, 1, 1,  1, 0, 1,  1, 1, 1, 0 ), matrixPosition );
            if( n == 9 ) result = hitPosition( float4x4( 1, 1, 1,  1, 0, 1,  1, 1, 1,  0, 0, 1,  1, 1, 1, 0 ), matrixPosition );
        }            

        return result;
    }

    int getNDigits( int n )
    {
        return int( ceil( log2( float( n + 1 ) ) / log2( 10.0 ) ) );
    }

    void
    getGridInformation( int2 topLeft, int scale, out int digit, out int2 gridPosition )
    {
            float2 offsetFromTopLeftFloat = floor( outCoord() - float2( topLeft ) );
            int2 offsetFromTopLeftInt = int2( offsetFromTopLeftFloat );
            int2 gridOffsetFromTopLeftInt = int2( floor( float2( offsetFromTopLeftInt ) / float2( scale ) ) );

            digit = gridOffsetFromTopLeftInt.x / digitXSpacing;
            gridPosition = int2( gridOffsetFromTopLeftInt.x - digit * digitXSpacing, gridOffsetFromTopLeftInt.y );
    }

    // Returns true iff this is a position that might lead to a number being displayed
    bool 
    positionNeedsChecking( int digit, int2 gridPosition, int width )
    {
        return 
            gridPosition.x >= 0 && 
            gridPosition.x < 3 && 
            gridPosition.y >= 0 && gridPosition.y < 5 
            && digit >= 0 && digit < width;
    }

    bool
    displayInt( int n, int digit, int2 gridPosition, int scale, int width, bool displayleadingZeros )
    {
        bool result = false;
        
        bool negative = n < 0;
        n = n < 0 ? -n : n;

        int negativeDigitPosition = displayleadingZeros ? 0 : width - getNDigits( n ) - 1;

        if( negative && digit == negativeDigitPosition )
        {
            result = displayNegativeSign( digit, gridPosition );
        }
        else
        {
            result = displayInt( n, digit, gridPosition, width, displayleadingZeros );
        }

        return result;
    }
    
    bool
    displayInt( int n, int2 topLeft, int scale, int width, bool displayleadingZeros )
    {
        bool result = false;

        int digit;
        int2 gridPosition;

        getGridInformation( topLeft, scale, digit, gridPosition );

        if( positionNeedsChecking( digit, gridPosition, width ) )
        {
            result = displayInt( n, digit, gridPosition, scale, width, displayleadingZeros );
        }

        return result;
    }

    bool
    displayFloat( float f, int2 topLeft, int scale, int width, int precision, bool displayleadingZeros )
    {
        bool result = false;

        int i = int( f > 0.0 ? floor( f ) : ceil( f ) );
        float fra = f > 0.0 ? ( f - float( i ) ) : ( -f + float( i ) );

        int digit;
        int2 gridPosition;

        getGridInformation( topLeft, scale, digit, gridPosition );

        if( positionNeedsChecking( digit, gridPosition, width ) )
        {
            int intWidth = width - precision - 1;

            // Display the integer value
            if( positionNeedsChecking( digit, gridPosition, intWidth ) )
                result = displayInt( i, digit, gridPosition, scale, intWidth, displayleadingZeros );

            // Display the fractional value
            if( positionNeedsChecking( digit - intWidth - 1, gridPosition, precision ) )
                result = result || 
                   displayInt( int( fra * pow( 10.0, float( precision ) ) ) , digit - intWidth - 1, gridPosition, scale, precision, true );

            // Display the decinal point
            if( digit == intWidth )
            {
                result = result || displayDecimalPoint( gridPosition );
            }
        }
        
        return result;
    }

    void
    evaluatePixel()
    {
        dst = sampleNearest( src, outCoord() );

        if( displayInt( intValue, int2( 10, 10 ), intScale, 12, displayleadingZerosParam ) )
        {
            dst = float4( 1.0, 0.0, 0.0, 1.0 );
        }

        if( displayFloat( floatValue, int2( 10, 50 ), floatScale, floatWidth, floatPrecision, displayleadingZerosParam ) )
        {
            dst = float4( 0.0, 0.0, 1.0, 1.0 );
        }
    }
}

The AIF team is looking for a new engineering manager

The job posting for our new engineering manager is up on the Adobe job site. The AIF team develops the Pixel Bender language and all of the behind the scenes magic that makes it run so fast. Check it out here:

https://adobe.taleo.net/careersection/2/jobdetail.ftl?lang=en&job=08505

Pixel bender 3D public beta now available

We’re delighted to announce we’ve just released the first public beta for Pixel Bender 3D. The Pixel Bender 3D technology works in conjunction with the new Molehill Flash API to make it easy to write shaders for your 3D models. To find out more about PB3D and download the initial release go to http://www.adobe.com/go/pixelbender3d. To find out more about Molehill go to www.adobe.com/go/molehill.

Please bear in mind that this is a beta release – as you’ll see from the release notes there are plenty of bugs and missing features that we know about, and I am sure there are plenty that we don’t know about. We’ve set up a forum here that we’ll be monitoring – let us know what problems you find and what cool things you’re doing with PB3D.

Welcome!

Welcome to the new Pixel Bender blog. Over the past few years, Kevin Goldsmith has hosted Pixel Bender content on his Adobe blog, but finally Pixel Bender has a blog of its own.

Remember that there’s still lots of great Pixel Bender content on Kevin’s blog.