27: fish: lighting/rendering
Back to crowd/flocking/schooling or skip to compositing
Coming soon

seen from United States
seen from Taiwan
seen from Canada
seen from United States

seen from India
seen from Canada
seen from Australia
seen from United States

seen from United States
seen from United States

seen from Serbia
seen from Türkiye
seen from United States
seen from China
seen from China
seen from United States

seen from United States

seen from United States
seen from United States

seen from United States
27: fish: lighting/rendering
Back to crowd/flocking/schooling or skip to compositing
Coming soon
12: quick texture projection
Working with matte paintings or even just plate/cg interaction usually requires some amount of camera projections.
The steps for making a shader with a camera mapped texture are few and relatively simple, but if it's 5 clicks, then it's 4 too many... :)
So here's a script that lets you select objects and, based on the currect view pane's camera, sets up a surface shader with a camera projected texture.
Usage: Select meshes and click the shelf button to get a file browser dialog, select texture file, click ok. BAM!
So the first thing you do, is bring in your (3d tracked) camera with an image plane.
Build the geometry for the different elements in the plate.
If there's a 3d track I probably have a lot of tracking points in there that I can snap my objects/vertices to, but if it is a matte painting I usually start with a plane rotated 90 degrees in the X axis (or roughly aligned to the ground/walls/whatever in the plate I'm building) and then begin pulling vertices, adding edge loops, splitting polygons etc until it resembles the feature in the image plane that I'm building geometry for:
Once I have a good wireframe, matching the image plane from the camera view, then I start pulling large parts of the geometry around along the camera z axis (maintaining the relationship to the image as seen from the camera), and then vertex by vertex, to get the details in:
If you're using a matte painting you probably already have the different elements as seperate layers/image files. If it's a live action plate you might have seperate image sequences for foreground, mid ground, background, house, etc.. or you might not. It doesn't matter. But for each of the image files/sequences that you do have, select the associated geometry and run the script (from a shelf button - or from the script editor/command line):
global proc string assignProjMat(){ // we'll run a check to isolate only selected meshes (no locators, Nurbs curves or other non renderables) // for proper shading group assignment later. Might not be necessary, but I enjoy doing unnecessary stuff string $selAll[] = `ls -sl`; string $sel[] = {}; for ( $i=0; $i<size($selAll); $i++){ if (`nodeType $selAll[$i]` == "transform"){ string $shapes[] = `listRelatives -s -f $selAll[$i]`; if (`nodeType $shapes[0]` == "mesh" || `nodeType $shapes[0]` == "nurbsSurface" ){ $sel[size($sel)] = $selAll[$i]; } } } if (size($sel)){ $texDir = `workspace -q -fn` + "/sourceimages/*"; $texPath = `fileDialog -dm $texDir`; if ($texPath == ""){ string $epicFail = "Projection cancelled.\n"; return $epicFail; }else{ string $viewport = `getPanel -wf `; if ($viewport == "outlinerPanel1"){ $viewport = "modelPanel4"; } // figure which camera is being looked through in the current viewport string $curCam = `modelPanel -q -camera $viewport`; string $curCamShape[] = `ls -dag -shapes -ap $curCam`; string $projMat = `shadingNode -asShader surfaceShader -n projMat`; string $projSG = `sets -renderable true -noSurfaceShader true -empty -name ($projMat + "_SG")`; connectAttr -f ($projMat + ".outColor") ($projSG + ".surfaceShader"); string $proj = `shadingNode -asTexture projection`; setAttr ($proj + ".projType") 8; setAttr ($proj + ".fitType") 2; connectAttr -f ($curCamShape[0] + ".message") ($proj + ".linkedCamera"); string $projFile = `shadingNode -asTexture file -n "projFile"`; setAttr ($projFile + ".filterType") 0; setAttr -type "string" ($projFile + ".fileTextureName") $texPath; string $place3dTex = `shadingNode -asUtility place3dTexture`; connectAttr ($place3dTex + ".wim[0]") ($proj + ".pm"); connectAttr ($projFile + ".outColor") ($proj + ".image"); string $place2dTex = `shadingNode -asUtility place2dTexture`; connectAttr -f ($place2dTex + ".coverage") ($projFile + ".coverage"); connectAttr -f ($place2dTex + ".translateFrame") ($projFile + ".translateFrame"); connectAttr -f ($place2dTex + ".rotateFrame") ($projFile + ".rotateFrame"); connectAttr -f ($place2dTex + ".mirrorU") ($projFile + ".mirrorU"); connectAttr -f ($place2dTex + ".mirrorV") ($projFile + ".mirrorV"); connectAttr -f ($place2dTex + ".stagger") ($projFile + ".stagger"); connectAttr -f ($place2dTex + ".wrapU") ($projFile + ".wrapU"); connectAttr -f ($place2dTex + ".wrapV") ($projFile + ".wrapV"); connectAttr -f ($place2dTex + ".repeatUV") ($projFile + ".repeatUV"); connectAttr -f ($place2dTex + ".offset") ($projFile + ".offset"); connectAttr -f ($place2dTex + ".rotateUV") ($projFile + ".rotateUV"); connectAttr -f ($place2dTex + ".noiseUV") ($projFile + ".noiseUV"); connectAttr -f ($place2dTex + ".vertexUvOne") ($projFile + ".vertexUvOne"); connectAttr -f ($place2dTex + ".vertexUvTwo") ($projFile + ".vertexUvTwo"); connectAttr -f ($place2dTex + ".vertexUvThree") ($projFile + ".vertexUvThree"); connectAttr -f ($place2dTex + ".vertexCameraOne") ($projFile + ".vertexCameraOne"); connectAttr ($place2dTex + ".outUV") ($projFile + ".uv"); connectAttr ($place2dTex + ".outUvFilterSize") ($projFile + ".uvFilterSize"); connectAttr -force ($proj + ".outColor") ($projMat + ".outColor"); for ( $each in $sel){ select -r $each ; sets -e -forceElement $projSG; } select -r $proj; string $selList = ""; for ($each in $sel){ $selList = ($selList + $each + "\n"); } string $success = ("Objects assigned projection shader: \n" + $selList); return $success; } }else{ string $epicFail = "Nothing selected! Select mesh onto which you want to project.\n"; return $epicFail; } } string $result = `assignProjMat`; print $result;
Here's a quick demo of the workflow after geometry is built:
assignProjMat from Andre Hitsoy on Vimeo.
05: Assigning hold out material on $sel
Often we want to have certain objects act as a hold out object (for matting purposes). Basicly, what it means is assigning a shader that is black in both rgb and alpha. However, when you do this on several objects it can become a bit of a hassle, because just can't just assign, say, a black surface shader. Well, you can, but it probably means that it wont line up with the beauty pass, since the hold out shader doesn't have the corresponding displacement shader and as such, you'll end up with mismatching edges.
So what we'll do here is take the "holdOut_mat" (a black surface shader with matte opacity 0), or create it if it doesn't allready exist, find the existing displacement shader on the selected objedt, and for each selected object create and assign a shading group with the "holdOut_mat" as a surface material and connect the original displacement shader to the shading group's displacement mat attribute:
Here's what the scene looks like:
We'll assign a hold out material on the 3 balls on the back row:
// --------------- assign holdout material --------------------- global proc assignHOMat(){ string $sel[] = `ls -sl`; if (!`size($sel)`){ print "nothing is selected!\n"; }else{ string $shader = "holdOut_mat"; if (!`objExists $shader`){ $shader = `shadingNode -asShader surfaceShader -n "holdOut_mat"`; setAttr ($shader + ".outMatteOpacity") -type double3 0 0 0 ; } for ( $i=0; $i < size($sel) ; $i++ ){ string $shape[] = `listRelatives -s $sel[$i]`; string $exSG[] = `listConnections -type shadingEngine $shape[0]`; for ( $sg=0; $sg<size($exSG); $sg++){ string $exDispShader[] = `listConnections -type displacementShader $exSG[$sg]`; if (`size($exDispShader)` > 0){ string $newSG = `sets -renderable true -noSurfaceShader true -empty -name ($sel[$i] + "_holdOut_SG")`; connectAttr -f ($shader + ".outColor") ($newSG + ".surfaceShader"); connectAttr -f ($exDispShader[0] + ".displacement") ($newSG + ".displacementShader"); select -r $sel[$i]; sets -e -forceElement $newSG; print ($sel[$i] + " was assigned the holdOut material\n"); }else{ string $newSG = "holdOut_SG"; if (!`objExists $newSG`){ $newSG = `sets -r 1 -nss 1 -em -n ( "holdOut_SG")`; connectAttr -f ($shader + ".outColor") ($newSG + ".surfaceShader"); } select -r $sel[$i]; sets -e -forceElement $newSG; print ($sel[$i] + " was assigned the holdOut material\n"); } } } } select -r $sel; // reselect the original selection. } assignHOMat();
We now end up with this:
Note the preserved displacement on the middle ball. The alpha channel looks like this:
The holdOut shading network now looks like this:
The two non-displaced spheres are connected to the general "holdOut_SG" while the displaced one (sphere2) has its own shading group called "sphere2_holdOut_SG". They all share the same hold out surface shader.
This is a nice way of applying other shaders that require per object displacement textures as well, like other "utility" shaders (if you can't use passes) i.e. depth, lighting passes shaders, shadow catchers' shaders, ambient occlusion, etc.
.