+ All Categories
Home > Documents > Christopher Evans Technical Art Lead, Crytek Responsibilities: Artist in R&D Pipeline tools ...

Christopher Evans Technical Art Lead, Crytek Responsibilities: Artist in R&D Pipeline tools ...

Date post: 28-Dec-2015
Category:
Upload: harvey-elliott
View: 219 times
Download: 1 times
Share this document with a friend
57
Transcript

Christopher EvansTechnical Art Lead, Crytek

Responsibilities: Artist in R&D Pipeline tools Character technology Digital Janitor

Mathias LindnerTechnical Animator, Crytek

Responsibilities 3rd Person Human Animations Animation Tools Motion Capture

What is this stuff? A look at some scripted tools

development at Crytek.

Beginner Maxscript Tutorial Using example code from tools at

Crytek We started our maxscript journey

from scratch

Crysis Scripted Tool Examples A close look at the Animation

tools/pipeline

Intended Audience Beginner to Advanced

Code examples in slides for beginners

Tool videos/source online for advanced

Technical Artists/Animators Anyone who wants to work

faster and better in 3dsMax

Session Overview CryTools Background Beginner Tutorial

Easy Street Basics Loops Animation

Transformations User Feedback Hacking with DOS

Production Examples

Session Overview Animation Tools

Structure Function definitions Motion Capture Cleanup

CryTools: Background In the beginning: 2006

No scripted tools No previous Maxscript experience (MEL) Pipeline/Architecture built from scratch

Current: 2008 14k+ of lines of code used by artists/animators across 3 studios 2 main contributors

Scripts load from latest build on local machine Can also sync via Perforce/LAN/Http

Modular design based on users Rigging, Animation, Art

CryTools: Background

Tools are freely available as part of the CryEngine2 ModSDK SDK:

http://www.crymod.com/filebase.php?fileid=1074&lim=0

Easy Street: The Basics

Do Not Store Global Variables

To store things globally, make global struct

--my scripttest = "hellow world“print test--total noob

--my script( test = “hellow world” print test)--hardened veteran

Easy Street: Not so Basic(But Important!)

--creating the structstruct _myTools_( fn function1 = (return "myFunction1"), fn function2 = (return "myFunction2"), var1,var2,var3)

--instance your structmyTools = _myTools_()

--testing your structmyTools.function1()"myFunction1"myTools.var1 = "storeMe"Print myTools.var1"storeMe"

Easy Street: The Basics

Use the Listener/Macro recorder

Maxscript docs rock (go Bobo!) Read other people’s scripts

www.scriptspot.com Use the Debugger!

Easy Street: The Basicsshowproperties $bone .width : worldUnits .height : worldUnits .taper : percent .length : float . . . .

showinterface layerManager Interface: LayerManager Properties: .count : integer : Read .current : Interface : Read Methods: <Interface>getLayer <integer>which <Interface>newLayer() . . . .

Easy Street: Loops

for i=1 to 4 (m += 2)

for item in array do (print item.x)

for obj in selection do (append obj array)

for obj in $C3D* do (obj.parent = $node)

for i=1 to (polyOp.getNumVerts obj) do( append locations (polyOp.getVert obj i))

Easy Street: Loops

--sometimes you want to start laterss = SplineShape pos:(obj.position.keys[1].value)addNewSpline ssfor i = 2 to obj.position.keys.count do( addKnot ss 1 #corner #line obj.position.keys[i].value)

--or end soonerfor i=1 to (items.count-1) do( rotBind items[i] root 0 0 180 false)rotBind items[items.count] root 0 0 180 true

Easy Street: Simplification

for obj in selection do( if (classof obj) == Sphere then ( if obj.wirecolor == red do ( obj.pos.z += 10 ) ))

Easy Street: Simplification

for obj in selection do( if (classof obj) == Sphere then ( if obj.wirecolor == red do ( obj.pos.z += 10 ) ))

Easy Street: Where!

for obj in selection where (classof obj) == Sphere and obj.wirecolor == red do

( obj.pos.z += 10)

--another example, this puts all spheres into an array called ‘spheres’spheres = for obj in selection where (classof obj) == Sphere collect obj

Easy Street: Loop Examples

--if a selected object had a turbosmooth modifier change it’s prefsfor obj in selection do( if (obj.modifiers[#turbosmooth] != undefined) do ( obj.modifiers[#turbosmooth].iterations = 1 obj.modifiers[#turbosmooth].useRenderIterations = true obj.modifiers[#turbosmooth].renderIterations = 2 ))

Easy Street: Nested Loops

--this removes bones in an array from a skin modifierfor u=1 to remBones.count do( for i=1 to (skinOps.getNumberBones obj.skin) do ( if (skinOps.GetBoneName obj.skin i 0) == remBones[u].name then ( skinOps.removeBone obj.skin i print ("removing " + remBones[u].name) ) ))--how can we simplify?myBones = for i=1 to skinOps.GetNumberBones obj.skin collect \ --cont next line (skinOps.GetBoneName obj.skin i 0)for i=1 to remBones.count where (finditem myBones remBones[i]) != 0 do(

skinOps.removebone obj.skin (finditem myBones remBones[i]))

--stepping through frameswith animate on( for i = animationrange.start to animationrange.end do ( slidertime = i obj.pos.x += 10 ))

--same as above, but much fasterwith animate on( for i = animationrange.start to animationrange.end do ( at time i (obj.pos.x += 10) ))

Easy Street: Animation/Time

fn cutString stringIn cut =( startCut = (findString stringIn cut) return (replace stringIn startCut cut.count ""))

--simple usagecutString “chicks dig technical artists” “ technical”“chicks dig artists”

--more complex(getnodebyname ((cutString obj.name "C3D:") \+ "_bone")).pos.controller = Position_XYZ()

Easy Street: Functions

--returns an array containing all childrenfn getChildren theNode =( nodeArray = #() for obj in theNode.children do ( append nodeArray obj join nodeArray (getChildren obj) ) return nodeArray)

Easy Street: Self Referencing

$.transform(matrix3 [1,0,0] [0,1,0] [0,0,1] [23.1612,0.667526,0]) [-----orientation-----] [-----position-----]

--maxscript cannot set parts of a transform like so:$.transform[1] = [1,0,0]--but this will work:new = $.transformnew[1] = [1,0,0]$.transform = new

Transformations

Transformations: Dealing with Biped

--let’s get the position of a biped objectprint $'Bip01 Head'.position-- Unknown property: "position" in $Editable_Mesh:Bip01 Head @ [-25.684864,-37.348450,118.445419]

--fail, ok let’s check out what properties does haveshowproperties $'Bip01 Head'false

--again: fail… when all else fails, go the transformprint $'Bip01 Head'.transform.position[-25.6849,-37.3484,118.445]

a = 5b = aa += 2print b5

a = "ftw"b = aa[3] = a[1]a[1] = "w"print b"wtf“

--this is because of how subsets are stored in memory

--for data-types that are groups of items (strings, arrays, etc) use ‘copy’ instead, example:b = copy a

Other tips: Variables

Other tips:--try/catchtry (print $.name)catch(print “nothing selected”)

--reach into rollout floaters to pass varsmyTool.rollouts[1].variable

--create undosUndo "make point" on( point name:"test")

--is an object animated?obj.isAnimated

--getting a position at a certain timeprint (at time 11f obj.pos)

Altogether:Better User Feedback

On checkbutton changed state do( if state == true then ( if selection != undefined then ( objs = (selection as array) checkbutton.text = (objs.count as string + “ objs selected”) ) else ( messagebox “No objects selected” checkbutton.checked = false ) ) else ( checkbutton.text = “Select Objects” ))

--sample ui in course materials

Altogether:Better User Feedback

On checkbutton changed state do( if state == true then ( if selection != undefined then ( objs = (selection as array) checkbutton.text = (objs.count as string + “ objs selected”) ) else ( messagebox “No objects selected” checkbutton.checked = false ) ) else ( checkbutton.text = “Select Objects” ))

--sample ui in course materials

Altogether:Better User Feedback

try ( throw "This will be the name of your error")catch ( messagebox (getCurrentException()))--you could also use this to write out error logs on remote machines, have people send them to you when they get an error (or automatically send it)

Hacking Things in DOS

DOSCommand [command <string>] CryTools has a silent command line fn

crytools.scmd [command <string>] [wait? <bool>]

Many general uses Moving files Perforce, AlienBrain Glean info from ipconfig (domain, ip, MAC) Get external info Run small executables

Hash generator

Building/Executing external scripts VBS/Python

DOS Example 1: Simple

--This function will make a file writable, I use this a lot before writing to files.

fn minusR path = (

if doesfileexist path == true then(

doscommand ("attrib -r \"" + path + "\"“))else(

print (path + " does not exist"))

)

Getting info from DOS

First figure out the DOS command Dump generated text to a file with

‘>’

Then look at it’s output Figure out how you want to parse it

Getting info from DOS Then look at it’s output

Figure out how you want to parse it

DOS Example 2: Output

fn local2unc letter =

(

cmd = ("net use " + letter + ": > " + sysInfo.tempDir + “cmd.txt")

doscommand cmd

loadIn = openfile (sysInfo.tempDir + "local_unc.txt")

skipToString loadIn "Remote"

loadInARR = (filterString (readline loadIn) " ")

close loadIn

doscommand ("del " + sysInfo.tempDir + "local_unc.txt")

return loadInARR[2]

)

local2unc "s"

"\\storage\Builds"

local2unc "k"

"\\fs1\Artists"

DOS Example 2: Output fileC:\Documents and Settings\christopher\Local Settings\Temp\

cmd.txt

Local name S:

Remote name \\storage\Builds

Resource type Disk

Status Disconnected

# Opens 0

# Connections 1

The command completed successfully.

--tidbit from experience: people install DOS in different languages ;)

Callbacks! Do things based on user input

Always remember to unregister!

fn myFn =( theFaces = 0 for obj in selection do (theFaces += obj.mesh.numfaces) print theFaces)

--registercallbacks.addScript #selectionSetChanged "myFn()" id:#myFn

--unregistercallbacks.removeScripts id:#myFn

CryTools: Examples

Transfer Facial Morphs [ transfer_morphs.avi ]

Mirror Morphs/Deformation [ mirrorMorphs.avi ]

Hierarchy to Bones [ hierarch2bones.avi ]

Hierarchy Tools [hierarchy_tools.avi]

CryInfo [ cryinfo.avi ]

In Closing

Maxscript helped immensely on Crysis

Scripting is a slippery slope One day you write a script to help

someone, the next it’s your job :) Screw efficiency

If something works, and is fast… let it be.

Refactoring can be dangerous CryTools has a lot of ‘beginner code’, but

very few tools that take longer than an eyeblink to execute.

Animation Tools

Overview

Structure How we used structures

Function definitions How we used functions

Motion Capture Cleanup Problems and solutions

Animation Tools

Structures Are declared in global scope Initialized with defined values Structure name is self-explaining Good for instancing variables in a structured way Behave a bit like classes Used about 60 different structures

Examplestruct pivotSelSt ( index = 0, position = [0,0,0], pivObject )struct bipPartSt(

object,part,name,pivotSel = ( pivotSelSt pivObject = undefined )

)

Animation Tools

Function definitions Structure placeholder will be overwritten by

function Global functions get removed Function name is self-explaining

Example

cryTools.cryAnim.getBipNames = function getBipNames index =

(...

)getBipNames = undefined

Animation Tools

cryTools.cryAnim.getBipNames = function getBipNames index =

(...

)getBipNames = undefined

Advantages Easy to maintain (for development) No need to look at local scope of functions Function can be defined outside of the structure

Disadvantages Functions will be duplicated once = more time to load

Animation Tools

Motion Capture Cleanup Problems we encountered

Slow workflow for Animators (lots of repeated clicks)

Bad for health and time management

Too technical to achieve code requirements Animators had trouble to get used to constant

changes

No feedback when something went wrong Endless time spent with debugging

Animation Tools

Motion Capture Cleanup Solutions:

Everything repetitive needs to be gone Packed functions executed at once Designed tools to speed up the animation

process

Powerful User Interface Self-explaining functionality Compact set of tools

Animation Tools

Motion Capture Cleanup Everything repetitive needs to be

gone:

One Click Solutions Simple scripts just for the purpose No user interface needed

Examples: Set planted keys for biped (video)

Copy Paste Transformations (video)

Animation Tools

Motion Capture Cleanup Everything repetitive needs to be gone:

Batch process for animations(video)

Use of different file formats Sub folder support File mask Execute scripts to solve different problems Status report

Motion Capture Cleanup Powerful User Interface:

Goals:

Fast production of assets Compact functionality in one place

Animator should not care about technical things

Solutions for complex bone behavior

User Customization Animator can change the look and functionality of

dialogs

Animation Tools

Motion Capture Cleanup Powerful User Interface - Solutions:

Fast production of assets

Fast loading and saving of assets(video)

Load files directly out of the production folder Export files into the game

Using snapshots for foot alignment(video)

Speed up hand and foot cleanup How it works (video)

Animation Tools

Motion Capture Cleanup Powerful User Interface - Solutions:

Animators should not care about technical things

Locomotion Locator animation (video) Used for linking the animation to the character in-

game In some cases complex behaviour

Weapon / Item adjustment (video) Specific bones to carry weapons / items in the game Rotation and position can change for each item

Animation Tools

Motion Capture Cleanup Powerful User Interface - Solutions:

User Customization

No hardcoded values / states

Dialog should represent the needs of Animators

Easy to add new elements

Animation Tools

Motion Capture Cleanup Powerful User Interface - Solutions:

Animation Tools

Normal Multi Row

(video)

Thank you for your attention

Questions?

Full Source of Examples at:www.ChrisEvans3D.com/files/fmx08.r

ar

Crytools/Source at:www.ChrisEvans3D.com/files/crytools

.rar

Should be up by 12/05/08

Questions or comments via email?

Christopher [email protected]

Mathias [email protected]


Recommended