020 7920 7120 | public@publicreative.com

April 30th, 2009

Inside the Classic

It’s been a while between posts for me. Mainly because I have been heavily involved in creating the Remaster the Classic project for the last month or so.

The site was made for K-Swiss and MTV to promote the K-Swiss Classic Remastered trainer. Users have the opportunity to customise their Classic by expressing their creativity using paint, graphics and uploading images not to mention adding chains, diamonds and/or studs to their shoe.

Designs are applied to the shoe (a Collada model rendered with Papervision, created in Maya) in real time. Users can continue to edit the shoe until they are happy with it and then submit the shoe to the competition and gallery when both the texture and a thumbnail of the designed shoe are saved.

There were many challenges and many (very) late nights but well worth it as the end result has proven to be extremely popular. Below is a high level overview of the site in relation to the functionality of the Shoe.


Creating the model and applying materials.

The shoe model and the additions you can add to it (the chains and the studs) were created in Maya and exported as Collada files using the Collada plugin. The chains and studs are separate Collada files with individual textures that are mapped to each of them. These are added as children to the main shoe DAE.

Most people reading this will probably be aware that when you export a Collada file from Maya (or Max) that you want to use with Papervision you need a Collada (.dae) file and the texture/material image that has been mapped to that model.

The trick is getting this material image to map correctly to the model in Papervision. To do this you need to know where to look.

With a Collada file exported from Maya I found you need to search the Collada file for the triangles node.

Here it is in our Collada file.

triangles material="a_Backed_Shoe2SG" count="1958"

You need the name of the material, in our case “a_Backed_Shoe2SG”.

Then when you are creating the MaterialsList to use with the DAE in Papervision you pass it this name.

// create a BitmapMaterial instance using the BitmapData from the loaded texture image.
_shoeMaterial = new BitmapMaterial(_loader.getBitmapData(_shoeTexture));
// create a new materials list. Pass it the bitmap material and give it the name we found in the Collada file from the triangles node.		 
_materialsList = new MaterialsList(); _materialsList.addMaterial( _shoeMaterial , "a_Backed_Shoe2SG");
// the shoeDae is an instance of a DAE class and is passed the loaded DAE file in binary form and the materials list we created above.
_shoeDae.load(_loader.getBinary("shoe_model") ,_materialsList);
 
// the DAE is then added to the Papervision scene
scene.addChild(_shoeDae);

NB: _loader is an instance of the Bulk Loader class. You can check out this library here.

Swapping textures at runtime.

To swap the material at runtime which obviously happens often I made a setter function on the Shoe class.

public function set material( material:BitmapData):void {
        // if the shoe material exists, dispose of the bitmap
	if (_shoeMaterial) _shoeMaterial.bitmap.dispose();
	// make a new bitmap material
	_shoeMaterial = new BitmapMaterial( material );
	// replace the material using the name that we found in the Collada  file above
	_shoeDae.replaceMaterialByName( _shoeMaterial , "a_Backed_Shoe2SG);
}

One of the trickiest challenges was turning the area of the shoe the user was editing into the BitmapData to pass to this function and use as the new material for the shoe.

In brief the recipe for this was:
1. Grab a copy of the current shoe material with everything the user has already created on it. This is a 1600×1600 Bitmap.
2. Create a holder sprite to build the new image in. Add this current shoe material as the bottom layer.
3. Grab a copy of the original material, a clean canvas with nothing on it.
4. Mask the original material with the exact shape of the area the user is editing. This mask needs to be rotated, scaled and translated to the correct position on the original material. Layer this on top of the current shoe material.
5. So now the resulting image should show everything the user has added to the rest of the texture but the current area they are editing will be clear.
6. Grab the BitmapData from the area of the shoe the user is currently editing with all the graphics etc the user has added.
7. Again mask this so that graphics that go outside the editable area are not going to be included on the final image.
8. Layer this on top, rotating, scaling and translating as necessary with a Multiply blend mode so the stitching comes through from the original texture.
9. BitmapData.draw the resulting holder sprite with these layers on it and pass to the material function above to swap out the material.

Everything is easier to understand in pictures so here it is:

Here is the original shoe material:

And here it is an example of what it looks like once edited:

Preformance and Rendering

Other things to consider were balancing performance with quality. We tried to keep the polygons on the shoe model as low as possible before it really became noticeable and keep the quality of the material image high.

When both the chains and the studs are added, as these are additional models the polygon count goes up considerably so we really tried hard to keep this as low as possible. When flash is asked to render anything over 3000 triangles, it really starts to show.

Additional to that we had problems with Z-Sorting due to the many overlapping parts of the shoe, especially around the laces. To solve this we needed to employ the services of the QuadrantRenderEngine with the Z sorting filter. However, as there are more calculations with every render, this slowed things down even more.

To use this advanced render engine, and keep the polygon count high while not affecting performance we made it so instead of constantly rendering, the Papervision scene was only updated when needed, i.e. when rotated or the texture has been changed.

Saving the entries.

A major part of this campaign is the competition. Every shoe designed and submitted needs to be saved for the gallery and judging.

To do this there are two main things that are needed. The main texture of the shoe, the 1600×1600 jpg that holds the users design and the small thumbnail of the shoe with the design in place for use in the gallery.

The main texture of the shoe is always present in the current BitmapMaterial of the shoe. We just get it out using the BitmapMaterial.bitmap property.

Capturing the thumbnail is a little more involved. First we needed to rotate the shoe to the correct position so that all thumbnails are in the same position. Then we do a BitmapData.draw of the viewport after doing a bit of Matrix scaling and translating.

So we now have the two BitmapData objects for the two images, we just need to save them to the server along with the rest of the users entry details. To save the images we encode the images with Adobes JPGEncoder class (for the big texture) and the PNGEncoder (for the thumbnail). These are both available in the corelib.

Next we encode the resulting ByteArrays with the Base64 encoder. You can grab this from Dynamic Flash.

Code for saving the main image.

// the bitmap data for the current shoe material
var imageBd:BitmapData = Shoe2.getInstance().shoeMaterial.bitmap; imageBd = Shoe2.getInstance().shoeMaterial.bitmap;
// the jpg encoder and the resulting ByteArray
var j:JPGEncoder = new JPGEncoder(50); 
var bytes:ByteArray = j.encode( imageBd); bytes.position = 0; 
// Encoding to Base64 and saving as part of the entry data object.
entryData.texture_image = Base64.encodeByteArray(bytes);

The whole package containing the users entry data along with the Base64 encoded images are sent to our custom PHP backend in one tidy package via AMFPHP.

The obvious final step is PHP decoding the base64 images and saving them to disk storing the resultant URL with the rest of the entry data.

Summary.

As I warned at the start of this post, the above is only a very brief overview of how things were done. There was so much more to this than just the shoe but obviously this was the focus and main technical challenge of the site. Any feedback, questions or requests for further detail are obviously welcomed.

2 Responses to “Inside the Classic”

  1. Mark says:

    Not sure if I understand, but I think what you need to do is be able to access the bitmapdata of the original texture. Once you have done this you need to combine the original texture with the new layer with the text on it. To do this you can create a ‘holder’ sprite, add the original layer then add the text layer (with multiply blend mode so the original layer can still be seen). Then use bitmapdata.draw() to create a new bitmap you can use as the material.

  2. mimo says:

    These are the answers what i am searching for, they’re very great!!
    i am doing the similar things, however, the last step is too difficult for me because i am not familiar with pHp.
    i can load dae into flash and change its’ material. What i am trying to do is to input some text on a given texture which is displayed in the flash, and the texture with texts can be loaded into the bitmapdata and map to the dae model. But how can i extract the texture with texts and change to bitmapdata and then map to the model?

Tell us what you think!