Category Archives: 3D Student

The Future of 3D: Mixing CGI with Auditory Illusions?

3D technology has become more common in the entertainment industry. Movies and television shows are produced in 3D, with the audience being given special glasses to view the effects. Developers have even found a way to create 3D effects in sound, creating a realistic experience for the listener. With the two advancement of the two technologies, it is conceivable that movies, television, games, or videos could be created with both 3D visual and sound effects, creating a total 3D experience that replicates a realistic experience as closely as technology will allow. Here’s how it works:

Auditory Illusions

Advances have been made in creating so-called “auditory illusions” in which sound appears to be coming from different locations independent of the speakers. One such example includes the “virtual barber shop” from Q Sound Labs:

The technology produces a sound that imitates real actions. As the barber in this clip moves to cut hair at different spots around the head, the sound moves in those directions. If the barber is meant to be at your right ear, you hear the scissors clipping by your right ear. The technology can also be used to create the illusion of sound in different spaces, such as a large room, a hallway, or a cave.

Possibilities for the Future

The technology exists for 3D visual effects and auditory illusions, but the two have rarely been combined on the big screen. While surround sound has been able to replicate the “3D” experience to some extent, it hasn’t been as effective as the technology seen in the type of auditory illusions created in the “virtual barber shop.” It’s possible that future movie-going experiences could include the use of 3D glasses for the visual effects and personal headphones for the sound effects.

Limitations

Of course, creating personal sound ports for individual movie goers has practical and cost limitations. Doing so would require re-outfitting most movie theaters, or giving audience members personal, portable sound devices, such as a small radio on a limited frequency. The technology also has limits for personal viewing. While individuals could watch programming on a laptop and use personal headphones for the sound effects, the same experience could not be replicated by watching on a television set, which would include a larger picture for a more enjoyable viewing experience. As 3D technology grows and is embraced by larger audiences, the technology to view and enjoy will have to change with it.

Already, 3D technology is growing for movie-goers, with more 3D screens available and up to 40 percent of ticket sales coming from 3D films this year. Breakout films like Avatar have shown the possibilities for 3D visual technology and audience demand for the technology when it is done well. Combining this type of innovation in visual technology with innovation in sound technology can create a unique movie experience that could change the way films and television are created.

Alpha Mapping to Create Realistic Leaves

Alpha mapping is a technique in 3D computer graphics where an image is mapped (assigned) to a 3D object, and designates certain areas of the object to be transparent or translucent. The transparency can vary in strength, based on the image texture, which can be greyscale, or the alpha channel of an RGBA image texture.

1-Hello everyone, in this lesson we will talk about alpha maps, alpha maps are really important cause they are helpfull to create very detailed or photo realistic result in 3d from leaves for a plant or tree to character’s hair for video games.

So basically there is one rule that says  : White is visible – Black is invisible (transparent).

We will start with a leave image in photoshop to understand an Alpha map, simply search google to find any of your choice:

2 – Lets press F7 on keyboard  to open up layers window and double click on our image (name background) and press Ok; this will convert that to a layer.

3- Select magic wand tool and change the tolerance to 25, click on white area and press Delete key on your keyboard. Select magic wand tool again and click out of the screen to deselect that area.

4- So now we have a transparent leaf image in photoshop, its time to make the background green, so if any pixel fails in our alpha map, that will have the same color of our leaf and its not going to be noticable . Create a new layer, select eye dropper tool, click anywhere off leaf, then select paint bucket tool and fill that layer by clicking in our image. Don’t forget to drag our green layer under the leaf layer.

5- Select move tool, Press control-T on your keyboard and rotate the leaf a bit to get a better direction. When you are done, press enter on your keyboard.

6- Press filter menu and click in sharpen—> sharpen mask and change the values as follows, this will help us to made our leaf image sharper and better in quality to prevent blur (you can change the values as its based on your image, so play with the percentages).

7- Now its time to save our image as a jpg file. A quality of 10 would have a balance of quality and file size. Also save a PSD file just in case you want to edit something later.

8- Select the green background, select a black color and fill the background layer using paint bucket tool.

9- Select the leaf layer, click on FX icon and click color overlay.

10- Select a pure white color and click OK .

11- Now save this image as our alpha-map, also click on image—>image size and remember to write the size of our image in pixels.

12- Open your 3d software, in our case its 3ds max, and create a plane the same size as your image size. Dont worry if it looks too big, you can always scale it down.

13- Now press M to open material editor, select a material, add the leaf image we created in photoshop as diffuse and add the alpha image as opacity. Also check two sided box.

14- Make sure the plane is selected then press “assign material to selection” and “show standard map in viewport”.

15. Now we simply finished to get a working alpha map in our 3ds max software. By adding more segments to our plan and moving them around or adding a bend modifier, we can create a good result that we can use on our models.

I hope you enjoyed using this method, please dont hesitate to ask if you have any other questions.  Don’t forget to check out the other tutorials in our Texturing section, and if you’d like more information on this technique have a look at our older alpha map tutorial.

Happy alpha mapping!

Recommended Deliberate Practice for VFX Artists

If you haven’t already, go and read the first part of this mini-series on Deliberate Practice and Continuous Learning.

Deliberate Practice for VFX Artists

Over the past week I’ve been looking at job openings for VFX artists, mainly in America, Canada, and the UK but I wasn’t very location picky. Here are the assumptions I’ve made based on the criteria they claim to desire.

They tend to split into two broad categories; Software and Techniques, and Personal traits. Because both categories seem to be integral I’m going to cover each in turn.

Software and Techniques Wish List

For any of these subjects deliberate practice is easy to define (relatively). You can start out on each topic by picking up a good textbook or course and once you know enough of the basics you can set up a plan to practice those daily while you experiment with new things on the other side. There are hundreds of tutorials for each (or at least a few) and plenty of resources available.

Because its less of a challenge to figure out how to get started I’m going to keep this part fairly simple. Here’s a list of techniques and pieces of software that came up during my research.

Software:

  • Maya
  • 3D Studio Max
  • After Effects
  • Nuke
  • Photoshop
  • Python (scripting)
  • Unreal Engine (mostly with games)
  • Shake
  • Cascade
  • Mental Ray
  • Houdini
  • Mel (more scripting)

Techniques:

  • Particle Effects
  • Composite Layers
  • Rendering Optimisation
  • Light Rigs
  • Roto Mattes
  • Blue/Green Screening
  • 2D Painting Skills for Mark-ups
  • Compositing
  • Integrating live action with miniatures or CGI
  • Use textures and 3D meshes in effects
  • Performance and Resource Management (games again)
  • Fluid Dynamic Particle Effects
  • Graphic Shaders
  • Procedural Modelling
  • Real Time Particle Systems
  • Scripting
  • Stylized lighting and Mood Lighting
  • Traditional Art Skills
  • Photography
  • Digital Image Manipulation
  • Stereoscopic 3D

Quite a list! I’m going to go through most of the techniques on this blog in the next few years, and probably some of the different pieces of software.

Traits of a Perfect Employee

These are, in general, much harder to practice and develop. Personally, I think this is because defining them is tricky; how do you cultivate being proactive, for example?

Hand on heart, I don’t know if any of this will actually work. Yet. I’ve only tried out deliberate practice on a couple of them and even on those I’ve tried the progress is slow (though noticeable). I’ll list my translation of the traits I found (you’re welcome!) and then I’ll go into depth on one for an example. If you’ve been practicing already, or you’re really good at some of these, drop me a comment and let me know how it went for you.

  • Understanding of Light, Colour and Composition
  • Demonstrate you’re a team player and can get along with multiple disciplines and backgrounds (I’d recommend building connections for this part)
  • Be able to talk about different types of art, your preferences, and why you like one style vs. another
  • Build change into your workflow and try not to flip out when things change last minute
  • Show you’ve improved your skills over time (*cough*Continuous Learning*cough*)
  • Be proactive and take initiative
  • Take direction from peers and supervisors with grace
  • Keep to schedule and deadlines
  • Create quality work
  • Perform well under high stress (or, presumably, manage the stress so that it never reaches ‘high’)
  • Communicate well within the team
  • Problem Solving
  • Spend time consuming projects from your industry (Different types of games for games, TV programs for television, etc)

Keep to Schedule and Deadlines (my example)

Anyone that knows me, knows I struggle with this one. Not because of bad time-keeping but because I have this habit of taking on far more than I can achieve within a specified time frame.

In fact, and I’m not proud of this, I don’t think I finished a single practical project in my degree year. Fortunately my ideas and paperwork were good enough that I passed anyway – that didn’t make it feel much better to me. After a month or so of not doing anything at all (ok, maybe two months) when the course finished I finally dusted myself off and decided to do something about that.

I found a project management solution that allowed me to time myself doing tasks, create milestones, multiple projects, and anything else I needed. I also went through the Personal Effectiveness Program book; some chapters were more helpful than others but I’d recommend giving it a read and following through as much as possible.

Armed with those tools I set up projects, learned quickly that everything creative was taking longer than I’d estimated and a lot of the other tasks were taking far less time to complete. The next time I scheduled a task similar to one I’d completed, I looked at the difference between estimated time and actual time and adjusted it accordingly.

I learned that I wasn’t nearly as productive as I’d thought initially and scaled back on the work I scheduled for each day, prioritising the tasks as I went.

This was my form of continuous improvement; I’m still not very good at it but I’m more accurate than I was and I’ve gone from 1-2 hours of solid ‘real’ work a day to 2-3 (sometimes more) on average. Since I can see just how ambitious every idea I come up with is now I can allocate enough time to work on them (one of the benefits of setting your own deadlines for your own ideas) and the failing to learn process is much simpler.

To summarize the steps in a general way, here’s what I did:

  • Identified a problem in my skill set
  • Set up a method to track why there was a problem
  • Using the information gathered from tracking, determine what my ‘basics’ were (For this example those were estimating accurately, allocating work coherently, and paring back non-essential tasks)
  • Practice those basics every day and track improvements

Once I reach a point where I can successfully take a project from start to finish without extending the deadline then I can start to be more adventurous in how I practice. Yes I’m aware that sounds terrible (this would be a good time to point out that I can work on other people’s projects to schedule easily enough).

Your Next Steps

Have a look at that huge list and decide which part is most relevant to you. Then comment below saying which one it is, and I’ll respond with how I would start to work on it were I in your shoes.

That way, we can start together. Get the ball rolling with your comment just now (I dare you).

Continuous Learning and Deliberate Practice for VFX Artists

Why should I care about Continuous Learning?

Continuous learning is one of those things we hear a lot while we’re in school or college, usually within the first week of the year and as some magical thing that will help us throughout our lives.

Unfortunately, that’s usually all that’s said on the subject. If you’re lucky you get a bit more about why you should be doing it, or even a couple of pointers for things to practice that will be ‘useful in the industry’.

Continuous learning or Deliberate Practice, however, is one of the most important skills you can cultivate. Not just in this industry (though my research over the past week suggests that its a desirable trait), but in life in general.

It allows you to take skills you’ve learned, multiply them (over time) and if followed through it can make you a true expert in your areas of interest. I could go on, but I learned most of what I know from these folks;

 Let’s Define Deliberate Practice

For the purposes of this post I’m going to define deliberate practice as follows;

“The continual act of regularly taking a skill you have and practicing both the basics and pushing your understanding.”

  • Continual = you don’t stop.
  • Regular = Daily, Weekly, Fortnightly (I wouldn’t recommend monthly, but it could happen).
  • Skill = Measurable activity or set of actions. Think modelling with low polys, texturing to a certain resolution, and so on.
  • The basics = The very foundation of your skill. What you’re taught first when approaching the topic – the basic tenants of your craft.
  • Pushing your understanding = Going further than you ever have before. Possibly even than anyone has gone (I’m resisting a star trek quote here, but you get the idea).

It’s hard work, on a regular basis, over a long period of time. This isn’t a magical bullet solution (and because of that I fully expect most of you to ignore this!), you won’t become amazing over night and it’ll be more boring than anyone really wants to think too closely about.

Your friends, family and significant other won’t get it. Guaranteed.

It will give you both increased skill in your ‘area of expertise’ (for want of a better phrase) and a framework which you can use to learn just about anything with a little creativity.

In the visual effects industry in particular it’s vital; technology and techniques move far too quickly to approach learning them with anything less than a creatively made, flexible, framework. Our bread and butter as 3D artists changes every year or so (looking at Autodesk here) and we have to get used to software features appearing and disappearing all the time. Going beyond that, technological advances mean new techniques, new pieces of hardware, new software, and new requirements at our heart.

Assuming 2012 doesn’t herald the end of all we know, here’s how I’d recommend approaching these challenges for a visual effects artist. At least to begin with – you’ll come up with your own ideas and tailor it to your own plans eventually.

First, Make Time For It

Finding time is the first major hurdle when you approach anything outside of your normal routine. It’s not like we have time where we’re doing literally nothing – every single one of us can effectively fill our 24 hours a day.

Working on the assumption that no one can alter time or be in more than one place at once, we’re going to have to make sacrifices to fit all this in. I’d recommend an hour a day as being fairly manageable though you’ll know how much time you can spare. I’m not about to guilt you or point fingers at some of the things we fill our time with, but here are some points to keep in mind:

  1. It’s been mentioned multiple times that it takes 10,000 hours of continuous practice to become an expert.
  2. Focusing is not easy. After a bunch of practice and really watching where my time goes I’ve discovered that I can pay attention and work hard for approximately 2-3 hours a day. (Note: I work longer than that, but never very effectively)
  3. Exercise can usually roust you from sleepy inactivity, especially after work. I recommend dancing.

Next Time on ‘Deliberate Practice for VFX Artists’

Yes, it’s a bit of a tease but my ultra long post just wasn’t focused enough to cut the mustard (though why anyone would want to, I’ve no idea).

This will continue tomorrow with specific techniques and traits that my research into job postings has uncovered and how to use Deliberate Practice to improve your own skills. As well as a fascinating example from yours truly. Well, ‘somethin-ating’ anyway.

In the mean time, your next step is to make some room. You know where. Commit to some deliberate practice, mark out a time on your calendar daily (I like google calendar for this), and prepare yourself.

Also, comment and let me know what you’re taking time from to do this instead.

 

Ambient Occlusion Combined with Toon Shader Tutorial

(Editors note: Hey folks, this is the last post we’ll be seeing on here until January sometime – I’m entering a heavy development phase and I can’t maintain this as well. I will be back though, promise. For now, over to Prantic)

Hey there back with another Maya rendering tutorial and this time its on Render Composites of Maya’s Mental Ray Ambient Occlusion Texture and ToonShader.
With the combination of these two shader networks we can create a very cool composite that can be used for any CG stylized animation or commercial product rendering.
Here we’ll learn about different techniques to render out AO pass and then combine them with the Maya TS.

The video training can be categorized into:

  1. Ambient Occusion Through manuel object Plugin
  2. AO through layer compositing
  3. Toon Shader techniques
  4. Compositing the render scenes in Photoshop

 

Ambient Occlusion and ToonShader Render Composite Tutorial from Heather Craik on Vimeo.

Or watch it on Prantic’s Channel.

3D Rendering Tutorial Part Two

Welcome again! It’s time to continue writing more code for our small, simple and regularly fast 3D renderer. Today we will write a few more classes: Vertex3D, Plane3D, Object3D, World3D, FlatFiller, and Triangle. – Our “Hello World”, which is actually a rotating flat-filled triangle, will also be written on this lesson.

1. Vertex3D.as

A 3D vertex is basically a 3D point (x, y, z) that includes more information related to the presentation of the object that contains the vertex. Information such as color, texture information, light and more. – But for now, we’ll write a small vertex code that has includes only color information.

The following code goes in a file named “Vertex3D.as” on the “xr/core” folder.
[code]
/**
** Vertex3D.as
**
** Definition of a 3D Vertex3D.
**
** Written by J. Palencia (support@ciachn.com) (c) 2009-2011
*/

package xr.core
{
/**
** @prot: public class Vertex3D
**
** @desc: Describes a 3D Vertex. That is, a vector in 3D space that also
** has related properties such as light, texture information, etc.
*/

public class Vertex3D extends xr.core.Vector3D
{
/**
** @prot: public var vs: xr.core.Vector3D;
**
** @desc: Coordinates of the vertex in view-space (not world-space).
*/

public var vs: xr.core.Vector3D = new Vector3D ();

/**
** @prot: public var color: uint;
**
** @desc: Color of the vertex.
*/

public var color: uint;

/**
** @prot: public var _2d: Vector2D = null;
**
** @desc: Coordinates of the point in 2D space of the 3D vertex after
** a 3D to 2D projection is performed.
*/

public var _2d: Vector2D = new Vector2D ();

/**
** @prot: public function Vertex3D (x: Number = 0, y: Number = 0, z: Number = 0)
**
** @desc: Constructor of the 3D vertex. If no parameters are provided
** a vector at the origin (0, 0, 0) is created.
*/

public function Vertex3D (x: Number = 0, y: Number = 0, z: Number = 0)
{
this.x = x;
this.y = y;
this.z = z;
}

/**
** @prot: public function project () : void
**
** @desc: Performs a projection and stores the resulting 2D coordinates on
** the point2d object of the vertex.
*/

public function project () : void
{
this._2d.x = 0.5*640 + 256 * (vs.x / (vs.z + 256));
this._2d.y = 0.5*480 – 256 * (vs.y / (vs.z + 256));
}

/**
** @prot: public function transform (tm: Matrix3D) : void
**
** @desc: Transforms the vertex using the given matrix.
*/

public function transform (tm: Matrix3D) : void
{
tm.mulv (vs, true);
}

/**
** @prot: public function reset () : Vector3D
**
** @desc: Resets the ViewSpace vector and returns it.
*/

public function reset () : Vector3D
{
this.vs.x = x;
this.vs.y = y;
this.vs.z = z;
this.vs.w = w;

return this.vs;
}

};
};
[/code]
As you can see, the actual information is only the “color” field, which specifies the color of the vertex. As we advance to make a slightly more complicated renderer, we will modify this class to include more informational fields.

2. Plane3D.as

This is the most important part of the engine because all objects in our world are made up of planes. Since this will be seen thousands of times in the object queue it needs to be small and simple. Same as last time, this file goes into the “xr/core” folder.
[code]
/**
** Plane3D.as
**
** Definition of a plane in 3D space.
**
** Written by J. Palencia (support@ciachn.com) (c) 2009-2011
*/

package xr.core
{
/**
** @prot: public class Plane3D
**
** @desc: Describes a 3D plane. This is the most important part of the
** engine because all objects are made up of planes.
*/

public class Plane3D
{
/**
** @prot: public var v1: Vertex3D, v2: Vertex3D, v3: Vertex3D;
**
** @desc: Vertices that make up the 3D plane. Only three vertices are
** needed because we are using triangular planes.
*/

public var v1: Vertex3D;
public var v2: Vertex3D;
public var v3: Vertex3D;

/**
** @prot: public var filler: String;
**
** @desc: Name of the filler class. This is used to fill the plane.
*/

public var filler: String;

/**
** @prot: public function Plane3D (v1: Vertex3D, v2: Vertex3D, v3: Vertex3D)
**
** @desc: Constructor of the 3D plane.
*/

public function Plane3D (v1: Vertex3D = null, v2: Vertex3D = null, v3: Vertex3D = null)
{
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
}

/**
** @prot: public function depth () : Number
**
** @desc: Returns an approximation of the depth level of the plane, this
** is calculated as the average of the Z coordinate of each vertex.
*/

public function depth () : Number
{
return (this.v1.z + this.v2.z + this.v3.z) / 3;
}

/**
** @prot: public function project () : void
**
** @desc: Performs a projection on each of the vertices of the plane.
*/

public function project () : void
{
v1.project ();
v2.project ();
v3.project ();
}

/**
** @prot: public function transform (tm: Matrix3D) : void
**
** @desc: Transforms the vertices of the plane.
*/

public function transform (tm: Matrix3D) : void
{
v1.transform ™;
v2.transform ™;
v3.transform ™;
}
};
};
[/code]

The depth() function is used by the renderer to perform object ordering before showing the objects, this will be highly required to build a correct final scene. Later on we will see two small flash files, one with depth ordering and one without it, the difference will be highly noticeable.

The “filler” string is used to determine what is the class that fills the contents of the plane, a string is better because it needs little storage. On this lesson we will write code for one common filler known as the FlatFiller (for flat filling, that is a plain-single-colored plane 🙂

3. Object3D.as

The Object3D class provides a base for all objects that are used for modelling. It provides the famous ModelView matrix and currently only the render() method which should be overridden by child classes.
[code]
/**
** Object3D.as
**
** Generic 3D object. It is the base object for all modelling object. It includes
** model view matrix and rendering methods.
**
** Written by J. Palencia (support@ciachn.com) (c) 2009-2011
*/

package xr.core
{
/**
** @prot: public class Object3D
**
** @desc: Generic 3D object. It is the base object for all modelling
** object. It includes model view matrix and rendering methods.
*/

public class Object3D
{
/**
** @prot: public var modelView: Matrix3D;
**
** @desc: Model view matrix of the object.
*/

public var modelView: Matrix3D;

/**
** @prot: public function Object3D ()
**
** @desc: Constructor of the generic object.
*/

public function Object3D ()
{
this.modelView = Matrix3D.identity ();
}

/**
** @prot: public function render () : void
**
** @desc: Renders by transforming the object and generating fundamental
** objects (Plane3D) if necessary, the results are sent to the
** World’s rendering queue for further drawing.
*/

public function render () : void
{
// Should be implemented by child classes.
}
};
};
[/code]

4. World3D.as

[code]
/**
** World3D.as
**
** The world global object provides a clean mechanism to store and render objects
** using their “object data” which in this scope are just Plane3D objects.
**
** Written by J. Palencia (support@ciachn.com) (c) 2009-2011
*/

package xr.core
{
/**
** @prot: public class World3D
**
** @desc: The world global object provides a clean mechanism to store and
** render objects using their “object data” which in this scope are
** just Plane3D objects.
*/

public class World3D
{
/**
** @prot: public static var cameraView: Matrix3D;
**
** @desc: Camera view matrix of the world.
*/

public static var cameraView: Matrix3D = Matrix3D.identity ();

/**
** @prot: private static var queue: Array;
**
** @desc: Internal queue to store each Plane3D object.
*/

private static var queue: Array = new Array ();

/**
** @prot: private static var fillers: Object;
**
** @desc: List of registered plane fillers.
*/

private static var fillers: Object = new Object ();

/**
** @prot: public static function addFiller (name: String, code: Object) : Boolean
**
** @desc: Registers a filler in the system.
*/

public static function addFiller (name: String, code: Object) : Boolean
{
fillers[name] = code;
return true;
}

/**
** @prot: public static function clear () : void
**
** @desc: Clears the queue.
*/

public static function clear () : void
{
queue = new Array ();
}

/**
** @prot: public static function push (obj: Plane3D) : void
**
** @desc: Adds an object to the queue.
*/

public static function push (obj: Plane3D) : void
{
queue.push (obj);
}

/**
** @prot: public static function draw (g: flash.display.Graphics) : void
**
** @desc: Draws all primitive objects stored in the queue.
*/

public static function draw (g: flash.display.Graphics) : void
{
for each (var i in queue)
{
i.transform (cameraView);
i.project ();
}

g.clear ();

for each (var i in queue)
{
if (fillers[i.filler] == null)
continue;

fillers[i.filler].draw (i, g);
}
}
};
};
[/code]

5. FlatFiller.as

The FlatFiller provides an standard draw() method which will fill a provided plane with the color of the first vertex of the plane. The result is written to a graphics surface provided as a parameter. For this file you will need to create another folder on xr named “filler”. The file path should be xr/fillers/FlatFiller.as.
[code]
/**
** FlatFiller.as
**
** Flat filler. Nothing much to say.
**
** Written by J. Palencia (support@ciachn.com) (c) 2009-2011
*/

package xr.fillers
{
import xr.core.World3D;

/**
** @prot: public class FlatFiller
**
** @desc: Flat filler. Nothing much to say.
*/

public class FlatFiller
{
/**
** @prot: public static var reg: Boolean;
**
** @desc: Registers the FlatFiller class using the name “flat”.
*/

public static var reg: Boolean = World3D.addFiller (“flat”, new FlatFiller ());

/**
** @prot: public function draw (p: xr.core.Plane3D, g: Graphics) : void
**
** @desc: Draws the plane on the given graphics surface. The actual color
** used to fill is the color of the first vertex.
*/

public function draw (p: xr.core.Plane3D, g: flash.display.Graphics) : void
{
g.beginFill (p.v1.color);
g.moveTo (p.v1._2d.x, p.v1._2d.y);
g.lineTo (p.v2._2d.x, p.v2._2d.y);
g.lineTo (p.v3._2d.x, p.v3._2d.y);
g.endFill ();
}
};
};
[/code]
All filler classes should implement a draw() method as shown above receiving two parameters, one of type xr.core.Plane3D and another of type flash.display.Graphics. The filler can assume that the “_2d” field of the vertices of the plane are ready (aka already projected to 2D space).

A filler should also register itself using World3D.addFiller() with a string specifying its name, this way when a Plane3D object uses the same name on its “filler” field the correct object will be located.

6. Triangle.as

Since we’re now done with the core and the fillers, you can forget about those folders. Now create another one with the name “model”, here we will be storing the modelling object. And for our first object we’ll create “Triangle”.
[code]
/**
** Triangle.as
**
** Triangle class for object modelling.
**
** Written by J. Palencia (support@ciachn.com) (c) 2009-2011
*/

package xr.model
{
import xr.core.Object3D;

import xr.core.Vertex3D;
import xr.core.Plane3D;

import xr.core.World3D;

/**
** @prot: public class Triangle
**
** @desc: Triangle class for object modelling.
*/

public class Triangle extends xr.core.Object3D
{
/**
** @prot: public var plane: Plane3D;
**
** @desc: Plane that describes the triangle.
*/

public var plane: Plane3D = new Plane3D ();

/**
** Properties used to forward to the plane properties.
*/

public function get v1 () { return plane.v1; }
public function get v2 () { return plane.v2; }
public function get v3 () { return plane.v3; }
public function get filler () { return plane.filler; }

public function set v1 (v: Vertex3D) { plane.v1 = v; }
public function set v2 (v: Vertex3D) { plane.v2 = v; }
public function set v3 (v: Vertex3D) { plane.v3 = v; }
public function set filler (v: String) { plane.filler = v; }

/**
** @prot: public function Triangle (v1: Vertex3D, v2: Vertex3D, v3: Vertex3D)
**
** @desc: Constructor of the 3D triangle.
*/

public function Triangle (v1: Vertex3D = null, v2: Vertex3D = null, v3: Vertex3D = null)
{
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
}

/**
** @prot: public override function render () : void
**
** @desc: Renders the object. Overrides Object3D.render().
*/

public override function render () : void
{
modelView.mulv (plane.v1.reset (), true);
modelView.mulv (plane.v2.reset (), true);
modelView.mulv (plane.v3.reset (), true);

World3D.push (plane);
}
};
};
[/code]
Well, now we have everything we need for the hello world #1!! The following code is the Main.as file which will use all the stuff we have done so far.
[code]
/**
** Main.as
**
** Skeleton code for an ActionScript 3 application.
**
** Compile using: as3compile -X 640 -Y 480 Main.as
** Download as3compile from: http://www.swftools.org/
*/

import flash.display.MovieClip;
import flash.events.*;

import xr.core.Vector2D;
import xr.core.Vector3D;
import xr.core.Matrix3D;
import xr.core.Vertex3D;
import xr.core.Plane3D;
import xr.core.World3D;

import xr.fillers.FlatFiller;

import xr.model.Triangle;

// Main package.
package Main
{
// Main class.
public class Main extends MovieClip
{
public var a, b;

public function Main ()
{
var w: int = 50;
var h: int = 50;

a = new Triangle (); a.filler = “flat”;
a.v1 = new Vertex3D (w, h, 0);
a.v2 = new Vertex3D (-w, -h, 0);
a.v3 = new Vertex3D (-w, h, 0);
a.v1.color = 0xFF0000;

b = new Triangle (); b.filler = “flat”;
b.v1 = new Vertex3D (w, h, 0);
b.v2 = new Vertex3D (w, -h, 0);
b.v3 = new Vertex3D (-w, -h, 0);
b.v1.color = 0xFFF000;

stage.addEventListener (Event.ENTER_FRAME, onEnterFrame);
}

public function onEnterFrame (e: Event)
{
World3D.clear ();

World3D.cameraView =
World3D.cameraView
.rotate (0.06, 0, 0, 1)
.rotate (0.02, 0, 1, 0)
.rotate (0.07, 1, 0, 0);

a.render ();
b.render ();

World3D.draw (this.graphics);
}
};
};
[/code]
Don’t worry about compilation, or which folder to use. The result is a square with two colors that rotates on all axes on every frame that is updated on the AS3 project.

If you want to download the files (all of them) including the executables, examples and the batch files used to compile you can click here: http://www.ciachn.com/lab/3d/06.zip

Next lesson is going to be a little bit harder because it will be time to write a lot more object modelling classes and begin writing more complex figures! 🙂

3D101 Starting a Simple Renderer

Now that you’re familiar with the fundamentals of 3D (spaces, coordinates, projections, and rotations) and the processes that are performed by a renderer, it’s finally time to begin writing a quick and clean simple 3D renderer in Action Script 3 language. I chose AS3 because it’s easy and quick to develop, but if you don’t like AS3 you can use any language of your choice and apply the same principles shown in this lesson.

Note: To compile the code shown throughout this lesson you will need an ActionScript 3 compiler such as Adobe Flex or an alternative such as AS3Compile from SWFTools which can be downloaded for free from http://www.swftools.org/. The code was written to be compliant with AS3Compile, it’s highly recommended to use it.

 

1. What To Do From Here

 

The first thing we need to do is to write the core classes of our system, we will be using fully object oriented programming and I’m sure you’ll enjoy the following paragraphs, it’s finally time to see previous knowledge from a much more practical point of view. By core classes I mean the classes that will be used as a base for everything else in our system. In case you’re not familiar with the term “class”, please visit http://en.wikipedia.org/wiki/Class_(computer_programming) for more information.

 

If you’re not familiar with AS3 or any programming language for that matter – don’t worry, the examples shown here are ready-to-run, you can just copy+paste them and run them yourself without problems, this way you can test everything first and if you see it’s worth learning a programming language then you’ll have enough motivation already.

 

Our simple yet useful 3D engine library will be called “xr”, so create a new folder named “xr”. Everytime you need to import the xr library into your AS3 project just copy the entire folder to your new project’s folder. We will not use a stacked model like OpenGL, instead we will use a method much simpler and easier to understand.

 

Today we will prepare the core classes of the renderer (only the basic ones, other more advanced elements will be done later on), these classes are:

 

  • Vector2D
  • Vector3D
  • Matrix3D

 

To begin create a sub-folder named core on the xr folder. All files we will create have “.as” extension and should be placed on this folder.

2. Vector2D.as

[code]
/**
** Vector2D.as
**
** Definition of a 2D vector.
**
** Written by J. Palencia (support@ciachn.com) © 2009-2011
*/

package xr.core
{
/**
** @prot: public class Vector2D
**
** @desc: Describes a vector in 2D-space, that is an object containing
** two coordinates x and y.
*/

public class Vector2D
{
/**
** @prot: public var x: Number;
**
** @desc: X-coordinate (horizontal axis) value of the vector.
*/

public var x: Number;

/**
** @prot: public var y: Number;
**
** @desc: Y-coordinate (vertical axis) value of the vector.
*/

public var y: Number;

/**
** @prot: public function Vector2D (x: Number = 0, y: Number = 0)
**
** @desc: Constructor of the 2D vector. If no parameters are provided
** a vector at the origin (0, 0) is created.
*/

public function Vector2D (x: Number = 0, y: Number = 0)
{
this.x = x;
this.y = y;
}

/**
** @prot: public function clone () : Object
**
** @desc: Returns a clone of the object.
*/

public function clone () : Object
{
return new Vector2D (x, y);
}
};
};

[/code]

As you can see this class is used for storage only, there are no operations at all, this is because we are not really using 2D vectors for calculations, instead we use this class only as a temporal storage when we convert vectors from 3D space to 2D space.

 

3. Vector3D.as

[code]

/**
** Vector3D.as
**
** Definition of a 3D vector.
**
** Written by J. Palencia (support@ciachn.com) © 2009-2011
*/

package xr.core
{
/**
** @prot: public class Vector3D
**
** @desc: Describes a vector in 3D space, that is an object containing
** three coordinates x, y and z. Several methods to manipulate a
** 3D vector are also provided.
*/

public class Vector3D
{
/**
** @prot: public var x: Number;
**
** @desc: X-coordinate (horizontal axis) value of the vector.
*/

public var x: Number;

/**
** @prot: public var y: Number;
**
** @desc: Y-coordinate (vertical axis) value of the vector.
*/

public var y: Number;

/**
** @prot: public var z: Number;
**
** @desc: Z-coordinate (depth axis) value of the vector.
*/

public var z: Number;

/**
** @prot: public var w: Number;
**
** @desc: W-coordinate (homogeneous coordinate).
*/

public var w: Number;

/**
** @prot: public function Vector3D (x: Number = 0, y: Number = 0, z: Number = 0, w: Number = 1)
**
** @desc: Constructor of the 3D vector. If no parameters are provided
** a vector at the origin (0, 0, 0, 1) is created.
*/

public function Vector3D (x: Number = 0, y: Number = 0, z: Number = 0, w: Number = 1)
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}

/**
** @prot: public function scaleByVector (vector: Vector3D) : Vector3D
**
** @desc: Multiplies corresponding coordinate values of the vectors and
** updates the current vector values.
*/

public function scaleByVector (vector: Vector3D) : Vector3D
{
x *= vector.x;
y *= vector.y;
z *= vector.z;
w *= vector.w;

return this;
}

/**
** @prot: public function scaleByFactor (factor: Number) : Vector3D
**
** @desc: Updates each coordinate with the product of the coordinate
** and the given factor.
*/

public function scaleByFactor (factor: Number) : Vector3D
{
x *= factor;
y *= factor;
z *= factor;
w *= factor;

return this;
}

/**
** @prot: public function sumVector (vector: Vector3D) : Vector3D
**
** @desc: Sums the corresponding coordinates of the vectors and
** updates the current vector values.
*/

public function sumVector (vector: Vector3D) : Vector3D
{
x += vector.x;
y += vector.y;
z += vector.z;
w += vector.w;

return this;
}

/**
** @prot: public function subVector (vector: Vector3D) : Vector3D
**
** @desc: Subtracts the corresponding coordinates of the vectors and
** updates the current vector values.
*/

public function subVector (vector: Vector3D) : Vector3D
{
x -= vector.x;
y -= vector.y;
z -= vector.z;
w -= vector.w;

return this;
}

/**
** @prot: public function norm () : Number
**
** @desc: Returns the norm of the vector, that is the square root of
** the sum of squared coordinates.
*/

public function norm () : Number
{
return Math.sqrt (x*x + y*y + z*z + w*w);
}

/**
** @prot: public function crossProduct (vector: Vector3D) : Vector3D
**
** @desc: Builds a new vector formed by the result of the cross product
** between the current and the given vector.
*/

public function crossProduct (vector: Vector3D) : Vector3D
{
return new Vector3D (
y*vector.z – vector.y*z,
-x*vector.z + vector.x*z,
x*vector.y – vector.x*y
);
}

/**
** @prot: public function dotProduct (vector: Vector3D) : Number
**
** @desc: Returns the dot product of the current vector and the given one.
*/

public function dotProduct (vector: Vector3D) : Number
{
return x*vector.x + y*vector.y + z*vector.z + w*vector.w;
}

/**
** @prot: public function normalize () : Vector3D
**
** @desc: Returns a new vector that contains the normalized components
** of the current vector.
*/

public function normalize () : Vector3D
{
var n: Number = this.norm ();

return new Vector3D (x/n, y/n, z/n, w/n);
}

/**
** @prot: public function clone () : Object
**
** @desc: Returns a clone of the object.
*/

public function clone () : Object
{
return new Vector3D (x, y, z, w);
}
};
};

[/code]

The 3D vector class besides containing standard storage for the four coordinates (x, y, z and w) it also has many methods to operate over the vectors, methods such as scale, subtraction, addition, normalization, cross product, and dot product.

 

The 3D vector will eventually represent the position of a vertex, and a vertex will contain information related to the actual object, such as texture coordinates, light colors, etc. But for now, we’ll just write the basic 3D vector as shown above.

 

4. Matrix3D.as

[code]
/**
** Matrix3D.as
**
** Definition of a 3D matrix.
**
** Written by J. Palencia (support@ciachn.com) © 2009-2011
*/

package xr.core
{
/**
** @prot: public class Matrix3D
**
** @desc: Provides an interface to create and manipulate homogeneous 4×4 matrices.
*/

public class Matrix3D
{
/**
** @prot: public var values: Array;
**
** @desc: Contains the actual values of the matrix, this array contains a total
** of sixteen (16) floating-point elements.
*/

public var values: Array;

/**
** @prot: public function Matrix3D (values: Array = null)
**
** @desc: Constructs an instance of the matrix class, the given parameter contains
** the values to store in the matrix, if not provided, a zero-matrix will
** be created.
*/

public function Matrix3D (values: Array = null)
{
if (values == null)
this.values = new Array (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
this.values = values;
}

/**
** @prot: public static function identity () : Matrix3D
**
** @desc: Returns a new identity matrix, that is, a matrix with it’s diagonal
** set to ones and the rest to zero.
*/

public static function identity () : Matrix3D
{
return new Matrix3D (new Array
(
1.000, 0.000, 0.000, 0.000,
0.000, 1.000, 0.000, 0.000,
0.000, 0.000, 1.000, 0.000,
0.000, 0.000, 0.000, 1.000
));
}

/**
** @prot: public function mul (p: Matrix3D) : Matrix3D
**
** @desc: Returns the product of the current matrix and the given one (p), returns
** a completely new matrix.
*/

public function mul (p: Matrix3D) : Matrix3D
{
var result:Matrix3D = new Matrix3D ();

for (var i:uint = 0; i < 16; i += 4)
{
for (var k:uint = 0; k < 4; k++)
{
var sum:Number = 0;

for (var j:uint = 0; j < 4; j++)
sum += values[i+j] * p.values[k+j*4];

result.values[i+k] = sum;
}
}

return result;
}

/**
** @prot: public function sum (p: Matrix3D) : Matrix3D
**
** @desc: Returns the sum of the current matrix and the given one (p), returns
** a completely new matrix.
*/

public function sum (p: Matrix3D) : Matrix3D
{
var result:Matrix3D = new Matrix3D ();

for (var i:uint = 0; i < 16; i += 4)
{
for (var j:uint = 0; j < 4; j++)
result.values[i+j] = values[i+j] + p.values[i+j];
}

return result;
}

/**
** @prot: public function transpose () : Matrix3D
**
** @desc: Transposes the matrix (reverts the order of the components of the matrix
** from ij to ji) and returns a new matrix.
*/

public function transpose () : Matrix3D
{
var result:Matrix3D = new Matrix3D ();

for (var j:uint = 0; j < 4; j++)
{
for (var i:uint = 0; i < 4; i++)
result.values[j*16+i] = values[i*16 + j];
}

return result;
}

/**
** @prot: public function mulScalar (f: Number) : Matrix3D
**
** @desc: Multiplies the matrix by the given scalar and returns a new matrix.
*/

public function mulScalar (f: Number) : Matrix3D
{
var result:Matrix3D = new Matrix3D ();

for (var i:uint = 0; i < 16; i += 4)
{
for (var j:uint = 0; j < 4; j++)
result.values[i+j] = values[i+j] * f;
}

return result;
}

/**
** @prot: public static function translationMatrix (x:Number, y:Number, z:Number) : Matrix3D
**
** @desc: Returns a translation matrix for the given components.
*/

public static function translationMatrix (x:Number, y:Number, z:Number) : Matrix3D
{
var result:Matrix3D = Matrix3D.identity ();

result.values[0x03] = x;
result.values[0x07] = y;
result.values[0x0B] = z;

return result;
}

/**
** @prot: public static function rotationMatrix (f:Number, x:Number, y:Number, z:Number) : Matrix3D
**
** @desc: Returns a rotation matrix configured to rotate by the given factor (f) along
** the given arbitrary axis (x, y, z).
*/

public static function rotationMatrix (f:Number, x:Number, y:Number, z:Number) : Matrix3D
{
var result:Matrix3D = new Matrix3D ();

var C:Number = 1.0 – Math.cos (f);
var s:Number = Math.sin (f);
var c:Number = Math.cos (f);

result.values[0] = 1 + C*(x*x – 1);
result.values[1] = C*x*y – z*s;
result.values[2] = C*x*z + y*s;

result.values[4] = C*x*y + z*s;
result.values[5] = 1 + C*(y*y – 1);
result.values[6] = C*y*z – x*s;

result.values[8] = C*x*z – y*s;
result.values[9] = C*y*z + x*s;
result.values[10] = 1 + C*(z*z – 1);

result.values[15] = 1.0;

return result;
}

/**
** @prot: public static function scalationMatrix (fx:Number, fy:Number, fz:Number) : Matrix3D
**
** @desc: Returns an scalation matrix configured to scale each x, y and z component
** by the given factors respectively.
*/

public static function scalationMatrix (fx:Number, fy:Number, fz:Number) : Matrix3D
{
var result:Matrix3D = Matrix3D.identity ();

result.values[0x00] = fx;
result.values[0x05] = fy;
result.values[0x0A] = fz;

return result;
}

/**
** @prot: public function mulv (v:Vector3D, rewrite: Boolean = false) : Vector3D
**
** @desc: Returns a vector that is the product of the current matrix and the
** given vector. If rewrite is set the vector components will be updated
** and returned, otherwise a new vector is returned.
*/

public function mulv (v:Vector3D, rewrite: Boolean = false) : Vector3D
{
var x:Number, y:Number, z:Number, w:Number;

x = values[0x00+0] * v.x;
x += values[0x00+1] * v.y;
x += values[0x00+2] * v.z;
x += values[0x00+3] * v.w;

y = values[0x04+0] * v.x;
y += values[0x04+1] * v.y;
y += values[0x04+2] * v.z;
y += values[0x04+3] * v.w;

z = values[0x08+0] * v.x;
z += values[0x08+1] * v.y;
z += values[0x08+2] * v.z;
z += values[0x08+3] * v.w;

w = values[0x0C+0] * v.x;
w += values[0x0C+1] * v.y;
w += values[0x0C+2] * v.z;
w += values[0x0C+3] * v.w;

if (rewrite)
{
v.x = x; v.y = y; v.z = z; v.w = w;
return v;
}
else
return new Vector3D (x, y, z, w);
}

/**
** @prot: public function translate (x:Number, y:Number, z:Number, r:Boolean=false) : Matrix3D
**
** @desc: Translates the current matrix to the given point and returns
** a new matrix.
*/

public function translate (x:Number, y:Number, z:Number, r:Boolean=false) : Matrix3D
{
if (r)
return Matrix3D.translationMatrix (x, y, z).mul (this);
else
return this.mul (Matrix3D.translationMatrix (x, y, z));
}

/**
** @prot: public function rotate (f:Number, x:Number, y:Number, z:Number, r:Boolean=false) : Matrix3D
**
** @desc: Rotates the current matrix by the given factor along the given
** arbitrary axis, returns a new matrix.
*/

public function rotate (f:Number, x:Number, y:Number, z:Number, r:Boolean=false) : Matrix3D
{
if (r)
return Matrix3D.rotationMatrix (f, x, y, z).mul (this);
else
return this.mul (Matrix3D.rotationMatrix (f, x, y, z));
}

/**
** @prot: public function scale (fx:Number, fy:Number, fz:Number, r:Boolean=false) : Matrix3D
**
** @desc: Scales the current matrix by the given factors and returns
** a new matrix.
*/

public function scale (fx:Number, fy:Number, fz:Number, r:Boolean=false) : Matrix3D
{
if (r)
return Matrix3D.scalationMatrix (fx, fy, fz).mul (this);
else
return this.mul (Matrix3D.scalationMatrix (fx, fy, fz));
}

/**
** @prot: public function clone () : Matrix3D
**
** @desc: Returns a clone of the matrix.
*/

public function clone () : Matrix3D
{
var newObj:Matrix3D = new Matrix3D ();

newObj.values = values.concat ();
return newObj;
}
};
};

[/code]

This is a very important class, it may not be as optimized as it should be, but the code is clean and as crystal clear as I could write it, it can be easily understood and will help you to develop more optimized classes later on.

 

The Matrix3D class stores only 16 floating point numbers representing each element of the 4×4 matrix, the rest of the class are a bunch of methods to help manipulate the matrix, and as you may notice, rotation, scaling and translation is embedded in the class, which will make it quite easy to build our Model View matrices once we get there!!

 

Right now you should have a folder named “xr” and inside it should be another folder named “core”. The core folder has (for now) only three files, Vector2D.as, Vector3D.as and Matrix3D.as – On the next lesson we will continue writing the rest of the classes in order to actually build our first “Hello World”.

 

 

Mental Ray Caustics Tutorial (Maya)

Alright, after so much anticipation in creating a lighting tutorial in Maya, I’m back with a proper, easily understood, video lesson regarding Caustics. The Video lesson is about 20 minutes and focuses on Maya’s Mental Ray system shaders and lighting techniques. Caustic effect is an important and a remarkable effect which occurs in nature and is very much required in creating a realistic looking glass lighting effect.  As this is a more advanced tutorial beginners may have a little trouble initially; don’t worry, I’m available if you’ve any questions.

The Topics in the video can be categorized as follows:

  1.  Intro: Discussing “what is caustics?” with examples
  2. Creating basic caustic effect using Maya’s own default material nodes
  3. Discussing about Photon transmission, GI/Caustics
  4. Creating Caustics with Mental Ray materials
  5. Ways and Tips to make Renders times faster
  6. Conclusion: Showing mental ray renders with properties and Photon Map Visualizer.

So, grab a pack of something (I’d recommend chips) and let’s get started!

Maya Mental Ray Caustics Tutorial from Heather Craik on Vimeo.

Alternatively, you can watch it on Prantic’s Youtube channel.

3D 101 Expanding on Matrices

Affine Transformations

First and foremost, an affine transformation is simply a linear transformation followed by an addition. A linear transformation is an equation that operates on a vector to transform it into something else, the most popular linear transformations are rotation, and scaling.

Ordinarily we perform linear transformations by evaluating equations, take for example the equations for X-axis rotation found on the first lesson of this tutorial, which are defined by:

Z’ = Z*COS(Θ) – Y*SIN(Θ)

Y’ = Z*SIN(Θ) + Y*COS(Θ)

 

The above equations contain 4 multiplications and 2 additions, for a total of 6 arithmetic operations just for X-axis rotation. Now imagine we have about 3000 vertices that need to be rotated in X, Y and Z axes, and then need to be scaled (which requires 3 multiplications one for each vector component), that gives us a total of 63,000 operations just to rotate and scale each vertex, imagine if we had a more complex object that had more vertices and required more actions such as scaling more than once, or translating, and rotating using different axes, the final number of operations required would easily grow to millions, here’s where our beloved matrices come in!

Note: Before anything, there is need to mention a slight mistake in the previous lesson, when describing matrix multiplication I strictly said only squared matrices can be multiplied, but in fact that’s not true. In order to correctly multiply matrices A and B, the matrix A should be of size NxM and matrix B must be of size MxP, (in other words, the number of columns of A should match the number of rows of B), now after processing the multiplication the resulting matrix will be of size NxP. – Apologies for my mistake.

With matrices we are able to perform parallel multiplication of vectors, to make this clear imagine we combine the above equations into a single matrix, the result would be:

As you can see, the matrix shown above (A) can be multiplied with a 3D vector (V) and the result obtained (R) will be the same result as the one obtained with equations for X-axis rotation. But still, we have a small problem, what if our equations were changed to something like this:

 

Z’ = Z*COS(Θ) – Y*SIN(Θ) + 777

Y’ = Z*SIN(Θ) + Y*COS(Θ) + 555

 

I have deliberately added an addition on both equations (the +777 and +555), if you think about this for about five minutes you will realize there is no way to use a 3×3 matrix to produce the exact same output as these equations.

 

1. Homogeneous Coordinate Space

Homogeneous coordinate space is the solution to the problem we found a few seconds ago in the previous paragraph. The term “homogeneous” can be more easily understood as “to be symmetric”, for example imagine when you’re baking, and the cake mix has some small lumps, you whisk and keep whisking the mix until it’s smooth and all evened out, right? What you did was to obtain a “homogeneous” mix.

The same applies to matrix arithmetic, with matrices we are able to multiply, and divide, but addition of an scalar value is not possible. But when using homogeneous coordinates we are able to use all basic arithmetic operations and combine them in a single matrix.

Imagine we have the usual 3D vector <x, y, z>, to make it homogeneous the only thing we need is to add a new coordinate to the vector with the value of “1”, the actual letter for the new coordinate may vary, but most books use the letter “w”. Our vector <x, y, z> becomes the homogeneous vector <x, y, z, w> with “w” being the value “1”.

Similarly we do the same with our matrices, if we had a 3×3 matrix we will now add another column and another row to make it 4×4. And now we’re using homogeneous vectors and homogeneous matrices.

Let’s retry the previous problem, and let’s see if now we’re able to create a single matrix that can produce the same result as the equations shown below:

Z’ = Z*COS(Θ) – Y*SIN(Θ) + 777

Y’ = Z*SIN(Θ) + Y*COS(Θ) + 555

 

Our brand new homogenous matrix is:

The matrix “A” (also known as augmented matrix, or affine transformation matrix) effectively produces the correct result when multiplied with a homogeneous vector, and as you can see using the magical w coordinate we can perform addition within the same matrix without problems of any kind.

But what does this mean?

This means, one simple thing that’s incredibly important: We can now combine several linear transformations such as rotation, scaling and now even translation into one single matrix and use it only when we need it. A single matrix multiplication operation with a homogeneous vector will be the equivalent of evaluating ALL the linear transformations at once, saving indeed some speed and code complexity.

To combine the transformations, first you have to figure out the affine transformation matrix for the equations of the transformation you want to combine (let’s call this matrix B), just like we did on this lesson to figure out the matrix for the X-axis rotation.

Once you have that matrix, just multiply it with an existing matrix (let’s call it A) where A is the current matrix, which initially is set to an identity matrix. The identity matrix is a matrix where it’s diagonal contains only “1”s.

2. Affine Transformation Matrices

The following is a list of matrices for most of the operations we will be needing on our simple 3D renderer.

 

In all the matrices,  Θ is the angle in radians. fX, fY and fZ are scaling factors for the X, Y and Z axes respectively. And dX, dY and dZ are displacement values used when translating the X, Y and Z axes respectively.

Combine multiple matrices by multiplying them, and the resulting matrix will be the matrix representation of the operands. For example, if we have matrix A for X-rotation, matrix B for scaling matrix C for translation, and a homogeneous vector v which is the vector we want to transform. The goal is to perform A, B then C on the vector.

Evaluating step by step, we have:

v1 = A * v

v2 = B * v1

v3 = C * v2

v’ = v3

Above you can see v1, v2 and v3, which are temporal vectors which represent the product of the respective matrix with the previous vector. v’ represents the result vector. Now, the previous statements are equivalent to say:

v’ = C * (B * (A * v))

The following was obtained by replacing temporal vectors v1, v2, v3 on the final equation for the result “v’ = v3”. We can now remove parenthesis and we get:

v’ = C * B * A * v

Using associative properties of matrices we can continue factorizing to obtain:

v’ = ((C * B) * A) * v

And finally we combine the matrix product of C*B and A on a single matrix we’ll call M, and the final result is:

v’ = M * v

What you see here, this simple equation is the one we’ll see the most on our 3D renderer, the matrix M is obtained by multiplying C by B and then by A. Note that the order is VERY important, matrix multiplication is NOT commutative. Meaning that A*B is NOT the same as B*A, be careful there.

The matrix M is known as the Model View Matrix, which is the combination of all the transformations required to make our 3D model look the way it’s supposed to on the rendered world, all of our 3D objects have a model view matrix.

On the next lesson we will begin coding all these fundamentals in actual code.

 

3D Burning Paper Tutorial (FumeFX)

3D Burning Paper Effect (Ian Steve) from Heather Craik on Vimeo.

Hello everyone, I’m Ian Steve, welcome to another 3d tutorial. In this tutorial we are going to  to create a nice 3d burning paper effect with FumeFx plugin in 3DS Max. Ok.. let’s get started.

The first step, let’s create a simple plane on perspective view. Size or color doesn’t matter.

Open up material editor, select ‘Get Material’ and apply Gradient Ramp on the first slot.

Now, we can add 2 keys on the Gradient Ramp color until we get a white thin line like picture below. Set the noise amount to 0.1 and size to 2.

Now, let’s create texture for the paper. Drag the first slot material to the diffuse color on the second slot and choose ‘instance’. Rename it to ‘Paper’. Then apply it to the paper on stage.

Apply UVW Map modifier to the paper. Rotate the gizmo 900 and scale it up little bit.

Let’s scale up the timeline to 400 or 450. Go to the first slot of your material editor then turn on Auto Key. Animate the 3 middle keys from left to right. Then, turn off the Auto Key.


 

Go to second slot, drag/copy the diffuse map to opacity map, and clear its diffuse map.

Go to gradient ramp parameters delete the second keys and edit the color like picture below. Don’t move or delete the other keys.

We can now create the temperature map. Copy the opacity map to the new slot then rename it to ‘Temperature’, select ‘output’ and choose ‘invert’.

Edit the gradient color of the temperature map like below.

Now, let’s apply the FumeFx grid to the whole paper. Select FumeFx Helpers, choose ‘Object src’ and draw this outside the grid. Choose ‘pick object’ and click the paper.

Select the Object Src, set the Fuel, Temperature, and Smoke map to ‘Source from Intensity’. Chose instance for all map.

Open FumeFx UI, go to General Tab and set the Spacing to 1 . Then go to Simulation tab set the parameters like below :

–          Quality : 3 (depends on your computer spec)

–          Bouyancy : 0.65

–          Burn rate : 12.5

–          Dissipation strength : 5

–          Check Fire Creates Smoke.

Go to Obj/Src tab and choose ‘pick object’. Then click the src helper on stage. You can also change the fuel or smoke color from Rendering tab. Let’s start the simulation. And here is what I got on output preview.

Finally, render the scene as video and see the final result. Happy 3d ^^