How to use FSMorphBitmapFill?

Questions on how to use Transform SWF.

How to use FSMorphBitmapFill?

Postby soner » Wed May 23, 2007 3:36 pm

Hello,

The main aim of my program is to generate 3D look faces. I have partly managed this aim. Here is an example.
http://www.yuzmodeli.com/tr/face/face.jsp?id=1

The algorithm I have employed is simple. I cut the previously generated texture image in to triangles. Then these triangles are transformed to create the 3D look of a face. I have generated 3D faces from different view points, so I make a rotation animation.

My new aim is to make smooth transitions between these 3D key frames. so I started to work on the FSDefineMorphShape objects.

I am able to move triangles but their FSMorphBitmapFill does not move with them. I have constructed FSMorphBitmapFill like this.

new FSMorphBitmapFill(FSFillStyle.Clipped, imageId, initialTransform, finalTransform)

I was expecting that image of FSMorphBitmapFill will be transformed from initialTransform to finalTransform while frames progress. But while the triangles move, the FSMorphBitmapFill stand still.

I am sure I missed something but can not find. So can you give me an working example code that FSMorphBitmapFill is transformed?

Regards,

Soner
soner
 
Posts: 5
Joined: Wed May 16, 2007 8:34 am

I still can not find the solution

Postby soner » Tue May 29, 2007 11:35 am

I am still working on it but I can not find any working FSMorphBitmapFill example. Can you just give me a working example?
soner
 
Posts: 5
Joined: Wed May 16, 2007 8:34 am

Postby smackay » Tue May 29, 2007 3:33 pm

Soner,

I am very sorry for the delay in replying to you. Here is a example on how to use FSMorphBitmapFill to change the shape that is used to display an image. The example is very primitive but it works and has the added advantage that it is easy to play with so you can see how all the steps were put together:

Code: Select all
import java.util.ArrayList;

import com.flagstone.transform.*;
import com.flagstone.transform.util.*;

public class MorphImage
{
    private FSMovie movie = new FSMovie();

    public static void main(String[] args)
    {
        new MorphImage(args);
    }

    public MorphImage(String[] args)
    {
        try {
            createMovie();
            movie.encodeToFile("morph_image.swf");
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void createMovie() throws Exception
    {
       FSImageConstructor imageGenerator = new FSImageConstructor("a.jpg");

        int imageId = movie.newIdentifier();

        FSDefineObject image = imageGenerator.defineImage(imageId);

        movie.setFrameRate(1.0f);
        movie.setFrameSize(new FSBounds(0, 0, 2000, 2000));
        movie.add(new FSSetBackgroundColor(FSColorTable.lightblue()));
        movie.add(image);

        ArrayList fillStyles = new ArrayList();
        ArrayList lineStyles = new ArrayList();

        // The image is scaled by x20 so it is displayed at its original size.
        // You can change the oordinate transforms to produce a variety
        // of different effects.

        fillStyles.add(new FSMorphBitmapFill(FSFillStyle.Clipped, imageId, new FSCoordTransform(0,0, 20, 20),  new FSCoordTransform(0, 0, 20, 20)));
        lineStyles.add(new FSMorphSolidLine(10, 10, FSColorTable.black(), FSColorTable.red()));

        // Define the shape used to display the image at the start of the
        // morphing process.

        FSShape rectangle = new FSShape();

        rectangle.add(new FSShapeStyle(1, 1, 0, 0, 0));
        rectangle.add(new FSLine(2000,0));
        rectangle.add(new FSLine(0,1000));
        rectangle.add(new FSLine(-2000,0));
        rectangle.add(new FSLine(0,-1000));

        FSBounds rectangleBounds = new FSBounds(0, 0, 2000, 1000);

        // Define the shape used to display the image at the end of the
        // morphing process.

        FSShape square = new FSShape();
        square.add(new FSLine(1500,0));
        square.add(new FSLine(0,1500));
        square.add(new FSLine(-1500,0));
        square.add(new FSLine(0,-1500));

        FSBounds squareBounds = new FSBounds(0, 0, 1500, 1500);

        FSDefineMorphShape shape = new FSDefineMorphShape(movie.newIdentifier(), rectangleBounds, squareBounds, fillStyles, lineStyles, rectangle, square);

        movie.add(shape);

        movie.add(new FSPlaceObject2(shape.getIdentifier(), 1 , 0, 0));
        movie.add(new FSShowFrame());

        // now morph the image in a series of 8 steps. The second
        // argument in the FSPlaceObject2 constructor describe the
        // state of the morphing process and ranges from 0.0 (unmorphed)
        // to 1.0 (morphed into the final shape)

        for (int i=0; i<8; i++)
        {
            movie.add(new FSPlaceObject2(1, i*0.125f, 0, 0));
            movie.add(new FSShowFrame());
        }
     }
}


Play around with the code so you can see the steps involved. If you have any questions please let me know.

Regards and sorry for the delay,

Stuart
--
Stuart MacKay
Flagstone Software Ltd.
smackay
Site Admin
 
Posts: 594
Joined: Sat Sep 03, 2005 9:04 am

But Fill Image still does not move...

Postby soner » Thu May 31, 2007 3:30 pm

Hello smackay,

Thank you very much for your example. I have changed it a little bit in the way that I have to use it. Here is the code that you send me and I can not manage my aim.

The problem is here.
Code: Select all
        // I think the problem is here. endTransform which is the second transform of FSMorphBitmapFill constructor has no effect on result.
        // You can try the code with FSMorphBitmapFill(FSFillStyle.Clipped, imageId, startTransform, new FSCoordTransform()) and nothing changes.
        fillStyles.add(new FSMorphBitmapFill(FSFillStyle.Clipped, imageId, startTransform, endTransform));


In this code piece, MorphBitmapFill image should morph from startTransform, to endTransform which is not the case. Is this a bug or I misunderstand the API that says;

endTransform : An optional FSCoordTransform object that will be applied to the image, to change its origin, orientation, etc., at the end of the morphing process


COMPLETE CODE
Code: Select all
import java.io.*;
import java.util.*;

import com.flagstone.transform.*;

public class MorphImage
{
    private FSMovie movie = new FSMovie();

    public static void main(String[] args)
    {
        new MorphImage(args);
    }

    public MorphImage(String[] args)
    {
        try {
            createMovie();
            movie.encodeToFile("object.swf");
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void createMovie() throws Exception
    {
        int imageWidth = 256 * 20;
        int imageHeight = 256 * 20;
        int frameCount = 40;
        FSBounds bounds = new FSBounds( -imageWidth / 2, -imageHeight / 2, imageWidth / 2, imageHeight / 2);
        System.out.println("bounds : " + bounds);

        movie.setFrameRate(10.0f);
        movie.setFrameSize(bounds);
        movie.add(new FSSetBackgroundColor(FSColorTable.white()));
        movie.add(new FSJPEGEncodingTable());
        ArrayList lineStyles = new ArrayList();
        lineStyles.add(new FSMorphSolidLine(0, 0, FSColorTable.blue(), FSColorTable.blue()));
        int imageId = movie.newIdentifier();
        FSDefineJPEGImage image = new FSDefineJPEGImage(imageId, readFile(new File("image.jpg")));
        movie.add(image);
        // The start transform that I have to make to see the full size image.
        FSCoordTransform startTransform = new FSCoordTransform( -imageWidth / 2, -imageHeight / 2, 20.0, 20.0);
        // This is the end transform that I want to apply to the morph bitmap fill image. It is a clockwise 90 degree rotation. I make a composite transform that I think it should be. No need to think about this now.
        FSCoordTransform endTransform = new FSCoordTransform();
        endTransform.rotate(90.0);
        endTransform.composite(startTransform);
        ArrayList fillStyles = new ArrayList();
        // I think the problem is here. endTransform which is the second transform of FSMorphBitmapFill constructor has no effect on result.
        // You can try the code with FSMorphBitmapFill(FSFillStyle.Clipped, imageId, startTransform, new FSCoordTransform()) and nothing changes.
        fillStyles.add(new FSMorphBitmapFill(FSFillStyle.Clipped, imageId, startTransform, endTransform));

        // Initial rectangle
        ArrayList initialRectangle = new ArrayList();
        initialRectangle.add(new FSShapeStyle(1, 1, 0, -imageWidth / 2, -imageHeight / 2));
        initialRectangle.add(new FSLine(imageWidth, 0));
        initialRectangle.add(new FSLine(0, imageHeight));
        initialRectangle.add(new FSLine(-imageWidth, 0));
        initialRectangle.add(new FSLine(0, -imageHeight));

        // Clockwise 90 degree rotated rectangle
        ArrayList morphedRectangle = new ArrayList();
        morphedRectangle.add(new FSShapeStyle(1, 1, 0, imageWidth / 2, -imageHeight / 2));
        morphedRectangle.add(new FSLine(0, imageHeight));
        morphedRectangle.add(new FSLine(-imageWidth, 0));
        morphedRectangle.add(new FSLine(0, -imageHeight));
        morphedRectangle.add(new FSLine(imageWidth, 0));

        int shapeId = movie.newIdentifier();
        movie.add(new FSDefineMorphShape(shapeId, bounds, bounds, fillStyles, lineStyles, new FSShape(initialRectangle), new FSShape(morphedRectangle)));
        movie.add(new FSPlaceObject2(shapeId, 1, 0.0f, 0, 0));

        movie.add(new FSShowFrame());
        float ratioStep = 2.0f / (frameCount - 1);
        for(float ratio = ratioStep; ratio <= 1.0f; ratio += ratioStep){
            movie.add(new FSPlaceObject2(1, ratio, 0, 0));
            movie.add(new FSShowFrame());
        }
        for(float ratio = 1.0f; ratio >= 0.0f; ratio -= ratioStep){
            movie.add(new FSPlaceObject2(1, ratio, 0, 0));
            movie.add(new FSShowFrame());
        }
    }

    private byte[] readFile(File file) throws FileNotFoundException, IOException{
        FileInputStream inputStream = null;
        byte[] bytes = new byte[(int)file.length()];
        inputStream = new FileInputStream(file);
        inputStream.read(bytes);
        inputStream.close();
        return bytes;
    }
}
[/code]
Last edited by soner on Fri Jun 01, 2007 9:37 am, edited 1 time in total.
soner
 
Posts: 5
Joined: Wed May 16, 2007 8:34 am

I have forgotten to attach the SWF file. Here it is.

Postby soner » Thu May 31, 2007 3:34 pm

I have forgotten to attach the SWF file. Here it is.
Attachments
object.swf
The image should rotate with rotating window.
(19.95 KiB) Downloaded 287 times
soner
 
Posts: 5
Joined: Wed May 16, 2007 8:34 am

Postby smackay » Fri Jun 01, 2007 9:40 am

Soner,

Yes you are using the API correctly however I think the MorphBitmapFill is not working as you (or I) expected.

I modified your example so that the coordinate transform is applied to the entire shape on the display list rather than using morphing:

Code: Select all
        for(float ratio = ratioStep; ratio <= 1.0f; ratio += ratioStep){
           FSCoordTransform tx = new FSCoordTransform(0, 0);
           tx.rotate(ratio*360.0f);
            movie.add(new FSPlaceObject2(1, ratio, tx));
            movie.add(new FSShowFrame());
        }
        for(float ratio = 1.0f; ratio >= 0.0f; ratio -= ratioStep){
           FSCoordTransform tx = new FSCoordTransform(0, 0);
           tx.rotate(ratio*360.0f);
            movie.add(new FSPlaceObject2(1, ratio, tx));
            movie.add(new FSShowFrame());
        }


This, I think, gives the effect you are looking for. You should try simply rotating the photo and remove the code that creates the morphing bitmap to see if the simple transforms applied above still give the effect you are looking for.

Regards,

Stuart
smackay
Site Admin
 
Posts: 594
Joined: Sat Sep 03, 2005 9:04 am

Postby soner » Fri Jun 01, 2007 2:07 pm

Hi Stuart,

This is a good work around. I have allready used a very similar way to generate a 3D face model rotation animation. It is working good but the size of SWF file becomes the problem. This is because of my algorithm to generate 3D object.

Here is an example SWF file. This SWF file is composed of 11 frames and have a 255 Kb size. It uses a 512x512 texture JPG image of size 45 Kb the rest is 3D data. In my algorithm, I use this image as fill for all triangles that generates the human face as a whole. To do this, for each frame, I calculate final position of each triangle and add it. I use more than 1000 triangle is added for each frame, so the result SWF file has 12000 added objects that causes 255 Kb - 45 Kb = 210 Kb data.

My ultimate aim is to make happy, angry and some other face animations that is about 400 frames. With this grow rate my SWF files will be more than 7 Mb that is unacceptable.

On the other hand morph syntax is very simple and compact. I only define start and end positions of each triangle once and fill between with morph objects. Hence the size of SWF file will be nearly independent of frame size that is what I need. So the MorphBitmapFill is a must for me.

Please try to find that MorphBitmapFill has a bug or not? If so I will be glad to be involved in debugging process. If not please say me the correct usage of MorphBitmapFill object.

Thanks for your helps.

Regards

Soner
Attachments
object.swf
3D Face Model Rotation Animation
(254.08 KiB) Downloaded 254 times
soner
 
Posts: 5
Joined: Wed May 16, 2007 8:34 am

Postby smackay » Fri Jun 01, 2007 3:13 pm

Soner,

OK, Now I understand the problem. I tried various different ways of generating the morph shape to see if it was a coding problem. In each case I cannot get the end coordinate transform to be applied to the image.

So instead I tried using MorphSolidFill to check that I was constructing the morphing shape correctly. This works as expected.

I suspect that the reason the transforms are not applied to the bitmap is because the Flash Player does not work that way. I will still try to see if I can get it to work but I think you might have to try something else.

Stuart
smackay
Site Admin
 
Posts: 594
Joined: Sat Sep 03, 2005 9:04 am


Return to Using Transform

Who is online

Users browsing this forum: No registered users and 1 guest

cron