Mod Tool

From OniGalore
Revision as of 10:14, 16 September 2012 by Paradox-01 (talk | contribs) (scripting: disabling logmessages)
Jump to navigation Jump to search

general information

Various modders of the community use "Autodesk Softimage Mod Tool". Usually we just call it "Mod Tool" or "XSI" (old name of the program).

Beside the free version, there's also the retail and student version "Autodesk Softimage [year]"

Those versions are also available as 64-bit versions.
If you are a student you can get Autodesk Software for free if your school is a partner of Autodesk.
In that case you can register with your email address given by your school.

But in the very most cases "Mod Tool" isn't really in disadvantage towards the retail version when it comes to modding Oni.

There's also the possibility to get files that extent Mod Tool's range of functions.

Those are scripts (*.vbs, js), toolbars (*.xsitb) and addons (*.xsiaddon).
They can be create on one's own and also shared with other users.


extensions

links


how to bind scripts to buttons (embedded code or .vbs / .js)

  • You can enable/disable the Main Shelf over "View" > "Optional Panels" > "Main Shelf". Then click the "Custom" tab.
  • A) Right-click the free gray space, click on "Customize Toolbar...". Select "Toolbar Widgets" > "Script Button".
  • Enter your code and make sure you selected the correct Scripting Language. Click okay when you are done.
  • B) You can also drag'n'drop your script file directly onto the free gray space.
  • A new window pops up, check the settings and click okay when done.
  • Right-click the Main Shelf and use the "Save" option. ("Save As" let you save the Main Shelf as toolbar file.)


how to install toolbars (.xsitb)

  • creation: goto "View" > "New custom toolbar"
  • Now you can add buttons like in Main Shelf. Remember to save your changes. (Right-click, "Save As".)
  • installation: Drag'n'drop the xsitb file onto the viewport (it's simply the window where you can see 3D objects).
  • access: goto "View" > "Toolbars"
  • deletion: goto "View" > "Manage..." Check a toolbar and click Delete button.
  • The file will remain with a new file suffix ".bak" You can restore this backup if you remove the ".bak" from the name.


how to install addons (.xsiaddon)

  • A) drag'n'drop the file into the so-called viewport (it's simply the window where you can see 3D objects), then restart Mod Tool
  • B) if drag and drop doesn't work, goto "File" > "Add-On" > "Install"
  • Then click on the "..." button to search for the file. When you found it, click the "Install" button.


building .xsiaddon

  • So far building an addon file seems to be the most difficult among those 'extension' files but for the end user it's best because it can hold all other files: toolbars, plugins, etc.

new notes [in progress]

  • so, simply putting scripts into folders didn't worked, they must be "plugins" (file extension is the same e.g. vbs but they do also something else)
  • a script can run on another computer if its content is found under a command, and plugin register that new command(s)
  • [...]

old notes

  • It Seems not to work with script file (but embedded code does), the alternate method (File > Add-On > Package... ) doesn't work at all with ModTool ... "Add-Ons cannot be created with Softimage Demo Version."
  • The problem with embedded code:
Let's say you want to integrate a toolbar into the xsiaddon file. The toolbar button was created as Script Button and holds: CreatePrim "Cube", "MeshSurface"
When using that button it will also call the cube's property page. Imagine what happens if you make a script that creates hundreds of objects. Right, the user would have to close all those property pages.
The property pages (PPG) will not open if the button was created as Script Command linking to an external script file. But xsiaddon seems unable to ship the script file's location as relative path. The relative path is needed because other user could have Mod Tool installed in a different location. What now?
ExecuteScript XSIUtils.ResolvePath("$XSI_USERHOME/") & "Addons\Oni_TRGV_tools\Application\Plugins\add_TV.vbs" This example use ExecuteScript to lunch a script file and XSIUtils.ResolvePath("$XSI_USERHOME/") to get the first part of it's location. The rest of the path depends how the author stores the files on the system where the addon was created.
That combination of embedded code and extern script file could create the cube without opening the PPG.


selected wisdom

We've also a tutorial thread on OCF.


camera navigation

  • move camera: [S]+[LClick]+[Moving_Mouse]
  • rotate camera: [S]+[RClick]+[Moving_Mouse]
  • zoom camera: [S]+[Scrolling]
  • reset view: [R]


mesh

  • extracting a polygon from an object: select polygon, right-click, "Extract Polygons (Delete)"
  • copying an polygon from an object: select polygon, right-click, "Extract Polygons (Keep)"
  • merging two objects: select one of them, goto Model>Modify>Poly.Mesh>Boolean>Union, select second object
(this makes a copy of the second object and attaches it to the first one, the merged objects must be freezed before the original second object can be removed)
  • filling a hole: select all edges surrounding the hole and choose one of the following methods
    • A) goto Model > Modify > Poly.Mesh > Weld Boundary Points/Edges
    • B) goto Model > Modify > Poly.Mesh > Bridge Boundary Points/Edges (if blue lines appear try to disable the checkbox "Angle > 90")
  • merging two objects at blue lines: merge the objects at first, then proceed with the point above "filling a hole"
  • hiding some polygons: select polygons and hit [H], use [Control]+[H] to unhide all
  • mirroring an object: select object, Edit > Duplicate/Instantiate > Duplicate Symmetry (center rotation might need to be changed afterwards)
  • working with symmetry mode
    • select object, Property > Symmetry Map (YZ/XZ/XY) (press [W] to preview symmetry plane)
    • click on Sym buttom (in Transform area) to enable/disable symmetry mode
    • changing the Symmetry plane: Explorer [8] > unfold object > Polygon Mesh > Cluster > delete SymmetryMapCls; then add a new symmetry plane


material and texture

  • objects use the scene material by default, objects need their own material if they should have individual textures
  • selecting a material and surface: Model>Material>Phong (simply close the windows that pops up)
  • connecting the texture with the material:
    • [7] to open Render Tree
    • in first column: "Texture"
    • in second column: drag'n'drop "Image" into the free space
    • click and hold the red point of "Image", then move it to "Phong" and release the mouse click
    • choose "diffuse" as illumination mode (for instance "ambient" won't work - the texture would be visible in Mod Tool but Onisplit can't use it)
  • now "Image" can be double-clicked (the Texture Editor will pop up), in the section "Image" click on "New" to choose an image


projection and UV

getting started

  • in section "Texture Projection" click on "New", choose a projection similar to the mesh shape (planar / cylindrical / cubic / spherical)
  • select the object
  • Texture editor: [Alt]+[7] (open it while being in selection mode "Object" or "Polygon", otherwise the UVs aren't shown)

modify single/all UVs

  • rotate 90°: [R]
  • rotate: [C]
  • scale: [X]
  • scale height only: [X], then [shift]+[MClick]+[move mouse]
  • scale length only: [X], then [shift]+[RClick]+[move mouse]
  • move: [V]
  • tearing single UV parts: [Control]+[T], then move [V]
  • heal (re-connect) selected UV parts: click on the plus symbol (the parts should be very near to each other, best if the points are on same spot)
  • snap function for move tool: Snap > Enable Snapping; check "Points" (if not already active)
  • relax (smooth warped UVs): [Control]+[R] (usually pressing several times that combination)
  • a new projection can also be applied to currently selected UV parts
  • freeze object to bake projections (green lines in the 3D view will disappear)
  • getting a picture of the UV: apply first a black texture then enter the Texture Editor [Alt]+[7], Edit > Stamp UV Mesh [Shift]+[S], save the texture


animating

  • preparing ModTool to save animations Oni can use: File > Preferences... > Preferences > Tools > Output Format > Frame Step: 1; Frame Format: Custom framerate; Frame Rate: 60
  • opening the Animation Editor : [0]
  • opening the DopeSheet: from any other Animation Editor, Editor > DopeSheet
  • making an animation shorter or longer: in DopeSheet click Region button (arrow with rectangle), click and hold to select keyframes, at selection edge a) [shift] plus left-click and move mouse or b) middle-click and move mouse


scripting

  • open the Script Editor: [Alt]+[4]
  • run the current code in the Script Editor window: [F5]
  • clear the log: Edit > Clear History Log
  • Actions from button embedded code will be logged.
  • Actions from code files that are linked in a button won't be logged. (This results in a performance boost.)
  • Logged stuff will be rewritten if you change the script language. (File > Preferences...)
  • You can also change the language by right-click the white script box and click on "Set to JScript" or "Set to VBScript".
  • Same way you can load a few code piece, e.g. "Syntax Help" > "If..Else" or "Catch Error".
  • Mark code you want to disable ("Comment Out") or enable ("Comment Remove").
  • You can save your code to a file via "File" > "Save As..." or "Save Selection"


links


notes about polygon extraction

  • a grid of 9 polygons (ID 0 to 8)
  • you extract the middle polygon (ID 4)
  • grid's polygon of ID 8 will change to ID 4
  • if you now extract 5th, the 7th gets the ID
  • now the ID order is: 0, 1, 2, 3, 6, 5, 4
  • this means that an automatic extraction of several polygons requires two changes in the code
  • 1) the ID array of selected polygons must be sorted
  • 2) the extraction must start with the last ID to avoid ID shift during the process (see code pieces)


some basics of VBScript

  • In VBS you declare variables only as a variant e.g. "dim PolygonCount". Mod Tool decides what type it becomes when it uses the variable the first time.
  • You can put "option explicit" at the start of your script. Then you will be forced to declare all variables with "dim". That looks quite unnecessary but help to find mistakes for example if you mistyped a variable somewhere in a long script.
  • The commands are not case-sensitive, e.g. you can write "LogMessage" or "logmessage".
  • Some common vbs functions can be found HERE.
' while it is possible to use + in strings,
' you should actually use & only for strings
' and + only for numbers

logmessage "How about ... " + "a riddle?"
logmessage "Where can you find following phrase in Oni? " & "The day is mine !!"
logmessage "Did you know that Bungie likes to hide sevens? The digits of the year 2032 add up to " & cstr(2 + 0 + 3 + 2) & "."

' INFO : How about ... a riddle?
' INFO : Where can you find following phrase in Oni? The day is mine !!
' INFO : Did you know that Bungie likes to hide sevens? The digits of the year 2032 add up to 7.


some ModTool commands in vbs language that might be interesting for Oni related stuff

Everywhere "logmessage" stands you can replace it with a variable (in that case don't forget the = sign.)

LogMessage [string | var] A command to log information. It requires a string or a variable. Example:
LogMessage "The object's name is: " & selection(0).Name
logmessage selection(0).Name Logs the object name.
logmessage selection(0).Material.Name Logs the material name.
logmessage selection(0).Material.CurrentImageClip.Name Logs the texture name. All "." inside the texture file name will be replaced by "_". Also a number might follow after the file suffix. Output example:
INFO : grid_part_8_tga4
logmessage selection(0).sclx.value Logs object's X scaling.
logmessage selection(0).scly.value Logs object's Y scaling.
logmessage selection(0).sclz.value Logs object's Z scaling.
logmessage selection(0).rotx.value Logs object's X rotation.
logmessage selection(0).roty.value Logs object's Y rotation.
logmessage selection(0).rotz.value Logs object's Z rotation.
logmessage selection(0).posx.value Logs object's X position.
logmessage selection(0).posy.value Logs object's Y position.
logmessage selection(0).posz.value Logs object's Z position.
logmessage selection(0).rotorder.value Logs object's rotation order. Oni characters have ZYX as rotation order.
0 = XYZ
1 = XZY
2 = YXZ
3 = YZX
4 = ZXY
5 = ZYX
SelectObj [string | var] select one or more objects. Comma serves as separator. Example:
SelectObj "grid,grid1"
ToggleSelection [string | var] Adds one or more objects from current selection. If the objects are already selected then they become subtracted from the selection. Example:
ToggleSelection "grid2,grid3"
SelectAllUsingFilter [SelFilter], [CheckComponentVisibility], [AffectSelectionList], [CheckObjectSelectability] Selects everything that matches the filter and other options. Example:
SelectAllUsingFilter "object", siCheckComponentVisibility
selects all roots, lights, cameras, and geometry (meshes)
SelectAllUsingFilter "geometry", siCheckComponentVisibility
selects all geometry (meshes)
DeselectAll deselects everything
DeleteObj [string | var] Deletes one or more objects. Comma used as separator. Example:
DeleteObj "grid"
DeleteObj "grid,grid1"
FreezeObj Makes all changes final. But saving those changes is still necessary. (Click on key symbol so it gets red.)
Translate [InputObjs], [X], [Y], [Z], [Delta], [RefMode], [Center], [AxesFilter], [Snap], [SnapReference], [SnapFilter], [SplitLocalComponents], [PropTagOnly], [Pivot], [PivotX], [PivotY], [PivotZ], [ConstructionMode], [SlideComponents] see link
Rotate [InputObjs], [X], [Y], [Z], [Delta], [RefMode], [Center], [AxesFilter], [Reference], [SplitLocalComponents], [PropTagOnly], [Pivot], [PivotX], [PivotY], [PivotZ], [ConstructionMode], [SlideComponents] see link


code pieces (VB Script)

Remember that you can use the search function of your web browser.

If you see absolute paths adapt them so that the code works on your system too.

[1] making an array [2] check selection mode [3] getting the IDs of selected polygons plus sorting them
[4] converting euler rotations (in degrees) to quaternions [5] converting quaternions to euler rotations (in degrees) [6] get and set values of the playcontrol (timeline)
[7] get keyframes [8] message box [9] input box
[10] getting the desktop path [11] selecting a folder [12] selecting a file of a specific type
[13] reading out environment variables [14] check if file exist [15] check if folder exist + create folder
[16] write xml file [17] create txt file + write lines [18] read txt file
[19] check onisplit version [20] call CMD, e.g. to use onisplit [21] building forms in ModTool
[22] UserDataBlob [23] getting the position of points (with selection mode point) [24] getting the position of points (with selection mode object)
[25] getting and setting the position of points (without selection) [26] getting the rotation and position of selected objects [27] getting the rotation and position of not selected objects
[28] decrypting merged integer flags [29] disabling PPG popups [30] disabling logmessages


' [1] making an array
' make some object, select them and run the code

dim y
y = selection.count

redim x (y - 1)
	' () sets the number of array items
	' use dim for an integer value
	' use redim if () contains a variable
 
for i = 0 to y - 1
	x(i) = selection(i).fullname
	logmessage x(i)
next

logmessage "counted objects: " & y


' [2] check selection mode 

checkfilter
'use sub to make use of the exit command

sub checkfilter
	Select Case Selection.Filter.Name
	'caution: case-sensitive

	Case "object"
		logmessage "object mode"
	Case "Edge"
		logmessage "edge mode"
	Case "Vertex"
		logmessage "point mode"
	Case "Polygon"
		logmessage "polygon mode"
	Case Else
		logmessage "Choose Object or Polygon selection mode."
		exit sub
	End Select
end sub


' [3] getting the IDs of selected polygons plus sorting them

poly_count = Selection(0).SubComponent.ComponentCollection.count
logmessage "poly_count: " & poly_count
redim selected (poly_count)
logmessage "Show ID as it is."
for i=0 to poly_count - 1
	' build ID array
	selected(i) = Selection(0).SubComponent.ComponentCollection(i).index
	logmessage selected(i)
next

' change sort order by replacing ">" with "<"
For i = 0 To poly_count - 1
	For j = 0 To poly_count - 1
		If selected(i) > selected(j) Then
			tmp = selected(i)
			selected(i) = selected(j)
			selected(j) = tmp
		End If
	Next
Next
logmessage "Show sorted ID."

for i=0 to poly_count - 1
	logmessage selected(i)
next


' [4] converting euler rotations (in degrees) to quaternions

dim x, y, z, dRotation, qRotation
x = 90
y = 0
z = 0

set dRotation = XSIMath.CreateRotation(XSIMath.DegreesToRadians(x), XSIMath.DegreesToRadians(y), XSIMath.DegreesToRadians(z)) 
set qRotation = XSIMath.CreateQuaternion() 

	dRotation.GetQuaternion (qRotation) 
	LogMessage qRotation.W
	LogMessage qRotation.X
	LogMessage qRotation.Y
	LogMessage qRotation.Z
	' INFO : 0,707106781186548
	' INFO : 0,707106781186547
	' INFO : 0
	' INFO : 0


' [5] converting quaternions to euler rotations (in degrees)

dim qW, qX, qY, qZ, qRotation, x, y, z

	qW = 0.707106781186548
	qX = 0.707106781186547
	qY = 0
	qZ = 0

set qRotation = XSIMath.CreateQuaternion (qW, qX , qY, qZ)

	qRotation.GetXYZAngleValues x, y, z
	logmessage XSIMath.RadiansToDegrees(x)
	logmessage XSIMath.RadiansToDegrees(y)
	logmessage XSIMath.RadiansToDegrees(z)
	' INFO : 89,9999999999999
	' INFO : 0
	' INFO : 0


' [6] get and set values of the playcontrol (timeline)

' timeline variables (tl)
dim tlStart, tlEnd, tlCurrent

' get values
tlStart = GetValue ("PlayControl.In")
tlEnd = GetValue ("PlayControl.Out")
tlCurrent = GetValue ("PlayControl.Current")

' set values
SetValue ("PlayControl.In"), 7
SetValue ("PlayControl.Out"), 70
SetValue ("PlayControl.Current"), 14


' [7] get keyframes


' [8] message box

msgbox "message", , "title"


' [9] input box

logmessage inputbox ("message", "title" , "pre-entered content")


' [10] getting the desktop path

' this can be useful for default locations like when selecting a folder
DesktopPath = CreateObject("WScript.Shell").SpecialFolders("Desktop")
logmessage DesktopPath


' [11] selecting a folder

' the default path is in this case my desktop
' to make it work on other systems, you would need the code of "getting the desktop path" section and replace my path with the DesktopPath
logmessage XSIUIToolkit.PickFolder("C:\Users\RMM\Desktop\", "title" )


' [12] selecting a file of a specific type

set oFileBrowser = XSIUIToolkit.FileBrowser
oFileBrowser.DialogTitle = "Select an image file (png/tga/jpg)" 
' (default folder)
oFileBrowser.InitialDirectory = "c:\"
oFileBrowser.Filter = "JPEG (*.jpg)|*.jpg|PNG (*.png)|*.png| Targa (*.tga)|*.tga||"
oFileBrowser.ShowOpen
If oFileBrowser.FilePathName <> "" Then
	logmessage "User selected " & oFileBrowser.FilePathName
Else
	logmessage "User pressed cancel"
End If


' [13] reading out environment variables

' some infos about env vars: (1), (2), (3)
' those variables are stored inside the setenv.bat, two disadvantages:
' adding or editing those vars appears to not work in vbs or I just did it wrong
' anyway, new vars can only be read out after app restart
' therefore let's concentrate on reading out existing ones and then how to create our own via txt files (example: Oni_env_vars.txt)
' code for reading out:
logmessage = XSIUtils.ResolvePath("$SI_HOME/")


' [14] check if file exist

Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists ("C:\folder\file.txt") then
	logmessage "File exists."
else
	logmessage "File doesn't exist."
end if


' [15] check if folder exist + create folder

dim strDirectory
strDirectory = "C:\test"

Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FolderExists(strDirectory) Then
   Set objFolder = objFSO.GetFolder(strDirectory)
   logmessage strDirectory & " already exists"
Else
   Set objFolder = objFSO.CreateFolder(strDirectory)
   logmessage "created folder " & strDirectory
End If


' [16] write xml file

FolderName = CreateObject("WScript.Shell").SpecialFolders("Desktop")
FileName = "test"
FilePath = FolderName & "\OBAN" & FileName & ".xml"

Set oFS = CreateObject("Scripting.FileSystemObject")
Set objXMLFile = oFS.OpenTextFile(FilePath, 2, True, 0)

' quote sign in a string needs two quote signs
objXMLFile.WriteLine "<?xml version=""1.0"" encoding=""utf-8""?>"
objXMLFile.WriteLine "<Oni>"
objXMLFile.WriteLine "..."


' [17] create txt file + write lines

txt_location = "C:\Softimage\Softimage_Mod_Tool_7.5\test.txt"
Set fso = CreateObject ("Scripting.FileSystemObject")
Set wText = fso.CreateTextFile (txt_location, 1)
wText.WriteLine "I'm a test file."
wText.WriteLine "Yo!"
wText.Close


' [18] read txt file

Set objFileToRead = CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\Softimage\Softimage_Mod_Tool_7.5\test.txt", 1)

do while not objFileToRead.AtEndOfStream
    strLine = objFileToRead.ReadLine()
    logmessage strLine
loop
' INFO : I'm a test file.
' INFO : Yo!

objFileToRead.Close
Set objFileToRead = Nothing


' [19] check onisplit version

Set objFSO = CreateObject("Scripting.FileSystemObject")
logmessage objFSO.GetFileVersion("F:\Program Files (x86)\Oni\Edition\install\onisplit.exe")

' result looks like this:
' INFO : 0.9.59.0


' [20] call CMD, e.g. to lunch onisplit or the game

' relative path

' the "GameDataFolder" isn't inside the "install" folder
' so we will use ..\ to go one folder backwards
'
' additional quote signs tells the program where the 
' paths strings start and end in case the path contains spaces

' if you are going to use the xml file right after its extraction (which is likely)
' then the "/wait" argument inside the onisplit_action string is important
' without it the code would continue and might try to read the not existing xml file and produce an error

onisplit_location = "F:\Program Files (x86)\Oni\Edition\install"
input_folder = """..\GameDataFolder\level19_Final\ONLVcompound.oni"""
output_folder = """..\GameDataFolder"""
onisplit_action = "cmd /C start /wait OniSplit.exe -extract:xml " & output_folder & " " & input_folder
logmessage "relative path: " & onisplit_action
' expected logmessage:
' INFO : relative path: cmd /C start OniSplit.exe -extract:xml "..\GameDataFolder" "..\GameDataFolder\level19_Final\ONLVcompound.oni"
XSIUtils.LaunchProcess onisplit_action, 1, onisplit_location


' absolute path

'adapt paths so it works on your computer
onisplit_location = "F:\Program Files (x86)\Oni\Edition\install"
input_folder = """F:\Program Files (x86)\Oni\Edition\GameDataFolder\level19_Final\ONLVcompound.oni"""
output_folder = """F:\Program Files (x86)\Oni\Edition\GameDataFolder"""
onisplit_action = "cmd /C start /wait OniSplit.exe -extract:xml " & output_folder & " " & input_folder
logmessage "absolute path: " & onisplit_action
' expected logmessage:
' INFO : absolute path: cmd /C start OniSplit.exe -extract:xml "F:\Program Files (x86)\Oni\Edition\GameDataFolder" "F:\Program Files (x86)\Oni\Edition\GameDataFolder\level19_Final\ONLVcompound.oni"
XSIUtils.LaunchProcess onisplit_action, 1, onisplit_location


' you can also lunch bat files

onibat = "cmd /C start run_wind.bat"
onilocation = "F:\Program Files (x86)\Oni\Edition"
XSIUtils.LaunchProcess onibat, 0, onilocation
' alternative to cmd: call onisplit directly via winmgmts

' slightly modified code from that site
' logmessage "onisplit finished." will be executed after the conversion finished, there should be also an delay of 3 seconds to support very slow computers 
' if you are going to use this method consider to extent the code to check if input file and output directory exist
osp_loca = "C:\OniAE\Edition\install\OniSplit.exe"
osp_action = "-extract:xml"
osp_output = """C:\OniAE\Edition\GameDataFolder"""
osp_input = """C:\OniAE\Edition\GameDataFolder\level1_Final\AKEVEnvWarehouse.oni"""
osp_total = osp_loca & " " & osp_action & " " & osp_output & " " & osp_input
logmessage osp_total

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objWMIService.Create osp_total, null, null, intProcessID
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

' wait 3 second to find event - should be enough time for single actions on a slow computer
Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _
    ("Select * From __InstanceDeletionEvent Within 3 Where TargetInstance ISA 'Win32_Process'")

Do Until i = 1
    Set objLatestProcess = colMonitoredProcesses.NextEvent
    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then
        i = 1
    End If
Loop
logmessage "onisplit finished."
' now you can work with the extracted xml file


' [21] building a form (PPG)


UserDataBlob_tn.png
' [22] UserDataBlob

' you can attach data to objects, e.g. new properties for the scene root or Oni Trigger Volumes
' the so-called "UserDataBlob" can't be saved in *.dae, so save the whole scene to keep your progress
'
' check if my property exist
found_my_prop = 0
set oProps = ActiveProject.ActiveScene.Root
logmessage "root name: " & ActiveProject.ActiveScene.Root
for each prop in oProps.Properties
	' remove apostroph in line beneath to log all root properties
 	'LogMessage prop.Name
	if instr(1, prop.Name, "my_prop") = 1 then
		found_my_prop = 1
	end if
next

' prop doesn't exist, create it
if found_my_prop = 0 then
	' create property (must also have content, in this case "yes")
	oProps.AddProperty( "UserDataBlob", , "my_prop" ).value = "yes"
	logmessage "created my new prop"
end if

' prop exists, change/read its value
if found_my_prop = 1 then
	' change property
	oProps.Properties( "my_prop" ).value = "no"

	' read property
	logmessage oProps.Properties( "my_prop" ).value
	' if you want to read a property from another script be sure that it was already created
	' reuse code under "check if my property exist"
end if


' [23] getting the position of points (with selection mode point)

' a point must be selected
' gets xyz position of first selected point of the first selected object
logmessage Selection(0).SubComponent.ComponentCollection(0).position.x
logmessage Selection(0).SubComponent.ComponentCollection(0).position.y
logmessage Selection(0).SubComponent.ComponentCollection(0).position.z


' [24] getting the position of points (with selection mode object)

' an object must be selected
' gets xyz position of point 0 of the first selected object
logmessage selection(0).activeprimitive.geometry.Points(0).Position.x
logmessage selection(0).activeprimitive.geometry.Points(0).Position.y
logmessage selection(0).activeprimitive.geometry.Points(0).Position.z


' [25] getting and setting the position of points (without selection) right after object creation

' point positions are relative to the object's center
' to get the absolute point positions add center to point
' to set the absolute point positions subtract center from point

set oRoot = application.activeproject.activescene.root
set oObj = oRoot.addgeometry( "Cube", "MeshSurface", "test" )

' to test our code move center to somewhere else
Translate oObj, 9, 11, 13, siRelative, siGlobal, siCtr, siXYZ, , , , , , , , , , 0
SaveKey oObj & ".kine.local.posx," & oObj & ".kine.local.posy," & oObj & ".kine.local.posz", 1, , , , True

FreezeObj oObj
set oGeometry = oObj.activeprimitive.geometry
aPositions = oGeometry.Points.PositionArray
' get old position
'                                         (xyz, point)
logmessage "old point 0 posx: " & aPositions(0, 0) + GetValue(oObj & ".kine.global.posx")
logmessage "old point 0 posy: " & aPositions(1, 0) + GetValue(oObj & ".kine.global.posy")
logmessage "old point 0 posz: " & aPositions(2, 0) + GetValue(oObj & ".kine.global.posz")

' set new position
aPositions(0, 0) = -7 - GetValue(oObj & ".kine.global.posx")
aPositions(1, 0) = -7 - GetValue(oObj & ".kine.global.posy")
aPositions(2, 0) = -7 - GetValue(oObj & ".kine.global.posz")

' update the array
oGeometry.Points.PositionArray = aPositions
' get new position
logmessage "new point 0 posx: " & aPositions(0, 0) + GetValue(oObj & ".kine.global.posx")
logmessage "new point 0 posy: " & aPositions(1, 0) + GetValue(oObj & ".kine.global.posy")
logmessage "new point 0 posz: " & aPositions(2, 0) + GetValue(oObj & ".kine.global.posz")

' INFO : old point 0 posx: -4
' INFO : old point 0 posy: -4
' INFO : old point 0 posz: -4

' INFO : new point 0 posx: -7
' INFO : new point 0 posy: -7
' INFO : new point 0 posz: -7


' [26] getting the rotation and position of selected objects

logmessage "mesh name: " & selection(0)
logmessage selection(0).rotx.value
logmessage selection(0).roty.value
logmessage selection(0).rotz.value
logmessage selection(0).posx.value
logmessage selection(0).posy.value
logmessage selection(0).posz.value


' [27] getting the rotation and position of not selected objects

' GetValue("NAME.kine.global.rotx")
' NAME must be the exact mesh name
' let's say you want the data of one chracter's pelvis
logmessage GetValue("pelvis.kine.global.rotx")
logmessage GetValue("pelvis.kine.global.roty")
logmessage GetValue("pelvis.kine.global.rotz")
logmessage GetValue("pelvis.kine.global.posx")
logmessage GetValue("pelvis.kine.global.posy")
logmessage GetValue("pelvis.kine.global.posz")


' [28] decrypting merged integer flags

' for example the BINACJBOTrigger Volume.xml file has flags as strings for the <Flags> tag
' and integer values for the <Teams> tag whereby the values are merged to one value
' so if <Teams> tag holds "101" we have to think what flags it holds, the flags can be broken down with following code

' x: hypothetical value of <Teams>
x=101
' 101 = 64 + 32 + 4 + 1

x_255
sub x_255
	if x > 255 then
		msgbox "Flags bigger than 255 are not allowed.", ,"error"
		exit sub
	end if
	if x >= 128 and x <= 255 then
		logmessage "128"
		x = x - 128
	end if
	if x >= 64 and x < 128 then
		logmessage "64"
		x = x - 64
	end if
	if x >= 32 and x < 64 then
		logmessage "32"
		x = x - 32
	end if
	if x >= 16 and x < 32 then
		logmessage "16"
		x = x - 16
	end if
	if x >= 8 and x < 16 then
		logmessage "8"
		x = x - 8
	end if
	if x >= 4 and x < 8 then
		logmessage "4"
		x = x - 4
	end if
	if x >= 2 and x < 4 then
		logmessage "2"
		x = x - 2
	end if
	if x = 2 then
		logmessage "2"
		x = x - 2
	end if
	if x = 1 then
		logmessage "1"
		x = x - 1
	end if
	if x = 0 then
		logmessage "finished check"
	end if
end sub

' INFO : 64
' INFO : 32
' INFO : 4
' INFO : 1
' INFO : finished check


' [29] disabling PPG popups

' if a script creates numerous objects in one go the same number of property pages (PPG) can appear
' for user convenience that PPG popups can be disabled 

' disable PPG popup
Preferences.SetPreferenceValue "Interaction.autoinspect", false

' creates the cube mesh but no PPG will show up
CreatePrim "Cube", "MeshSurface"

' enable PPG popup again
Preferences.SetPreferenceValue "Interaction.autoinspect", true


' [30] disabling logmessages

' msglogverbos is probably already set to false by default
' could be set at the start of a final script to increase performance
setvalue "preferences.scripting.msglogverbose", false
setvalue "preferences.scripting.msglog", false


script ideas

  • drag and drop support for specific xml/oni files
  • autoheal discontinuities (blue lines) of overlaying edges (for repairing google sketchup objects that weren't yet textured)
  • making loops from parts of animations
  • copying animation data from one character to another

The following sections are about ideas that are checked right now for their possibility of realization or already in the making.


trigger volumes export/import
exported warehouse TVs
TRGV_Oni_to_ModTool_tn.png
  • Oni to ModTool
    • conversion of oni to xml [done]
    • import of TV collection [done]
    • adding a new TV [done]
    • transparent textures for TVs [-]
    • TV properties form (PPG) [done]
  • ModTool to Oni [done]
  • xsiaddon file [-]


new door animations

creating new door animations

After a few experiments onisplit v0.9.54.0 seems to output XYZ-W instead of XYZW.

Example:

				X	Y	Z
Rotation in Mod Tool		40	0	0
--------------------------------------------------------------
				X	Y	Z	W
Q.Rotation in Mod Tool		0,342	0	0	0,939	
--------------------------------------------------------------
				X	Y	Z	-W
Q.Rotation onispl. v54		0,334	0	0	-0,94


Following code is "WIP", it gets quaternions and write them into an OBAN*.xml

It wasn't tested yet and will probably need some tweaks to meet Oni's door orientation. Also, OBAN flag "ZAxisUp" needs some more investigation.


hierarchy builder for characters
hierarchy breaker beta
hierarchy_breaker_beta_tn.png

(Automatic rigging.) Maybe null objects could stand for the centers of body parts. Then one click and the real centers gets positioned. The rotations are known and the names would lead to the correct hierarchy.

In order to make edits there is also a need of destroying the hierarchy again while preserving the rotation and position of the meshes.


code pieces


hierarchy breaker


hierarchy builder


keyframe affects hierarchy building

situation: "cube" and "cube1" were created

  • case 1:
    • apply 45° y rotation to cube
    • make cube1 a child of cube
    • cube1 will not inherit the 45°
  • case 2:
    • apply 45° y rotation to cube
    • make rotation keyframe for cube1
    • make cube1 a child of cube
    • cube1 inherit the 45°
  • case 3:
    • apply 45° y rotation to cube
    • make rotation keyframe for cube1
    • remove that keyframe again
    • make cube1 a child of cube
    • cube1 inherit the 45°
  • case 4:
    • apply 45° y rotation to cube
    • make rotation keyframe for cube1
    • remove that keyframe again
    • make cube1 a child of cube
    • save both cube to a dae file
    • make new scene and load dae
    • make cube1 a child of cube
    • cube1 will not inherit the 45°

Case 1 might be a bug (case 4 is a variant of it) but it simplify the hierarchy creation.


While doing those test you can observe red letters next to the meshes in the Schematic window.

A means the presence of keyframes. Removing the keyframe doesn't remove the A. Object must be saved and reloaded.
D means that mesh center was changed by rotation or translation (center mode) or by clicking Transform > Freeze(...). D can be removed by clicking the normal Freeze button. Yea, whatever...
C can be seen next to camera objects, present when Camera_Interest is horizontal attached to it.