thesispt3

advertisement
4.1 Imppaint
Impressionist Paint only effects the user-selected objects, and the Imppaint script
acts as a controller for Impressionist Paint ensuring the proper actions are taken for each
selected object. First, the script determines if the selected object is valid for painting.
Imppaint queries the object to establish whether or not the object has previously been
painted; if so the Paint group of scripts is called. If the object has yet to be painted, the
Prepaint sections are called. Once Prepaint is complete, Imppaint invokes the
procedures necessary to paint the object. If the object is not a NURBS surface, the user is
asked to choose another object for painting.
The Imppaint Script, then adds and stores, to each object, attributes from the userinterface including: curve length, curve direction, stroke width, perturb direction, perturb
amount and perturb position. These values are used to calculate shadows and highlighs
which are explained in section 4.5.3.
4.2 Prepaint
The preparation modules of code prepare the object and the scene to be painted.
Prepaint prepares each object for painting by creating nodes and ensuring that the proper
relationships are present for the painting process. Below we describe in detail the purpose
of each node created, each attribute set, and the impact of our variables throughout the
Prepaint routines of Impressionist Paint.
4.2.1 Creating Nodes
The Prepaint script first determines if the object is connected to a
closestPointOnSurface node. If one exists the Prepaint portions of the script are skipped,
ensuring that Prepaint is executed only one time per object. If one does not exist, a
closestPointOnSurface node is created to supply data in a usable form containing the
starting position of the curve. The world space attribute of the object Shape Node is
connected to the input attribute of the closestPointOnSurface. Connecting the two
attributes serves a dual purpose crucial to the final portions of the script. First, the
closestPointOnSurface node will provide the point on the surface closest to the point
from which a particle is emitted. Throughout the script particles are used to establish the
starting point for each curve. To obtain the particle position in UV texture space we must
use the value returned from the closestPointOnSurface node.
Particles are emitted from an exact position directly on a polygonal surface in
world space, yet when particles are emitted from a NURBS object, the particles are near
the surface but not always on the surface. Second, the newly created node takes each
particle’s emission point and determines the point on the surface that is closest to the
emission position. Also, the curveOnSurface command, used to create curves attached to
the object, calls for UV coordinates. The closestPointOnSurface node returns the surface
point in both world space and UV space so that the particle position may be used to
create a brush stroke.
4.2.2 Adding Particle objects to Point Emitters
As mentioned earlier, particles are utilized to create semi-random locations for the
strokes. In this way, the strokes appear to be painted with a certain degree of spontaneity.
Three point emitters are created as surface emitters for each object; in turn and each
emitter is connected to a particle group. Figure 4.1 illustrates particles created as a result
of the prepaint script as they are emitted from a sphere.
Figure 4.1 Particles created by the Prepaint script emit from a sphere
4.2.3 Per Particle and Emitter Attributes
Per particle attributes for particle color and opacity are added to each particle
group, thus creating new options for the emitters. Attributes are also set for each of the
particle groups and each emitter. All three emitters provide both common and unique
data for the brush strokes.
Each emitter is set to release particles based on the scale of the object. Maya
calculates the area of each object containing an emitter and determines a ratio that
ensures an even particle emission relative to the size of the object. Scaling the emission
rate promotes an even covering of strokes on all of the objects and thus prevents smaller
objects from being overly inundated with strokes. Figure 4.2 compares the emission rates
by scale and not by scale. The first set of spheres utilized scale by size, and the second set
does not.
Figure 4.2 emission rates
Collectively, the emitters and particles designate the placement of the initial point used to
create a curve, as well as color information for the curve, yet each particle group and
emitter query different sources to procure the data necessary to instigate the drawing
procedure.
4.2.3.1 Emitters
The first emitter is seeded to emit particles at unique positions, while the second and third
emitters are set to emit particles at coinciding locations. The first emitter, named Mid, holds information
used for the strokes that fall within the mid-tones of the object. The second emitter, named Ref, provides a
color Reference for strokes which fall in areas of highlight or shadow. The third emitter, Hishad,
determines which strokes are drawn to portray the shadowed and highlighted areas of the object.
4.2.3.1.1 Mid Emitter
The purpose of the Mid emitter is to control the covering of the object with brushstrokes. The
emitter gives off particles evenly over the object’s surface. The intersection point of each particle with the
surface marks the starting point of a curve. The goal is to completely cover the object with paint strokes;
however, blank spaces will occasionally appear. Alterations to the geoConnector node helped solve this
problem.
In our case, the geoConnector node provides an interface between the NURBS surface and the dynamics
system providing a tessellated polygonal representation of the NURBS object. Increasing the tessellation
of the geoConnector causes the particles to be emitted more evenly across the surface, thus allowing the
gaps to be filled as showed in Figure 4.3.
Figure 4.3 changing geoConnector tessellation
Here, the first sphere represents the particle emission pattern with the default geoConnector tessellation,
while the second sphere shows a more even emission as a result of increasing the geoConnector
tessellation. Since the particles are dispersed in a dense, consistent pattern, the gaps between strokes are
decreased and the holes disappear.
4.2.3.1.2 The Ref Emitter
Once the object is covered with a base layer of strokes, the Ref emitter acts as a color Reference
for the next layer of strokes which are drawn using the Hishad emitter. The Ref and Hishad emitters give
off particles at precisely the same positions. In order to avoid creating unnecessary strokes, only the Hishad
particles are used to draw strokes, while the Ref emitter supplies the color for each stroke. Figure 3.19
shows how the Ref emitter is used as a Reference to determine the starting position of the shadowed or
highlighted strokes. The colores particles are from the Ref emitter, which provides the color information
for strokes which fall in highlight or shadow. The grayscale values within the Ref particles are the
Highshad particles represent luminosity information for the object.
Figure 4.4 purpose of Ref emitter
The particle color represents the only difference between the Ref and Hishad particle groups.
4.2.3.1.3 The Hishad Emitter
The Hishad emitter determines which strokes will be drawn to illustrate areas of the object that fall
in shadow or highlight. Since impressionists avoid using black to illustrate shadows, a modified lighting
and shading scheme was developed. Here, the object shadows are based on the color of the object. That is,
a mixture of the original object color and the complementary color of the surface area are used along with
synched file textures to give the appearance of brush strokes in uniquely colored shadows. The saturation
of the color which falls in an area of highlight is decreased inorder to represent the influence of the lights.
In order to determine which strokes should be painted using shadow or highlight stokes, the paint portion of
Impressionist Paint creates a lambert shader, which is assigned a white color value. The script temporarily
applies the shader to the selected object. From this shader, the script creates a file texture storing composed
luminosity information for the object and the original shader is reassigned to the object. Figure 4.5
illustrates the file textures which are created through Impressionist Paint.
Figure 4.5 file textures
Since the file texture provides the luminosity values of the surface, each particle emitted maintains a
corresponding grayscale color value.
4.2.4 Prepaint Nodes and Attributes
The Prepaint portions of the script result in the creation and connection of the
nodes and attributes including the shadow node, closestPointOnsurface node, particle
groups, and emitters (see figure 4.6).
Figure 4.6 prepaint nodes
Once the Prepaint sections of the code are completed, the Paint procedures are called.
The paint portion of the code consists of three scripts. Collectively the scripts retrieve
variables set by the user to create the prescribed paint strokes.
4.3 Paint
Once the Prepaint sections are completed, the three scripts that make up the Paint
Procedure are called. Collectively the scripts retrieve variables set by the user to create
the desired paint stroke. The paint segment of the code places two layers of strokes on
the surface. As noted earlier, the first layer covers the object with mid-tones and the
second layer adds highlights and shadows. In order to increase the resemblance between
human painting actions and the exactness of a computer’s mathematical precision, the
following stroke and curve characteristics are individually emphasized:








placement
size
shape
imperfection
randomness
color
texture
stroke overlapping
4.3.1 Creating Curves
Curves are created according to the particle intersection position upon emission
from the object’s surface. The closestPointOnSurface node provides the UV coordinate
for the point on the surface which is closest to the emission point. The value returned
from the closestPointOnSurface node is used as the starting point of the curve; the U or V
value is incremented by adding the user specified distance to the original value along the
direction of the curve. Our associated $curve direction variable controls the placement of
the UV values to create either a vertical, horizontal, left diagonal, or right diagonal line.
The resulting curve length is determined by user input or random curve length.
The path of the curve is affected according to the values which the user input inside the
GUI. If the perturb value is greater than zero, the perturb amount is added to offset the
curve point form the path of the curve. Once the point has been drawn, the perturb
amount is subtracted from the new position and the user specified curve distance is then
added to the point position. The new value removes the offset and places the next curve
point on the correct path. Figure 4.7 illustrates this process in MEL code.
switch ($curvedirection){
case 1:
{
// creates a horizontal curve
U position += point distance;
V position += perturb value;
break;
}
case 2:
{
// creates a vertical line
V position += point distance;
U posiion += perturb value;
//Flag true to ensure U position is reset properly
$inc=1;
break;
}
case 3:
{
// creates a diagonal right line
U position -= point distance;
V position= V position + point distance + perturb
value;
break;
}
}
case 4:
{
//creates a diagonal left line
U position += point distance;
V position = V position + point distance + perturb
value;
break;
}
//switch
//U or V positions reset so the perturb amount only
//affects the specified curve points.
if ($inc==1)
U position-= perturb value;
else
V position-= perturb value;
Figure 4.7 Method used to determine line direction and curve position
The code uses the UV texture values, along with other information to build a string that
ultimately results in a Maya command string. This command string can then be executed
using the eval command to perform various tasks within our MEL Script.
The Maya command, curveOnSurface, creates curves on the exterior of the
surface. The properties of the curve created through the Maya command allow the user
to alter the curve’s position on the object, and to edit the control vertices, further
changing the curve’s shape and placement on the object. The ease in editing curves
allows for a greater addition of variance between specified strokes.
The definition of each curve is based on the NURBS parametric coordinates. The
new curve is selected and the curve is converted to a stroke using the
convertCurvesToStrokes command. Next, a stroke is attached to the curve. Then, a
unique brush node is attached to the stroke. The brush possesses over forty changeable
attributes which are originally set according to the user’s brush choice from the visor. In
Figure 4.8, the Hypergraph depicts the relationship of the object and the stroke.
Figure 4.8 object/stroke relationship.
4.3.2 Curve Variation and Uniqueness
This sequence of creating curves and strokes is repeated until the number of
strokes matches the number of emitted particles. As the number of curves increase, the
importance of curve variation also rises. The $perturb variable ensures the curve will be
drawn resembling the imperfect lines an artist draws. In figure 4.9, the left side illustrates
strokes drawn with no perturb value while the curves on the right side use a perturb value
to ensure line variation.
Figure 4.9 results of perturb values
Since the curve length may be random, the position of the curve that is to be
perturbed must be recalculated for each stroke. Figure 4.10 demonstrates how the
Perturb Position is calculated.
int $k=0; //place holder for particlepoint string
int $particlepoint[]; //determines the position of the
//point or points to be altered
switch ($perturbpos){
case 1: //perturbs the position at the
//beginning of a stroke
{
clear($particlepoint);
$particlepoint[0]= 1; //list of positions to
//be perturbed
break;
}
case 2: //perturbs the U or V position at the
//midpoint of a curve
{
$temppay = $curvelength/2;
$pay= `floor $temppay`;
clear($particlepoint);
$particlepoint[0]= $pay;
break;
}
case 3: //perturbs the end position of a curve
{
clear($particlepoint);
$particlepoint[0]= ($curvelength -1); //list of
//positions to be
//perturbed
break;
}
case 4: //perturbs the U or V position at the curves
//beginning and end
{
clear($particlepoint);
$particlepoint[0]= 1;
$particlepoint[1]= ($curvelength -1);
break;
}
}
for($m=0; $m<$curvelength; $m++){
if ($particlepoint[$k]= = $m){
//uses user input to determine the curve direction
float $direct= $perturbdir < 2 ? 1 : -1;
$perturb= $perturbamount * $direct;
}
else {
$perturb=0;
}
Figure 4.10 MEL code used to form intended inconsistencies in stroke positions
During the course of creating brush strokes, the number of strokes and curves
increases rapidly; therefore, we implemented a strong naming convention. The script
renames the new brush strokes according to the object’s name and the stroke number.
These strokes are placed into two groups: one for shadow and highlight strokes and the
other for the mid-tone strokes.
4.4 BrushAttr
Next, the BrushAttr script is called to set the stroke color. The color of the
particle used as the starting point for the curve is also used to determine the line color as
shown in figure 4.11.
Figure 4.11 The particle color determines the stroke color.
The particle color is based on the file texture assigned to the current object. This file
texture helps to automate the process of determining the assignment of stroke colors.
Figure 4.12 shows how diverse color schemes may be derived from two-dimensional
textures.
Figure 4.12 Two-dimensional textures allow for diverse color schemes.
Additionally, the file texture also increases similarities between colors that an
impressionist painter mixes and the computer-generated stroke colors by dictating
variations within the stroke color. In the traditional manner, the impressionist painters
allowed the viewer’s eye to visually mix the colors, but in computer graphics, additive
color mixing creates different color combinations. Figure 4.13 illustrates common
techniques for mixing colors using impressionist guidelines as shown in Impressionist
Landscape Painting [GRIF94].
Figure 4.13 Impressionist color-mixing techniques
The creation of the two dimensional texture is key to the believability of the
strokes. The method of sampling the texture creates a variation in the color of the strokes
that resembles the color changes found in a painting. Further, the diversity of the stroke
attributes assigned within the brush script creates a blending of colors and paint strokes.
Figure 4.14 shows that impressionist color mixing techniques can be replicated using file
textures.
Figure 4.14 file textures for color mixing
4.5 Shadow
The user determines how shadows are placed on each object within the scene, by
choosing to create the shadows once or on a per-frame basis. The length, style and
complexity of the animation play a role in determing the appropriate shading style. Each
of the two methods has its strengths and weaknesses.
4.5.1 Beginning Shadow Calculation Option
The first method promotes faster render times and is benefical if the character or
object does not undergo substantial lighting changes. For example, if an impressionist
woman is painted, and during the animation the woman walks under a tree, the shadows
are not accurate. For a simple animation, the user may save time by calculating the
shadows only once. In this case, the script is run on the first frame of the animation. The
file texture which is created, provides a map for three hundred and sixty degrees of
lighting, and remains accurate until the object moves drastically from the object’s
original position where the shading occurred. This shadow creation technique fails to
take into consideration extreme changes in lighting conditions; as mentioned above, the
shadows are only calculated one time at the beginning of the animation.
4.5.2 Constant Shadow Calculation Option
On the other hand, calculating shadows on a per frame basis helps to ensure
accuracy, yet the steps to determine shadow placement and color are time-consuming.
When updating shadow and highlight placement throughout the animation, a scriptNode
is created which activates the Shadow script before each frame renders. The shadows and
highlights remain accurate throughout vast degrees of movement and extreme lighting
changes. Choosing to update shadows slightly increases render time. Each time the
Shadow script is called any existing shadow strokes are deleted from the scene as are file
textures, which provide luminosity information. Then, shadows and highlights are
recalculated. New curves, which will be converted into strokes, are placed on the object.
Due to the unique properties of each stroke the repainting process creates visible stroke
movement on each object which adds to the painterly look of the work.
4.5.3 Calculating Shadow Colors and Placement
The derivation of the shadow color and placement is similar for both options.
Throughout this work we discuss the importance of creating unique strokes; however, a
great difference between the aesthetic qualities and positions of the strokes proves to be
distracting. The strokes created via the Shadow and highlight module are based on the
length, direction and width of the strokes drawn from the Mid emitter, as well as the
pertub amount, position, and direction of the original strokes.
As the particles are emitted from the object, each one is produced by the Hishad
emitter and tested to determine if the percentage of black in the particle color falls within
a user-set range that determines the level of shading. Particles falling outside of the two
user-defined ranges are ignored. If a particle falls within the user-defined range, the RGB
color value of the corresponding Ref particle determines the shadow color. Figure 4.15
demonstrates how the shadow color is derived.
global proc shadow(){
int
int
int
int
int
$j=1;
$testuv=0;
$csgfs=1;
$numparticles; //maximum number of particles per emitter
$imperfectstroke=1; //flag which denotes curve is to be
//perturbed
int $randomstrokelength=1; //flag which signals random curve lengths
int $scontrol=1; //flag determines if created curves are shadow or
//mid-tones
float $ct=50;
string
string
string
string
string
//current time
$ft="ft"; //name of file texture to be created
$shadowfiletex="";
$node; //shading node for current object
$revn="rev";
$sel= $shadobj;
SelectAllNURBSSurfaces;
string $shadlist[]=`ls -sl`; //stores list of selected objects
string $shadobj= $shadlist[0];
float $rf=`currentTime -q`; //return frame
for ($shadobj in $shadlist){
string $bsname="sstr";
string $ssgroup= ($shadobj + "shadgroup");
if (`objExists $ssgroup`){
//deletes shading strokes
delete $ssgroup;
}
$shadowfiletex=$shadobj + $ft;
if (`objExists $shadowfiletex`){
//deletes shadow file textures
delete $shadowfiletex;
}
//queries curve attributes to ensure similarities between
//mid-tone and shadow curves and strokes
float $curvelength= `getAttr ($shadobj + ".maxCurvePoint")`;
int $curvedirection= `getAttr ($shadobj + ".curveDirection")`;
float $sw= `getAttr ($shadobj + ".strokeWidth")`;
int $perturbpos= `getAttr ($shadobj + ".perturbPosition")`;
float $tempperturbamount= `getAttr ($shadobj + ".perturbAmount")`;
int $perturbdir= `getAttr ($shadobj + ".perturbDirection")`;
//returns shapeNode for selected object
string $selshape[]= `listRelatives $shadobj`;
string $tempselshape= $selshape[0];
$emitcontu=$sel + "|hishad"; //set current emitter to highshad
string $allNodes[]= `listConnections -type shadingEngine
$tempselshape`; //retuns shading engine of selected shape
$node= $allNodes[0];
// procedure call which creates luminosity file texture
textpart $sel $tempselshape $emitcontu;
//moves currentTime to zero
playButtonStart;
//forces dynamics to computer up to desired frame
runup -mxf $ct -cache;
//sets particle group to hishad
string $partsel= ($sel + "_hishad");
//gets number of particles being emitted from the current object
$numparticles= `getAttr ($partsel + ".count")`;
for ($n=0; $n<$numparticles; $n++){
//gets luminosity information from Hishad particle group
vector $colors = `partcolor $n $sel $testuv`;
float $colorR= ($colors.x);
$nvt=$colorR;
//calculate shadow color
if ($colorR < .20){
$testuv=2;
//get particle color from Ref particle group
vector $refcolor= `partcolor $n $sel $testuv`;
float $rcolorR= ($refcolor.x);
float $rcolorG= ($refcolor.y);
float $rcolorB= ($refcolor.z);
//calculate complemantary color using reverse node
setAttr ($revn + ".inputX") $rcolorR;
setAttr ($revn + ".inputY") $rcolorG;
setAttr ($revn + ".inputZ") $rcolorB;
float $tempr=`getAttr ($revn + ".outputX")`;
float $tempg=`getAttr ($revn + ".outputY")`;
float $tempb=`getAttr ($revn + ".outputZ")`;
vector $origcolor= `rgb_to_hsv <<$rcolorR, $rcolorG,
$rcolorB>>`;
vector $shadcolor= `hsv_to_rgb << $rcolorR,$rcolorG,$nvt>>`;
//store new shadow color values
$colorR= ($shadcolor.x);
$colorG= ($shadcolor.y);
$colorB= ($shadcolor.z);
Figure 4.15 Explanation of shadow color derivations
To calculate shadow strokes, the particle RGB color is first converted to the Hue
Saturation Value (HSV) color model which provides a simpler way to manipulate the
color properties. In additive color space, using the complementary color of the particle
color produces white instead of black for shadows due to additive color mixing
principles. To avoid the light color, the shadow color is computed as the average of the
original color and its complementary color. The average color falls halfway between the
opposing colors, and when mixed with the original color, forms a hue which mimics the
look of a the mixture of the complementary color and the original color using subtractive
color mixing. The new hue must be darker to create a convincing shadow color;
therefore, the value of the Hishad particle is used to derive the new color value since the
luminosity provides the correct value. The HSV color is then converted back to RGB
color and used as the shadow color. When the shadow stroke blends with the mid-tone
stroke, the shadow color resembles the color an impressionist painter may have used to
create a shadow.
The shadow stroke is created using the Hishad particle position and the color
derivation described above to create a colorful shadow. The particles for the starting point
of the shadow stroke fall in different locations than the mid-strokes. The strokes overlap,
therefore adding to the painterly feel of the rendered image. These two layers of strokes
also provide unique color combinations avoiding the harsh precision of computergenerated shadows.
4.5.4 Determining Highlight Color and Placement
If the grayscale value of the Hishad particle is less than the default ninety percent
(or a user designated value), the particle is used to create a brush stroke representing an
area which falls in the lightest portion of the object. The color of the stroke is based on
the current particle in the Ref particle array. Figure 4.16 depicts the color changes
implemented to create strokes which fall within the highlighted regions of the object.
//determines is area falls in highlight and determines color of highlight stroke
else if ($colorR > .90){
float $newsat= (1-$colorR);
select -r $Refparticleg;
partcolor $n;
vector $origsat= rgb_to_hsv <<$colorR,$colorG,$colorB>>;
vector $newcolor= hsv_to_rgb <<($origsat.x),$newsat,($origsat.z)>>;
$colorR= ($newcolor.x);
$colorG= ($newcolor.y);
$colorB= ($newcolor.z);
wherepart $partsel $n;
}
Figure 4.16 Technique for designating highlight stroke colors
Again, the color of the Ref particle is converted from RGB to HSV. The saturation value
of the reference color is replaced by the $newsat value, which is determined by
subtracting the Red color component value of the Hishad particle from one. Since the
RGB components for a particular shade of gray are all equal, we do not need to access the
green or blue values. The result is a lighter shade of the Ref particle. Finally the strokes
are painted as described with the mid tracker. Once the strokes have been added to the
object, the user can choose to add an individual stroke, add another layer of strokes, or to
edit the existing strokes.
4.6 Moving On - Animating the scene
Once the user is satisfied with the brush stroke coverage, the scene may be
animated. To better understand how to animate the scene, let us examine how the object
and strokes are organized. Figure 4.17 illustrates the object/stroke relationship created as
a result of using Impressionist Paint.
Figure 4.17 Object relationships
4.6.1 Understanding Stroke and Object Organization
Traditionally, Impressionist Painters avoided harsh outlines. Each brush stroke is
assigned a thickness and is placed on the exterior of each shape.
As shown in Figure 4.18, the brush strokes alter the shape of the object. The uneven
silhouette of the surface disrupts the smooth edges of the object, thus creating an
interaction between objects in image space. The edges of objects overlap and provide the
illusion of interacting paint strokes. Yet, stroke interpenetration from one object to
another may create undesired results. Additionally, the form of the object may be
obscured and intended details lost due to the close proximity of the surfaces and the size
of the competing strokes.
Figure 4.18 Alpha channels of an object before and after stroke application
Another issue to consider is that the volume of the paint strokes causes an
increase in the overall scale of the object. In order to account for the change in scale, the
pre-rendered surface must therefore either be modeled smaller or scaled once the addition
of strokes is completed. The object in figure 4.19 changes in proportions as a result of the
newly created strokes.
Figure 4.19 Proportion changes due to addition of painterly strokes
4.6.2 Scaling Objects
During an animation, changing the scale of an object does not alter the scale of
the brush strokes. The strokes will maintain the same position on the object, yet they
will appear smaller or larger in size depending on the new object size, and will sometimes
create empty areas in between the strokes. To avoid the holes in between the strokes,
each of the stroke groups that cover the object, along with the object must be selected
before scaling. This increases the global scale of the stroke, so the stroke size mirrors the
alteration of the object. The global scale of the object need only be altered when extreme
changes in scale are necessary. Re-sizing an object to offset the addition of strokes
requires no alterations in the global scale of the stroke.
Taking advantage of the stroke/object relationship allows the user to rig and
animate the object though traditional methods. The curve is parented to the object such
that changes to the transformation matrix of the object are inherited by the curve and by
the curve child, the stroke; therefore, when the object moves, the strokes follow. Since
Impressionist Paint incorporates Maya’s Paint Effects brushes, the strokes may be
animated using springs or forces. Alternatively, the curve animation may be scripted.
4.7 Voila, Rendering the Scene
Before the scene is rendered, the Impressionist Paint Script causes any previously
hidden brushstrokes to be shown. For a short time during the rendering process, the
objects appear to be unpainted. During rendering the paint strokes are added during
Maya’s post process.
Just as with non-stylized animations, the degree of complexity influences render
time. The greater the number of strokes and objects present in the scene, the longer the
frame takes to render.
4.8 Post-Processing
Once the scene is rendered, additional effects may be added to increase the
similarities between the computer-generated work and the impressionist style of paintings
produced by an artist. The role that the canvas plays in texture and color can be simulated
through using the texturizer in Photoshop to add a canvas filter to each frame. Other post
processing effects may be explored to further enhance the impressionistic effect.
Download