Spark 3D effects

Most effects manipulate the effect target in the x and y dimensions to create two-dimensional effects. In the two-dimensional coordinate system, the x, y coordinates of 0, 0 corresponds to the upper-left corner of the component’s coordinate system. For example, if the Application container takes up your full computer screen, those coordinates correspond to the upper-left corner of the computer screen. Increasing values of x moves to the right of the compute screen, and increasing values of y move down the screen.

The 3D effects add support for the z-axis. The z = 0 coordinate corresponds to the plane of the computer screen. Increasing values of z moves an object into the screen, making the object look farther away from the viewer. Decreasing values of z move the object toward the viewer.

The spark 3D effects are transform effects designed to take advantage of the support for three-dimensional graphics in Flash Player. Flex includes the following 3D effects:

  • Move3D

    Moves the effect target in the x, y, and z coordinate system. Moving the target to increasing values in the z direction makes it appear to move back away from the viewer, so the target shrinks. Moving the target to decreasing values in the z direction makes it appear to move toward the viewer, so the target grows.

  • Rotate3D

    Rotates the effect target around the x, y, or z-axis. For example, rotating the target around the y-axis rotates the object vertically through the x and z planes, similar to a door opening and closing on vertical hinges. Rotating the target around the z-axis makes the object rotate through the x and y planes, which is the same as a two-dimensional rotation.

  • Scale3D

    Scales the effect target in the x, y, and z directions by setting the appropriate scale properties on the target. A scale of 2.0 means the object has been magnified by a factor of 2. A scale of 0.5 means the object has been reduced by a factor of 2. A scale value of 0.0 is not allowed.

For an introduction to transform effects, see Spark transform effects.

Applying 3D effects

The following example applies the Move3D effect to an image:

<?xml version="1.0"?>
<!-- behaviors\Spark3DMoveEffect.mxml -->
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Declarations>
        <s:Move3D id="moveEffect" target="{targetImg}" 
            xBy="100" zBy="100" 
            repeatCount="2" repeatBehavior="reverse" 
            effectStart="playButton.enabled=false;"
            effectEnd="playButton.enabled=true;"/>
    </fx:Declarations>

    <s:Panel title="Move3D Effect Example"
        width="75%" height="75%" >
 
        <s:Image id="targetImg" 
            horizontalCenter="0"
            verticalCenter="0"
            source="@Embed(source='assets/Nokia_6630.png')"/>
            
        <s:Button id="playButton"
            left="5" bottom="5"
            label="Move3D" 
            click="moveEffect.play();"/>
    </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below:

In this example, the Move3D effect moves the target by increasing the value of the x and z coordinates by 100. It then reverses, and moves the component back to its original x and z coordinates. To the user, the image moves to the left and shrinks, then moves back to the right and grows to its original size.

The following example uses the Rotate3D effect to rotate the image around the y-axis:

<?xml version="1.0"?>
<!-- behaviors\Spark3DRotateEffect.mxml -->
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Declarations>
        <s:Rotate3D id="rotateEffect" target="{targetImg}" 
            angleYFrom="0" angleYTo="360" 
            repeatCount="2" repeatBehavior="reverse" 
            effectStart="playButton.enabled=false;"
            effectEnd="playButton.enabled=true;"/>
    </fx:Declarations>

    <s:Panel title="Rotate 3D Effect Example"
        width="75%" height="75%" >
 
        <s:Image id="targetImg" 
            horizontalCenter="0"
            verticalCenter="0"
            source="@Embed(source='assets/Nokia_6630.png')"/>

        <s:Button id="playButton"
            left="5" bottom="5"
            label="Rotate3D" 
            click="rotateEffect.play();"/>
    </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below:

Setting the transform center of a 3D effect

By default, the transform center of the target of a 3D transform effect is the upper-left corner of the target component. This point corresponds to coordinates (0, 0, 0) in the target component’s coordinate system. You can set the transform center to a different location. For an introduction to setting the transform center for two-dimensional effects, see Applying transform effects.

If you run the example in the previous section, you notice that the target object rotates around its left edge. That is because the effects, by default, operates around the default transform center of the target object.

Often, you want to rotate the target component around its center point instead of around the default transform center. One option is to set the transform center to the center point of the component by setting the autoCenterTransform property to true. The following example modifies the example from the previous section to rotate the image around its center point:
<?xml version="1.0"?>
<!-- behaviors\Spark3DRotateLayoutCenterTransform.mxml -->
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Declarations>
        <s:Rotate3D id="rotateEffect" target="{targetImg}" 
            angleYFrom="0" angleYTo="360" 
            duration="3000"
            autoCenterTransform="true"
            repeatCount="2" repeatBehavior="reverse" 
            effectStart="playButton.enabled=false;"
            effectEnd="playButton.enabled=true;"/>
    </fx:Declarations>

    <s:Panel title="Rotate 3D Effect Example"
        width="75%" height="75%" >
        
        <s:HGroup 
            horizontalCenter="0"
            verticalCenter="0">
            <s:Image 
                source="@Embed(source='assets/Nokia_6630.png')"/>
            <s:Image id="targetImg" 
                source="@Embed(source='assets/Nokia_6630.png')"/>
            <s:Image  
                source="@Embed(source='assets/Nokia_6630.png')"/>
        </s:HGroup>

        <s:Button id="playButton"
            left="5" bottom="5"
            label="Rotate3D" 
            click="rotateEffect.play();"/>
    </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below:

Alternatively, you can set the transormX, transformY, and transformZ properties on the effect target to define the transform center. In the following example, you set the transform center of the image to the right edge, corresponding to the transormX property having a value of 100:
<?xml version="1.0"?>
<!-- behaviors\Spark3DRotateLayoutRightTransform.mxml -->
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Declarations>
        <s:Rotate3D id="rotateEffect" target="{targetImg}" 
            angleYFrom="0" angleYTo="360" 
            duration="3000"
            repeatCount="2" repeatBehavior="reverse" 
            effectStart="playButton.enabled=false;"
            effectEnd="playButton.enabled=true;"/>
    </fx:Declarations>

    <s:Panel title="Rotate 3D Effect Example"
        width="75%" height="75%" >
        
        <s:HGroup 
            horizontalCenter="0"
            verticalCenter="0">
            <s:Image 
                source="@Embed(source='assets/Nokia_6630.png')"/>
            <s:Image id="targetImg"
                transformX="100" 
                source="@Embed(source='assets/Nokia_6630.png')"/>
            <s:Image  
                source="@Embed(source='assets/Nokia_6630.png')"/>
        </s:HGroup>

        <s:Button id="playButton"
            left="5" bottom="5"
            label="Rotate3D" 
            click="rotateEffect.play();"/>
    </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below:

Component layout and 3D effects

Effects can modify the layout of the parent container of the effect target. For example, suppose the effect target is in a container that uses vertical layout. You then use the two-dimensional Rotate effect to rotate the target through 360°. As the effect plays, the parent container modifies the layout of its other children to accommodate the rotating child. Therefore, container children can change position during the effect.

Flex has the concept of layering of the children of a container. Children are drawn on the screen in the order in which they are defined in the container. If children overlap, the child defined later in the container appears on top because it is drawn last.

Flex provides a set of built-in layout classes, such as the VerticalLayout class, to control child layout in a container. These layout classes assume that all children are in the z = 0 plane. That means a container always lays out children in the two-dimensional x, y plane.

However, a 3D effect can modify the effect target in the x, y, and z dimensions. If your 3D effect uses the z dimension, the built-in layout classes do not consider it during layout. If you then allow the parent container to update its layout by taking only the x and y dimensions into consideration, your application might not appear correctly. Therefore, you typically disable the parent container from performing layout while the 3D effect plays.

All effects support the disableLayout property. When set to true, this property disables layout in the parent container of the effect target for the duration of the effect. The default value is false. For effects though, you typically do not want to disable layout of the parent container entirely.

All transform effects define the applyChangesPostLayout property which, by default, is set to true for the 3D effects. This setting lets the 3D effect modify the target component, but the parent container ignores the changes and does not update its layout while the effect plays. Changes to other container children still cause a layout update.

Note: For the 2D transform effects Move, Rotate, and Scale, the affectLayout property is true by default.

You can think of the 3D effects as not playing until after the container for the effect target has completed its layout. Because the effect plays post layout, the parent container does not modify its layout for changes to the target component caused by the effect.

In the following example, the application contains three images in an HGroup container. The Rotate3D effect then plays on the middle image to rotate it around the y-axis. Because the applyChangesPostLayout property is true by default, no layout occurs as the image rotates, and the target image overlaps the image on its left:

<?xml version="1.0"?>
<!-- behaviors\Spark3DRotateLayout.mxml -->
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Declarations>
        <s:Rotate3D id="rotateEffect" target="{targetImg}" 
            angleYFrom="0" angleYTo="360" 
            duration="3000"
            repeatCount="2" repeatBehavior="reverse" 
            effectStart="playButton.enabled=false;"
            effectEnd="playButton.enabled=true;"/>
    </fx:Declarations>

    <s:Panel title="Rotate 3D Effect Example"
        width="75%" height="75%" >
        
        <s:HGroup 
            horizontalCenter="0"
            verticalCenter="0">
            <s:Image 
                source="@Embed(source='assets/Nokia_6630.png')"/>
            <s:Image id="targetImg" 
                source="@Embed(source='assets/Nokia_6630.png')"/>
            <s:Image  
                source="@Embed(source='assets/Nokia_6630.png')"/>
        </s:HGroup>

        <s:Button id="playButton"
            left="5" bottom="5"
            label="Rotate3D" 
            click="rotateEffect.play();"/>
    </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below:

For example, set the transformX property to 100 on the effect target in the previous example to rotate the middle image so that it overlaps the image on the right. The image on the right appears on top of the middle image because it was drawn last.

You can override the default of disabling layout on the effect target by setting the applyChangesPostLayout property of the effect to false. In the following example, you rotate the image around the z-axis, with the applyChangesPostLayout property set to false. A 3D rotation around the z-axis is essentially a 2D rotation in the x and y plane. Because the applyChangesPostLayout property is false, the parent container updates the layout of the other two images as the effect plays:
<?xml version="1.0"?>
<!-- behaviors\Spark3DRotateWithLayout.mxml -->
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Declarations>
        <s:Rotate3D id="rotateEffect" target="{targetImg}" 
            angleZFrom="0" angleZTo="360" 
            applyChangesPostLayout="false" 
            duration="5000"
            repeatCount="2" repeatBehavior="reverse" 
            effectStart="playButton.enabled=false;"
            effectEnd="playButton.enabled=true;"/>
    </fx:Declarations>

    <s:Panel title="Rotate 3D Effect Example"
        width="75%" height="75%" >
        
        <s:HGroup 
            horizontalCenter="0"
            verticalCenter="0">
            <s:Image 
                source="@Embed(source='assets/Nokia_6630.png')"/>
            <s:Image id="targetImg" 
                source="@Embed(source='assets/Nokia_6630.png')"/>
            <s:Image  
                source="@Embed(source='assets/Nokia_6630.png')"/>
        </s:HGroup>

        <s:Button id="playButton"
            left="5" bottom="5"
            label="Rotate3D" 
            click="rotateEffect.play();"/>
    </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below:

Setting the postLayoutTransformOffsets property on a component

You can directly modify the position, rotation, and scale of a component post layout without using a 3D effect. Instead, use the postLayoutTransformOffsets property, of type mx.geom:TransformOffsets, of the UIComponent class. By setting the postLayoutTransformOffsets property directly, you modify the target without causing the parent container to update its layout.

In the following example, you use the postLayoutTransformOffsets property to modify the position and scale of a component. As you modify it, notice that the parent container does not update its layout:

<?xml version="1.0"?>
<!-- behaviors\Spark3DOffset.mxml -->
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:s="library://ns.adobe.com/flex/spark">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    
    <fx:Script>
        <![CDATA[
            import mx.geom.TransformOffsets;
            
            // Define an instance of TransformOffsets.
            private var myXForm:TransformOffsets = new TransformOffsets();
            
            // Initialize the postLayoutTransformOffsets property of the target.
            private function initOffsets():void {
                targetImg.postLayoutTransformOffsets = myXForm; 
            }
            
            // Move the target 20 pixels to the left and 
            // increase its x and y scale by 0.1.
            private function nudgeImageLeft():void {
                targetImg.postLayoutTransformOffsets.x = 
                    targetImg.postLayoutTransformOffsets.x - 20;
                targetImg.postLayoutTransformOffsets.scaleX = 
                    targetImg.postLayoutTransformOffsets.scaleX + 0.1;
                targetImg.postLayoutTransformOffsets.scaleY = 
                    targetImg.postLayoutTransformOffsets.scaleY + 0.1;
            }

            // Move the target 20 pixels to the right and 
            // decrease its x and y scale by 0.1.
            private function nudgeImageRight():void {
                targetImg.postLayoutTransformOffsets.x = 
                    targetImg.postLayoutTransformOffsets.x + 20;
                targetImg.postLayoutTransformOffsets.scaleX = 
                    targetImg.postLayoutTransformOffsets.scaleX - 0.1;
                targetImg.postLayoutTransformOffsets.scaleY = 
                    targetImg.postLayoutTransformOffsets.scaleY - 0.1;
            }

            // Reset the transform.
            private function resetImage():void {
                targetImg.postLayoutTransformOffsets.x = 0;
                targetImg.postLayoutTransformOffsets.scaleX = 1.0;
                targetImg.postLayoutTransformOffsets.scaleY = 1.0;
            }
        ]]>
    </fx:Script>

    <s:Panel title="Offset Example"
        width="75%" height="75%" >
        
        <s:HGroup 
            horizontalCenter="0"
            verticalCenter="0">
            <s:Image 
                source="@Embed(source='assets/Nokia_6630.png')"/>
            <s:Image id="targetImg" 
                source="@Embed(source='assets/Nokia_6630.png')"
                creationComplete="initOffsets();"/>
            <s:Image  
                source="@Embed(source='assets/Nokia_6630.png')"/>
        </s:HGroup>

        <s:HGroup left="5" bottom="5">
            <s:Button id="nudgeLeftButton"
                label="Nudge Left" 
                click="nudgeImageLeft();"/>
             <s:Button id="nudgeRightButton"
                label="Nudge Right" 
                click="nudgeImageRight();"/>
             <s:Button id="resetButton"
                label="Reset" 
                click="resetImage();"/>
        </s:HGroup>
    </s:Panel>  
</s:Application>

The executing SWF file for the previous example is shown below:

Notice in this example that as you nudge the image to the left, it overlaps the image to its left. As you nudge the image to the right, it moves behind the image on the right. This overlap is because the image on the right is defined later in the container, and is therefore drawn last on the screen.

Setting the center of the projection

The 3D effects work by mapping a three-dimensional image onto a two-dimensional representation for display on a computer screen. The projection point defines the center of the field of view, and controls how the target is projected from three dimensions onto the screen.

By default, when you apply a 3D effect, the effect automatically sets the projection point to the center of the target. You can set the autoCenterProjection property of the effect to false to disable this default. You then use the projectionX and projectionY properties to explicitly set the projection point. These properties specify the offset of the projection point from the (0, 0) coordinate of the target.