21
edits
Paradox-01 (talk | contribs) m (i forgot, it was in that version) |
(Update notice w/ summary) Tags: Mobile edit Mobile web edit |
||
| (93 intermediate revisions by 3 users not shown) | |||
| Line 1: | Line 1: | ||
{{update|This article contains links to the now defunct Oni Central Forum. Sections: Selected Wisdom}} | |||
Autodesk's Mod Tool used to be the main choice for modders when working on level and character models (at least in Windows, since it's Windows-only). It was a free and accessible program, but has long since been discontinued. Nowadays, modders are encouraged to use [[Blender]] instead. | |||
{| class="wikitable" style="float:right;" | |||
|width="200px"| | |||
: | ;sub pages | ||
: | : [[Mod_Tool/Scripting]] | ||
: | : [[Mod_Tool/Rigging]] | ||
: [[Mod_Tool/OniTools_addon]] | |||
: [[Mod_Tool/Oni_level_rebuilder]] | |||
|} | |||
==Installation== | |||
Full name: "Autodesk Softimage Mod Tool". Usually we just call it "Mod Tool" or "XSI", the old name of the program. | |||
'''Download''' | |||
* '''Get it from [https://www.moddb.com/downloads/autodesk-softimage-mod-tool-75 Mod DB].''' | |||
* It's no longer possible to download Softimage from Autodesk because the [https://www.autodesk.com/products/softimage/overview software was discontinued] by Autodesk in favor of their major software packages Maya and 3ds Max. | |||
''' | '''Newer Windows installations usually require .NET 2.0 to be installed before the XSI installer can fully run.''' | ||
: Downloading and installing .Net 2.0 manually from the internet might not work. | |||
: '''Therefore use the Windows search and look for "features".''' (Enable/disable Windows features.) | |||
: From the Windows feature page install '''".NET framework 3.5 (includes .NET 2.0 and 3.0)"'''. | |||
There are various ways to extend Mod Tool's range of functions: scripts (.vbs, .js), toolbars (.xsitb) and addons (.xsiaddon). They can be created on one's own and also shared with other users. | |||
==Extensions== | ===Extensions=== | ||
'''links''' | '''links''' | ||
* [ | * [https://www.si-community.com/community/viewtopic.php?f=35&t=796 "Roadkill" UV Tool] | ||
* [http://www.xsidatabase.com/content/drag_and_drop_obj_files_jscript drag and drop support for OBJ files] | * [http://web.archive.org/web/20121001104022/http://www.xsidatabase.com:80/content/drag_and_drop_obj_files_jscript drag and drop support for OBJ files] | ||
* [ | * [https://www.si-community.com/community/viewtopic.php?f=35&t=797 OBJ exporter] | ||
* [http://mods.oni2.net/node/210 OBJ + OFGA exporter] for Oni | * [http://mods.oni2.net/node/210 OBJ + OFGA exporter] for Oni | ||
** might need the regular OBJ exporter to be installed first | ** might need the regular OBJ exporter to be installed first | ||
* [http://mods.oni2.net/node/210 adjusting existing fw throws] [ | * [http://mods.oni2.net/node/210 adjusting existing fw throws] [https://www.youtube.com/watch?v=vDTPYfvMf4M (instructions)] | ||
| Line 54: | Line 58: | ||
''' | '''building add-ons (<nowiki>http://softimage.wiki.softimage.com/sdkdocs/cus_addons_WalkthroughBuildinganAddon.htm</nowiki>, dead link)''' | ||
* Building an add-on file needs more effort than the other 'extensions' but for the end user it's best because it can hold all other files: toolbars, plugins (scripts), etc. | * Building an add-on file needs more effort than the other 'extensions' but for the end user it's best because it can hold all other files: toolbars, plugins (scripts), etc. | ||
** The user can install a newer version of the addon by repeating the installation with the new file: it's unnecessary to remove the old version. | ** The user can install a newer version of the addon by repeating the installation with the new file: it's unnecessary to remove the old version. | ||
| Line 146: | Line 150: | ||
end if | end if | ||
end function | end function | ||
==Selected wisdom== | ==Selected wisdom== | ||
We've also a [http://oni.bungie.org | We've also a [http://oni.bungie.org/forum/viewtopic.php?id=1229 tutorial thread on OCF.] | ||
Hotkey list can be found [http://www.keyxl.com/aaacbe0/415/SoftImage-XSI-keyboard-shortcuts.htm here]. | Hotkey list can be found [http://www.keyxl.com/aaacbe0/415/SoftImage-XSI-keyboard-shortcuts.htm here]. | ||
| Line 189: | Line 192: | ||
** B) goto Model > Modify > Poly. Mesh > Bridge Boundary Points/Edges (if blue lines appear try to disable the checkbox "Angle > 90") | ** 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" | * merging two objects at blue lines: merge the objects at first, then proceed with the point above "filling a hole" | ||
* '''merging two objects with UVs''': Create > Poly. Mesh > [http://cryrid.com/images/temp/XSI/merge_materials.jpg Merge] | * '''merging two objects with UVs''': Create > Poly. Mesh > [https://web.archive.org/web/20160225163131/http://cryrid.com/images/temp/XSI/merge_materials.jpg Merge] | ||
** extracted Oni characters have their materials and hence textures directly grouped under the mesh (see Explorer) | ** extracted Oni characters have their materials and hence textures directly grouped under the mesh (see Explorer) | ||
** when adding (merging) a new part to the existing mesh, the materials/textures will be grouped under (Explorer again) mesh > Polygon Mesh > Clusters > ... | ** when adding (merging) a new part to the existing mesh, the materials/textures will be grouped under (Explorer again) mesh > Polygon Mesh > Clusters > ... | ||
| Line 245: | Line 248: | ||
===Material and texture=== | ===Material and texture=== | ||
[[Image:apply_new_main_texture_in_Mod_Tool.png|thumb|200px|right|how to apply a new main texture]] | |||
[[Image:apply_new_polygon_cluster_texture_in_Mod_Tool.png|thumb|200px|right|how to apply a new polygon cluster texture]] | |||
* objects use the scene material by default, objects need their own material if they should have individual textures | * 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) | * selecting a material and surface: Model > Material > Phong (simply close the windows that pops up) | ||
| Line 254: | Line 259: | ||
** 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) | ** 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 | * now "Image" can be double-clicked (the Texture Editor will pop up), in the section "Image" click on "New" to choose an image | ||
* to change textures '''don't drag and drop textures directly one meshes''', this creates textures layers which are ignored by OniSplit | |||
| Line 276: | Line 282: | ||
* freeze object to ''bake'' projections (green lines in the 3D view will disappear) | * 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 | * 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 | ||
Things to test: | |||
* https://vimeo.com/67783125 | |||
===Rendering=== | |||
Rendering doesn't work well on my PCs.--[[User:Paradox-01|paradox-01]] ([[User talk:Paradox-01|talk]]) 01:09, 9 March 2016 (CET) | |||
Especially PNG, it works one time. But as soon as I import another dae the next render will fail. | |||
So, for creating a object library we might use blender. Nice thing is, it can also render in the background when called from CMD. This means you could keep working in XSI and render images in blender at the same time. | |||
example of a batch file: | |||
cd C:\Program Files\Blender Foundation\Blender | |||
blender -b --python C:\Users\Paradox-01\Desktop\blender-out\pythonScript.py | |||
example of a render script: | |||
import bpy | |||
# delete blender default cube object | |||
bpy.ops.object.mode_set(mode='OBJECT') | |||
bpy.ops.object.select_by_type(type='MESH') | |||
bpy.ops.object.delete(use_global=False) | |||
# load new object | |||
bpy.ops.wm.collada_import(filepath = "C:/Oni/r.dae") | |||
# render settings | |||
bpy.data.scenes['Scene'].render.resolution_x = 900 | |||
bpy.data.scenes['Scene'].render.resolution_y = 900 | |||
# default resolution percentage seems to be 50 | |||
bpy.data.scenes['Scene'].render.resolution_percentage = 100 | |||
bpy.data.scenes['Scene'].render.use_antialiasing = True | |||
# 5 | 8 | 11 | 16 | |||
bpy.data.scenes['Scene'].render.antialiasing_samples = "8" | |||
#TGA IRIS JPEG MOVIE IRIZ RAWTGA | |||
#AVIRAW AVIJPEG PNG BMP FRAMESERVER | |||
#no gif ? could be created by more code, maybe merging single frames of jpgs | |||
bpy.data.scenes['Scene'].render.image_settings.file_format = 'JPEG' | |||
bpy.data.scenes['Scene'].render.image_settings.quality = 100 | |||
# file suffix is overwritten by file_formate | |||
#bpy.data.scenes['Scene'].render.filepath = 'C:/Oni/renders/test.jpg' | |||
bpy.data.scenes['Scene'].render.filepath = 'C:/Oni/renders/test' | |||
# start render | |||
bpy.ops.render.render( write_still=True ) | |||
===Animating=== | ===Animating=== | ||
[[Image:Scale_animations_in_Mod_Tool_Animation_Editor_DopeSheet.png|thumb|200px|right|an animation that got scaled down from 116 to 58 frames]] | |||
* preparing ModTool to save animations Oni can use: File > Preferences... > Preferences > Tools > Output Format | * preparing ModTool to save animations Oni can use: File > Preferences... > Preferences > Tools > Output Format | ||
** Frame Step: 1 | ** Frame Step: 1 | ||
** Frame Format: Custom framerate | ** Frame Format: Custom framerate | ||
** Frame Rate: 60 | ** '''Frame Rate: 60''' | ||
* for real-time playback click on "Playback" option button and then "Real-Time Playback" | * for real-time playback click on "Playback" option button and then "Real-Time Playback" | ||
* opening the Animation Editor : [0] | * opening the Animation Editor : [0] | ||
* opening the DopeSheet: from any other Animation Editor, Editor > DopeSheet | * 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 | * '''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 | ||
====Issues when saving and sharing animation files (*.dae, *.exp)==== | |||
That what you currently see in Mod Tool and that what you get when saving data can be different. | |||
1) *.dae files might save data differently than expected. | |||
''Rotation flips'' might appear. | |||
2) *.exp and *.dae save data differently. | |||
*.exp files store the frames as they are. | |||
* | |||
* | |||
* | |||
*.dae file store their actions (rotations/translation/...) in seconds and eventually depend on what framerate a Modder uses. | |||
'''Following scenario: a modder wants to share an animation as *.exp and another modder wants to use that animation.''' | |||
Modder A uses 30 fps in his settings and exports an *.exp that is 58 frame long. | |||
* | |||
Modder B uses 60 fps in his setting and imports the *.exp, to his surprise the animation is 116 frames long. What now? | |||
If Modder B saves the *.exp under a new name would not help, the frames will be still the same. | |||
* | |||
Instead Modder B could scale the animation. The way to do so is described in the [[#Animating|Animating]] section, "making an animation shorter or longer". | |||
Modder B scales the animation and saves it as dae. | |||
Now he wants to see if it worked. He opens a new scene [Strg]+[N] and loads the dae. | |||
'''Summary of issue-holding aspects''' | |||
* '''Frames Per Second (FPS)''' | |||
When you share *.dae files with other Modders be sure that the output formate is 60 fps. Different framerates among modders can cause confusion. | |||
Dae file store their actions (rotation/translation/...) in seconds. | |||
An example: | |||
<float_array count="10" id="pelvis_rotation_x_ANGLE-anim-input-array"> | |||
0.000000 0.166833 0.333667 0.500500 0.600600 0.934267 1.267933 1.601600 1.768433 1.935267 | |||
</float_array> | |||
action at [s] * framerate [f/s] = frame [f] | |||
In this example the last rotation occurs at 1.935267s. | |||
: | |||
: Modder A uses 30 fps, his last frame is 58. | |||
: | : Modder B uses 60 fps, his last frame is 116. | ||
: | |||
* '''Euler rotations''' | |||
you will get [[wikipedia:Bézier_curve|BEZIER]] (cubic) interpolation instead of LINEAR if you use | |||
: "Convert Quarternion Rotation to Euler" | |||
: "Spline Interpolation" in the animation (fcurve) editor | |||
Those smooth the rotations. | |||
[...] | |||
''' | * '''Quaternion rotations''' | ||
Don't use this. | |||
[...] | |||
* '''Make Rotation Keys Continuous''' | |||
[...] | |||
====Animation mixer==== | |||
This could help with creating cutscenes and complex animations (e.g. run cycles for FILM files). | |||
Open the animation mixer with [Alt]+[0]. | |||
Further information over [http://web.archive.org/web/20170103065301/http://softimage.wiki.softimage.com/xsidocs/nla_mixer.htm#Rdw10200 HERE.] | |||
Here are a few videos: | |||
* '''https://www.youtube.com/watch?v=-xC31Q7zpM0''' | |||
* https://www.youtube.com/watch?v=njLrAIpDOFU | |||
: | * https://www.youtube.com/watch?v=PRDZaEo5CGo | ||
=====Sounds===== | |||
Within the animation mixer also sounds can be added. | |||
Further information over [http://web.archive.org/web/20170102120711/http://softimage.wiki.softimage.com/xsidocs/audio_LoadingAudioFilesintheAnimationMixer.htm#Rdy36984 HERE.] | |||
This could be used to synchronize sounds effect with physical actions in the scene. | |||
===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". | |||
* Python can be added as script language if you install it on your PC. | |||
* Right-clicking the white script box gives you also access to 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''' | |||
* [http://web.archive.org/web/20160803061035/http://softimage.wiki.softimage.com/index.php?title=Scripting_Tips_and_Tricks_%28XSISDK%29 xsi wiki page about scripting] | |||
* '''[http://web.archive.org/web/20170616035120/http://softimage.wiki.softimage.com/sdkdocs/scriptsdb/scriptsdb/scrdb_vbscript.htm many vbscript examples]''' | |||
* '''[https://ss64.com/vb/ vbs commands]''' | |||
* [https://web.archive.org/web/20070510173452/https://www.activexperts.com/activmonitor/windowsmanagement/adminscripts/filesfolders/files/ objFSO/objWSHShell: Scripts to manage Files] (replace "Wscript.Echo" with "logmessage") | |||
: | * [https://web.archive.org/web/20150504221146/http://activexperts.com/activmonitor/windowsmanagement/adminscripts/other/textfiles/ objFSO/objWSHShell: Scripts to manage Text Files] | ||
* [http://web.archive.org/web/20080905102848/http://www.kxcad.net/softimage_xsi/Softimage_XSI_Documentation/script_basics_IncludingExternalScripts.htm using external scripts] | |||
* [https://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=si_om/XSIUIToolkit.html,topicNumber=si_om_XSIUIToolkit_html progress bar and open file dialog<!-- (hm, InitialDirectory code for quick save idea ?)-->] | |||
<!--* [http://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=files/cus_ppg_FileBrowserWidget.htm,topicNumber=d30e11980,hash=WS34BA39B437A993419C80CAB58E3BEFA1-0059 text box]--> | |||
'''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". | |||
* Vbs functions can be found [https://web.archive.org/web/20150707131602/https://www.w3schools.com/vbscript/vbscript_ref_functions.asp 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. | |||
'''More tips''' | |||
* You can replace each "logmessage" with a variable. In that case don't forget the = sign. | |||
* Selection(0) means that from all selected objects the first one is taken. | |||
* Use a loop to get all objects. | |||
for each n in selection | |||
logmessage n | |||
next | |||
* In order to shorten the code you might want to set script objects. | |||
: The command to create a standard cube is ''CreatePrim "Cube", "MeshSurface"'' | |||
: If you use '''''set name = ''''' the cube or other object will be available under that ''name''. | |||
: Then you can use any valid method or property with that ''name''. | |||
: Example: | |||
set c = CreatePrim ("Cube", "MeshSurface") | |||
| | |||
| | logmessage selection(0).name | ||
| [ | logmessage selection(0).length.value | ||
| | logmessage c.name | ||
| | logmessage c.length.value | ||
| | |||
' INFO : cube | |||
' INFO : 8 | |||
' INFO : cube | |||
' INFO : 8 | |||
'''Some ModTool commands in vbs language that might be interesting for Oni related stuff''' | |||
{| class="wikitable" width="100%" | |||
| width=50% valign=top | LogMessage <nowiki>[string | var | object]</nowiki> | |||
| A command to log information. It requires a string or a variable. Example: | |||
: LogMessage "The object's name is: " & selection(0).Name | |||
|- | |- | ||
| | | logmessage selection.count | ||
| | | Logs the number of selected objects. | ||
| | |- | ||
| logmessage selection(0).Name | |||
| Logs the object name. | |||
|- | |- | ||
| | | logmessage selection(0).Materials(0).Name | ||
| Logs the material name. | |||
| | |||
|- | |- | ||
| | | logmessage selection(0).Materials(0).Library.name | ||
| | | Logs the material library name. | ||
|- | |- | ||
| | | logmessage selection(0).Materials(0).shaders(0).name | ||
| | | Logs the material shader (e.g. phong). | ||
|- | |- | ||
| | |valign=top| logmessage selection(0).Materials(0).CurrentImageClip.source.filename.value | ||
| | | Logs absolute path of the texture. Output example: | ||
: ''C:\Users\RRM\Desktop\TV_tex.png'' | |||
|- | |- | ||
| | |valign=top| logmessage selection(0).Materials(0).CurrentImageClip.source.Parameters("XRes").Value<br>logmessage selection(0).Material.CurrentImageClip.source.Parameters("YRes").Value | ||
| | | Logs the horizontal (X) and vertical (Y) pixel length of the texture. Output example: | ||
| | : ''512'' | ||
|- | |||
| logmessage selection(0).sclx.value<br>logmessage selection(0).scly.value<br>logmessage selection(0).sclz.value | |||
|valign=top| Logs object's scaling (X, Y, Z). | |||
|- | |||
| logmessage selection(0).rotx.value<br>logmessage selection(0).roty.value<br>logmessage selection(0).rotz.value | |||
|valign=top| Logs object's rotation (X, Y, Z). | |||
|- | |||
| logmessage selection(0).posx.value<br>logmessage selection(0).posy.value<br>logmessage selection(0).posz.value | |||
|valign=top| Logs object's position (X, Y, Z). | |||
|- | |||
|valign=top| 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 | |||
|- | |||
|valign=top| SelectObj <nowiki>[string | var]</nowiki> | |||
| select one or more objects. Comma serves as separator. Example: | |||
: SelectObj "grid,grid1" | |||
|- | |||
|valign=top| ToggleSelection <nowiki>[string | var]</nowiki> | |||
| 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" | |||
|- | |||
|valign=top| [https://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=si_cmds/SelectAllUsingFilter.html,topicNumber=si_cmds_SelectAllUsingFilter_html SelectAllUsingFilter] <nowiki>[SelFilter], [CheckComponentVisibility], [AffectSelectionList], [CheckObjectSelectability]</nowiki> | |||
|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 | |||
|- | |||
|valign=top| DeleteObj <nowiki>[string | var]</nowiki> | |||
| 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.) | |||
|- | |||
| [https://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=si_cmds/Translate.html,topicNumber=si_cmds_Translate_html Translate] <nowiki>[InputObjs], [X], [Y], [Z], [Delta], [RefMode], [Center], [AxesFilter], [Snap], [SnapReference], [SnapFilter], [SplitLocalComponents], [PropTagOnly], [Pivot], [PivotX], [PivotY], [PivotZ], [ConstructionMode], [SlideComponents]</nowiki> | |||
| see link | |||
|- | |||
| [https://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=si_cmds/Rotate.html,topicNumber=si_cmds_Rotate_html Rotate] <nowiki>[InputObjs], [X], [Y], [Z], [Delta], [RefMode], [Center], [AxesFilter], [Reference], [SplitLocalComponents], [PropTagOnly], [Pivot], [PivotX], [PivotY], [PivotZ], [ConstructionMode], [SlideComponents]</nowiki> | |||
| 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. | |||
([[Mod_Tool/Scripting|Here]]'s another page for math related code pieces.) | |||
{| class="wikitable" width="100%" | |||
|width=33%| [1] creating and extending an array | |||
|width=33%| [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] read xml file | |||
| [18] read xml file (attribute/content-based) | |||
|- | |||
| [19] create txt file + write lines | |||
| [20] read txt file | |||
| [21] check onisplit version | |||
|- | |||
| [22] call CMD, e.g. to use onisplit | |||
| [23] building forms in ModTool | |||
| [24] UserDataBlob | |||
|- | |||
| [25] getting the position of points (with selection mode point) | |||
| [26] getting the position of points (with selection mode object) | |||
| [27] getting and setting the position of points (without selection) | |||
|- | |||
| [28] getting the rotation and position of selected objects | |||
| [29] getting the rotation and position of not selected objects | |||
| [30] decrypting merged integer flags | |||
|- | |||
| [31] disabling PPG popups | |||
| [32] disabling logmessages | |||
| [33] getting bounding box values | |||
|- | |||
| [34] open an explorer window | |||
| [35] working with hierarchies | |||
| [36] drag and drop (DnD) support for specific oni files | |||
|- | |||
| [37] dae export | |||
| [38] fbx export | |||
| [39] import an image clip only once | |||
|- | |||
| [40] layers | |||
| [41] onisplit update | |||
| [42] get vertex color | |||
|- | |||
| [43] get all used textures | |||
| [44] get global point position | |||
| | |||
|} | |||
' '''[ | ' '''[1] creating and extending an array''' | ||
' creating an array | |||
' () sets the number of array items | |||
redim nums (3) | |||
for i = 0 to 3 | |||
nums(i) = (i) | |||
next | |||
logmessage "output all items" | |||
for each n in nums | |||
logmessage n | |||
next | |||
logmessage "first array item holds: " & lbound(nums) | |||
logmessage "last array item holds: " & ubound(nums) | |||
logmessage "-------------------------------------" | |||
' extending an array | |||
' use "preserve" to keep the old content | |||
' find next higher value | |||
plus_one = ubound(nums) + 1 | |||
redim preserve nums (plus_one) | |||
nums(plus_one) = 4 | |||
for each n in nums | |||
logmessage n | |||
next | |||
logmessage "first array item holds: " & lbound(nums) | |||
logmessage "last array item holds: " & ubound(nums) | |||
' | ' INFO : output all items | ||
' INFO : 0 | |||
' INFO : 1 | |||
' INFO : 2 | |||
' INFO : 3 | |||
' INFO : first array item holds: 0 | |||
' INFO : last array item holds: 3 | |||
' INFO : ------------------------------------- | |||
' INFO : 0 | |||
' INFO : 1 | |||
' INFO : 2 | |||
' INFO : 3 | |||
' INFO : 4 | |||
' INFO : first array item holds: 0 | |||
' INFO : last array item holds: 4 | |||
' '''[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 "unknown 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 | |||
logmessage | |||
' 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) | |||
logmessage | 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''' | ||
' | ' keyframe counting code like "selection(0).rotx.Source.Keys.count" will produce an error if no keys exist | ||
' to | ' that's why we need to catch possible errors for each counting | ||
on error resume next | |||
logmessage "--------------------------------------------------" | |||
logmessage "X rotation keys: " & selection(0).rotx.Source.Keys.count | |||
for each k in selection(0).rotx.Source.Keys | |||
logmessage "index: " & k.index & " // time: " & k.time & " // value: " & k.value | |||
next | |||
if err <> 0 then | |||
logmessage "no X rotation keys" | |||
end if | |||
on error goto 0 | |||
on error resume next | |||
logmessage "--------------------------------------------------" | |||
logmessage "Y rotation keys: " & selection(0).roty.Source.Keys.count | |||
for each k in selection(0).roty.Source.Keys | |||
logmessage "index: " & k.index & " // time: " & k.time & " // value: " & k.value | |||
next | |||
if err <> 0 then | |||
logmessage "no Y rotation keys" | |||
end if | |||
logmessage " | on error goto 0 | ||
on error resume next | |||
logmessage "--------------------------------------------------" | |||
logmessage "Z rotation keys: " & selection(0).rotz.Source.Keys.count | |||
for each k in selection(0).rotz.Source.Keys | |||
logmessage "index: " & k.index & " // time: " & k.time & " // value: " & k.value | |||
next | |||
if err <> 0 then | |||
logmessage "no Z rotation keys" | |||
end if | |||
on error goto 0 | |||
on error resume next | |||
logmessage "--------------------------------------------------" | |||
logmessage " | logmessage "X position keys: " & selection(0).posx.Source.Keys.count | ||
for each k in selection(0).posx.Source.Keys | |||
logmessage " | logmessage "index: " & k.index & " // time: " & k.time & " // value: " & k.value | ||
next | |||
if err <> 0 then | |||
logmessage "no X position keys" | |||
end if | end if | ||
on error goto 0 | |||
on error resume next | |||
logmessage "--------------------------------------------------" | |||
logmessage "Y position keys: " & selection(0).posy.Source.Keys.count | |||
for each k in selection(0).posy.Source.Keys | |||
logmessage "index: " & k.index & " // time: " & k.time & " // value: " & k.value | |||
next | |||
if err <> 0 then | |||
logmessage "no Y position keys" | |||
end if | |||
on error goto 0 | |||
on error resume next | |||
logmessage "--------------------------------------------------" | |||
logmessage "Z position keys: " & selection(0).posz.Source.Keys.count | |||
for each k in selection(0).posz.Source.Keys | |||
logmessage "index: " & k.index & " // time: " & k.time & " // value: " & k.value | |||
next | |||
if err <> 0 then | |||
logmessage "no Z position keys" | |||
end if | |||
on error goto 0 | |||
' output example (0 rot keys, 2 pos keys): | |||
' INFO : -------------------------------------------------- | |||
' INFO : no X rotation keys | |||
' INFO : -------------------------------------------------- | |||
' INFO : no Y rotation keys | |||
' INFO : -------------------------------------------------- | |||
' INFO : no Z rotation keys | |||
' INFO : -------------------------------------------------- | |||
' INFO : X position keys: 2 | |||
' INFO : index: 0 // time: 2 // value: 5,14534318031942 | |||
' INFO : index: 1 // time: 6 // value: 8,2411504340802 | |||
' INFO : -------------------------------------------------- | |||
' INFO : Y position keys: 2 | |||
' INFO : index: 0 // time: 2 // value: 0,365325291829147 | |||
' INFO : index: 1 // time: 6 // value: 1,11923927115289 | |||
' INFO : -------------------------------------------------- | |||
' INFO : Z position keys: 2 | |||
' INFO : index: 0 // time: 2 // value: 1,96103417177471 | |||
' INFO : index: 1 // time: 6 // value: 1,88564277384233 | |||
' '''[8] message box''' | |||
[https://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=si_om/XSIUIToolkit.MsgBox.html,topicNumber=si_om_XSIUIToolkit_MsgBox_html 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: [http://web.archive.org/web/20170309190841/http://softimage.wiki.softimage.com/xsidocs/config_envirovars.htm (1)], [http://web.archive.org/web/20180416194626/http://softimage.wiki.softimage.com/xsidocs/EnvVars_SettingandUsingEnvironmentVariables.htm (2)], [http://web.archive.org/web/20170617095054/http://softimage.wiki.softimage.com/xsidocs/EnvVars_EnvironmentVariableReference.htm (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: <nowiki>https://dl.dropbox.com/u/139715/OniGalore/ModToolScript/Oni_env_vars.txt Oni_env_vars.txt</nowiki> (dead link)) | |||
' 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 | |||
' | ' ### or simply: | ||
dir = "C:\test" | |||
XSIUtils.EnsureFolderExists (dir) | |||
' | |||
' '''[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 "..." | ||
objXMLFile.Close | |||
' '''[17] read xml file''' | |||
Set xmlDoc = CreateObject( "Microsoft.XMLDOM" ) | |||
xmlDoc.Async = "False" | |||
path = "C:\Users\RRM\Oni\AE\AEInstaller\vanilla\level19_Final\BINACJBOWeapon.xml" | |||
xmlDoc.Load( path ) | |||
Set colPosition = xmlDoc.selectNodes( "Oni/Objects/WEAP/Header/Position" ) | |||
Set colRotation = xmlDoc.selectNodes( "Oni/Objects/WEAP/Header/Rotation" ) | |||
Set colClass = xmlDoc.selectNodes( "Oni/Objects/WEAP/OSD/Class" ) | |||
loop_count = xmlDoc.selectNodes( "Oni/Objects/WEAP").length | |||
logmessage "found " & loop_count & " weapons:" | |||
logmessage "================" | |||
for i=0 to loop_count - 1 | |||
'split string into pices as array, space is used as seperator by default | |||
'element 0 = X; element 1 = Y; element 2 = Z | |||
pos = split(colPosition.item(i).text) | |||
rot = split(colRotation.item(i).text) | |||
' | ' Mod Tool wants comma instead of point for decimal seperator | ||
pos(0) = replace (pos(0), ".", ",") | |||
pos(1) = replace (pos(1), ".", ",") | |||
pos(2) = replace (pos(2), ".", ",") | |||
rot(0) = replace (rot(0), ".", ",") | |||
rot(1) = replace (rot(1), ".", ",") | |||
rot(2) = replace (rot(2), ".", ",") | |||
logmessage colClass.item(i).text | |||
logmessage pos(0) & " " & pos(1) & " " & pos(2) | |||
logmessage rot(0) & " " & rot(1) & " " & rot(2) | |||
logmessage "----------------" | |||
next | next | ||
' INFO : | ' INFO : found 2 weapons: | ||
' INFO : | ' INFO : ================ | ||
' INFO : | ' INFO : w5_sbg | ||
' INFO : | ' INFO : 23,16747 84,8193359 757,1958 | ||
' INFO : | ' INFO : 0 0 0 | ||
' INFO : ---------------- | |||
' INFO : | ' INFO : w4_psm | ||
' INFO : | ' INFO : 18,1105652 84,8193359 749,121 | ||
' INFO : | ' INFO : 0 0 0 | ||
' INFO : | ' INFO : ---------------- | ||
' INFO : | |||
' '''[ | ' '''[18] read xml file (attribute/content-based)''' | ||
Set xmlDoc = CreateObject( "Microsoft.XMLDOM" ) | |||
Set | |||
' tells the program to wait until the file was loaded conpletely | |||
xmlDoc.Async = "False" | |||
xmlDoc.Load( "C:\Users\RRM\Oni\AE\AEInstaller\vanilla\level0_Final\BINAEINOimpact_effects.xml" ) | |||
' example 1 ('''we use this one''') | |||
' nodes only with a certain attribute and conent will be collected | |||
' content-based search: node [child_node = 'content'] | |||
' attribute-based search: node [@attribute_name = 'attribute_value'] | |||
' | ' if things get too long an underscore _ can be used to make a linebreak | ||
' | '''set w1_tap = xmlDoc.selectNodes _''' | ||
'''( "Oni/ImpactEffects/Impact[@Name = 'w1_tap']/Material[@Name = 'Unbreak_Glass']/ImpactEffect [Component = 'Damage']" )''' | |||
' | ' example 2 | ||
' | ' use "or" for a search of various material | ||
'set w1_tap = xmlDoc.selectNodes _ | |||
' ( "Oni/ImpactEffects/Impact/Material[@Name = 'Default' or @Name = 'Character']/ImpactEffect" ) | |||
' | ' example 3 | ||
' | ' use (|) for a search of various content, e.g. ''<ImpactEffect><Modifier>Light'' plus ''<ImpactEffect><Modifier>Medium'' | ||
'set w1_tap = xmlDoc.selectNodes _ | |||
' ( "Oni/ImpactEffects/Impact/Material/(ImpactEffect [Modifier = 'Light'] | ImpactEffect [Modifier = 'Medium'])" ) | |||
for each element in w1_tap | |||
logmessage "Impact: " & element.parentNode.parentNode.getAttribute("Name") | |||
logmessage "Material: " & element.parentNode.getAttribute("Name") | |||
' outputs "tag name: tag content" | |||
logmessage element.childNodes(0).nodename & ": " & element.childNodes(0).text | |||
logmessage element.childNodes(1).nodename & ": " & element.childNodes(1).text | |||
logmessage "-----------------------------------" | |||
'check for sounds | |||
if element.childNodes(2).childNodes.length = 0 then | |||
logmessage "sound not present" | |||
else | |||
logmessage "sound is present" | |||
logmessage "-----------------------------------" | |||
logmessage element.childNodes(2).childNodes(0).nodename & ": " & element.childNodes(2).childNodes(0).text | |||
logmessage element.childNodes(2).childNodes(1).nodename & ": " & element.childNodes(2).childNodes(1).text | |||
logmessage element.childNodes(2).childNodes(2).nodename & ": " & element.childNodes(2).childNodes(2).text | |||
logmessage element.childNodes(2).childNodes(3).nodename & ": " & element.childNodes(2).childNodes(3).text | |||
end if | |||
logmessage "-----------------------------------" | |||
' check for particle | |||
if element.childNodes(3).childNodes.length = 0 then | |||
logmessage "no particle present" | |||
else | |||
logmessage "number of particle: " & element.childNodes(3).childNodes.length | |||
for each particle_section in element.childNodes(3).childNodes | |||
logmessage "-----------------------------------" | |||
for each particle_tag in particle_section.childnodes | |||
logmessage particle_tag.nodename & ": " & particle_tag.text | |||
next | |||
next | |||
end if | |||
logmessage "===================================" | |||
next | |||
' | ' INFO : Impact: w1_tap | ||
' INFO : Material: Unbreak_Glass | |||
' INFO : Component: Damage | |||
' INFO : Modifier: Any | |||
' INFO : ----------------------------------- | |||
' INFO : sound not present | |||
' INFO : ----------------------------------- | |||
' INFO : number of particle: 2 | |||
' INFO : ----------------------------------- | |||
' INFO : Name: d__GLASSCRACK | |||
' INFO : Orientation: 0 | |||
' | ' INFO : Location: 4 | ||
' INFO : Decal1: false | |||
' INFO : Decal2: true | |||
' INFO : ----------------------------------- | |||
' INFO : Name: w1_tap_x03 | |||
' INFO : Orientation: 0 | |||
' INFO : Location: 1 | |||
' INFO : Offset: -1 | |||
' INFO : =================================== | |||
' '''[] remove xml nodes''' | |||
Set objXMLDoc = CreateObject("Microsoft.XMLDOM") | |||
objXMLDoc.async = False | |||
Dim XMLFile | |||
XMLFile = "C:\Softimage\Softimage_Mod_Tool_7.5\OniLevels\ONLV\test\ONLVAirport.xml" | |||
objXMLDoc.load(XMLFile) | |||
Set nodes = objXMLDoc.selectNodes("Oni/CRSA/*") | |||
For Each node In nodes | |||
node.parentNode.removeChild(node) | |||
Next | |||
objXMLDoc.Save(XMLFile) | |||
' '''[19] 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 | |||
' '''[20] 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 | |||
' '''[21] 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 | |||
' '''[22] 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 | |||
' | |||
' you | ' if you are going to use the xml file right after its extraction (which is likely) | ||
' the | ' 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""" | |||
logmessage " | 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: | |||
' <small>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"</small> | |||
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 via winmgmts | |||
' | |||
' an | ' slightly modified code from [https://devblogs.microsoft.com/scripting/how-can-i-start-a-process-and-then-wait-for-the-process-to-end-before-terminating-the-script/ 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 = "." | |||
' to | 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 | |||
[[Image:XSI_Mod_Tool_PPG.png|thumb]] | |||
' '''[23] building a form (PPG)''' | |||
dim oPSet, oPPGLayout, oItem, PPG_exist | |||
' set check value to 0 | |||
PPG_exist = 0 | |||
' | ' check if PPG exists | ||
for each prop in ActiveProject.ActiveScene.Root.Properties | |||
logmessage prop.name | |||
if instr(1, prop.name, "my_new_PPG") > 0 then | |||
PPG_exist = 1 | |||
logmessage "found " & """" & prop.name & """" | |||
end if | |||
next | |||
' | ' create PPG if it doesn't exist | ||
if PPG_exist = 0 then | |||
set oPSet = ActiveSceneRoot.AddProperty("CustomProperty", false, "my_new_PPG") | |||
set oPPGLayout = oPSet.PPGLayout | |||
' setup PPG parameters | |||
' ################################################################################### | |||
' create checkbox and remove key symboles by setting parameter "Animatable" to false | |||
oPSet.AddParameter3 "Check1", siBool, 0, , , false | |||
oPSet.AddParameter3 "Check2", siBool, 0, , , false | |||
oPSet.AddParameter3 "Check3", siBool, 1, , , false | |||
oPSet.AddParameter3 "Check4", siBool, 1, , , false | |||
oPSet.AddParameter3 "text1", siString | |||
' last parameter of "int1" is set to ReadOnly | |||
oPSet.AddParameter3 "int1", siInt2, , , , false, 1 | |||
oPSet.AddParameter3 "int2", siInt2, , , , false, 0 | |||
' add PPG items | |||
' ################################################################################### | |||
oPPGLayout.AddItem "text1", "Hi there!" | |||
oPPGLayout.AddItem "int1", "number 1" | |||
oPPGLayout.AddItem "int2", "number 2" | |||
oPPGLayout.AddGroup "4 checkboxes", true | |||
oPPGLayout.AddRow | |||
oPPGLayout.AddItem "Check1", "C1" | |||
oPPGLayout.AddItem "Check3", "C3" | |||
oPPGLayout.EndRow | |||
oPPGLayout.AddRow | |||
oPPGLayout.AddItem "Check2", "C2" | |||
oPPGLayout.AddItem "Check4", "C4" | |||
oPPGLayout.EndRow | |||
oPPGLayout.EndGroup | |||
oPPGLayout.AddButton("log_values", "log PPG values").setAttribute siUICX, 120 | |||
oPPGLayout.Logic = "sub log_values_OnClicked" & vbCrlf & _ | |||
" logmessage ""text 1 = "" & getvalue(""my_new_PPG.text1"")" & vbCrlf & _ | |||
" logmessage ""number 1 = "" & getvalue(""my_new_PPG.int1"")" & vbCrlf & _ | |||
" logmessage ""C1 = "" & getvalue(""my_new_PPG.Check1"")" & vbCrlf & _ | |||
" end sub" | |||
oPPGLayout.Language = "VBScript" 'Optional because this is the default | |||
' open PPG | |||
InspectObj oPSet | |||
else | |||
' open that PPG if it already exist | |||
InspectObj "my_new_PPG" | |||
end if | |||
' set values from outside the PPG | |||
' | setvalue "my_new_PPG.text1", "any text could stand here" | ||
setvalue "my_new_PPG.int1", "42" | |||
setvalue "my_new_PPG.check1", true | |||
' | ' get values from outside the PPG | ||
logmessage getvalue("my_new_PPG.text1") | |||
logmessage getvalue("my_new_PPG.int1") | |||
logmessage | logmessage getvalue("my_new_PPG.check1") | ||
logmessage | |||
logmessage | |||
[[Image:XSI_Mod_Tool_UserDataBlob.png|thumb]] | |||
' '''[ | ' '''[24] 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 | |||
if | 'LogMessage prop.Name | ||
if instr(1, prop.Name, "my_prop") = 1 then | |||
found_my_prop = 1 | |||
end if | 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 | |||
' '''[25] getting the position of points (with selection mode point)''' | |||
' a point must be selected | |||
if | ' 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 | |||
' '''[26] 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 | |||
' '''[ | ' '''[27] 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 : | ' INFO : new point 0 posy: -7 | ||
' INFO : | ' INFO : new point 0 posz: -7 | ||
' '''[ | ' '''[28] getting the scaling, rotation and position of selected objects''' | ||
logmessage "mesh name: " & selection(0) | |||
logmessage selection(0).sclx.value | |||
logmessage selection(0).scly.value | |||
logmessage selection(0).sclz.value | |||
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 | |||
' '''[29] getting the scaling, rotation, and position of not selected objects''' | |||
' '''[ | |||
' let's | ' GetValue("NAME.kine.global.rotx") | ||
' NAME must be the exact mesh name | |||
' let's say you want the data of one character's pelvis | |||
logmessage GetValue("pelvis.kine.global.sclx") | |||
logmessage GetValue("pelvis.kine.global.scly") | |||
logmessage GetValue("pelvis.kine.global.sclz") | |||
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") | |||
' '''[30] decrypting merged integer flags''' | |||
' for example the [[XML:BINA/OBJC/TRGV|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 | |||
end | 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 | |||
' '''[31] disabling PPG popups''' | |||
' for example if code of a script button creates numerous objects in one go, the same number of property pages (PPG) can appear | |||
' for user convenience those 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 | |||
' '''[32] 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 | |||
' '''[33] getting bounding box values''' | |||
' this could be useful to create a bounding box for [[XML:OFGA|OFGA files]] | |||
' let's get the bounding box of a simple cylinder | |||
' the output values will be absolute positions | |||
CreatePrim "Cylinder", "MeshSurface" | |||
dim xmin, ymin, zmin, xmax, ymax, zmax | |||
dim list | |||
'if you use SelectionList the objects will be treated as one single object | |||
'set list = GetValue( "SelectionList" ) | |||
set list = GetValue( selection(0) ) | |||
GetBBox list, TRUE, xmin, ymin, zmin, xmax, ymax, zmax | |||
LogMessage "Lower Bound: " & xmin & " / " & ymin & " / " & zmin | |||
LogMessage "Upper Bound: " & xmax & " / " & ymax & " / " & zmax | |||
' expected output: | |||
' INFO : Lower Bound: -1 / -2 / -1 | |||
' INFO : Upper Bound: 1 / 2 / 1 | |||
' '''[34] open an explorer window''' | |||
' this could be used open an output folder ... | |||
strPath = "[http://web.archive.org/web/20150212074443/http://support.microsoft.com/kb/152457 explorer.exe /e]," & XSIUtils.ResolvePath("$SI_HOME/") | |||
Set objShell = CreateObject("Wscript.Shell") | |||
objShell.Run strPath | |||
' to select a generated file inside the folder: | |||
strPath = "explorer.exe /select," & "C:\folder\test.txt" | |||
'''[ | [[Image:XSI_Mod_Tool_SelectNeighborObj_obj_5.png|thumb|SelectNeighborObj obj 5]] | ||
' '''[35] working with hierarchies''' | |||
if typename ( | ' let's be sure we have an object selected | ||
logmessage | if selection.count > 0 and typename(selection(0)) = "X3DObject" then | ||
' the object itself | |||
logmessage selection(0) | |||
' the parent object | |||
logmessage selection(0).parent | |||
' the children | |||
for each n in selection(0).FindChildren( , , , 0 ) | |||
logmessage n | |||
next | |||
' the 4the parameter of FindChildren can be set to 0 or 1 | |||
' with 0 you get all direct children | |||
' with 1 you get everything located under that object no matter how deep the level | |||
' count all objects | |||
logmessage "children: " & selection(0).FindChildren( , , , 1).count | |||
' caution: if the 3rd parameter is set to siMeshFamily | |||
' then the selected object will be also counted | |||
' find the root object of the hierarchy, any object could be selected | |||
SelectNeighborObj selection(0), 4 | |||
' go through the hierarchy in different directions | |||
' | ' SelectNeighborObj [parameter1], [parameter2], [parameter3], [parameter4] | ||
' options of the second parameters | |||
' 0 go one level up | |||
' 1 go one level down | |||
' | ' 2 go to next silbing | ||
' 3 go to previous silbing | |||
' 4 go to highest level | |||
' 5 go to deepest level of current selected obj | |||
' | ' 5: if there are more than one children, the path goes always for the first (left) child (see image) | ||
' select the hierarchy as a whole | |||
SelectObj "left_thigh", "TREE", true | |||
' first parameter could be any object of the hierarchy | |||
' after using this the selection of an Oni character will be "B:pelvis" | |||
else | |||
msgbox "no object was selected" | |||
' | |||
' | |||
' | |||
end if | end if | ||
'''[36] drag and drop support for specific oni files''' | |||
function XSILoadPlugin( in_reg ) | |||
in_reg.Author = "" | |||
in_reg.Name = "Oni drag and drop support" | |||
in_reg.Email = "" | |||
in_reg.URL = "" | |||
in_reg.Major = 1 | |||
in_reg.Minor = 0 | |||
in_reg.RegisterEvent "support_oni_DnD",siOnDragAndDrop | |||
'RegistrationInsertionPoint - do not remove this line | |||
XSILoadPlugin = true | |||
end function | |||
function XSIUnloadPlugin( in_reg ) | |||
dim strPluginName | |||
strPluginName = in_reg.Name | |||
Application.LogMessage strPluginName & " has been unloaded.",siVerbose | |||
XSIUnloadPlugin = true | |||
end function | |||
function support_oni_DnD_OnEvent( in_ctxt ) | |||
Set objFSO = CreateObject("Scripting.FileSystemObject") | |||
= | |||
FullFilePath = in_ctxt.GetAttribute("DragSource") | |||
FileExt = objFSO.GetExtensionName(FullFilePath) | |||
FileName = objFSO.GetBaseName(FullFilePath) | |||
if instr(LCase(FileExt), "oni") = 1 then | |||
in_ctxt.SetAttribute "DragSourceSupported", true | |||
' next line prevents the code from being repeated | |||
if in_ctxt.GetAttribute("DragAndDropAction") = 1 then | |||
logmessage "What I'm supposed to do with that oni?" | |||
' do more stuff here | |||
' .................. | |||
' e.g. telling onisplit to extract the oni | |||
end if | |||
end if | |||
support_oni_DnD_OnEvent = true | |||
end function | |||
'''Important:''' | |||
Mod Tool has its own drag and drop event handler for dae and xml file. | |||
If we succeed in modifying and shipping that new file, we could finally trigger scripts with those files and process them. | |||
The original file can be found at: | |||
logmessage XSIUtils.ResolvePath("$XSI_HOME/") & "Application\DSScripts\Model.vbs" | |||
' C:\Softimage\Softimage_Mod_Tool_7.5\Application\DSScripts\'''Model.vbs''' | |||
A backup of the original file can be found here: '''<nowiki>https://dl.dropboxusercontent.com/u/139715/OniGalore/ModToolScript/Model.vbs</nowiki> (dead link)''' | |||
There are two issues that can be fixed by modifying this file. | |||
* import of xml files created by onisplit | |||
* import of dae and xml files with relative path from a html page | |||
Relative file pathes will be transformed to absolute pathes whereby an unwanted "file:///" is added. | |||
A solution to is to transform the path again. | |||
if | if instr(in_Filename,"file:///") = 1 then | ||
in_Filename = replace(in_Filename, "file:///", "") | |||
end if | end if | ||
Following function is always triggered, so we will modify it. | |||
sub ImportDotXSIProc( in_Filename, in_Parent ) | |||
<font style="color:#DD0000">if instr(in_Filename,"file:///") = 1 then | |||
in_Filename = replace(in_Filename, "file:///", "") | |||
end if | |||
Set objFSO = CreateObject("Scripting.FileSystem<Object") | |||
FileExt = objFSO.GetExtensionName(in_Filename)</font> | |||
if application.license = "Avid 3D" then | |||
SIImportDotXSIFile in_Filename, in_Parent | |||
else | |||
Set oFS = CreateObject("Scripting.FileSystemObject") | |||
<font style="color:#DD0000">if oFS.FileExists(in_Filename) = True then | |||
if FileExt = "xml" then | |||
' is this an Oni xml file ? | |||
Set xmlDoc = CreateObject("Microsoft.XMLDOM") | |||
xmlDoc.Async = "False" | |||
xmlDoc.Load(in_Filename) | |||
if xmlDoc.selectNodes("Oni").length > 0 then | |||
logmessage "Oni xml file detected" | |||
read_xml "OFGA", in_Filename | |||
end if | |||
exit sub | |||
end if</font> | |||
The lines in red has been added. | |||
''' | '''[37] dae export''' | ||
set oProps = ActiveProject.ActiveScene.Root.Properties | |||
if typename (oProps.find("ExportCrosswalkOptions")) = "Nothing" then | |||
logmessage "Export settings not set" | |||
CreateExportCrosswalkOptions , "ExportCrosswalkOptions" | |||
else | |||
logmessage "Export settings present" | |||
end if | |||
' sets the extension to dae | |||
SetValue "ExportCrosswalkOptions.Format", 1 | |||
' set export path and file name | |||
SetValue "ExportCrosswalkOptions.Filename", CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\export_test.dae" | |||
' selection only | |||
SetValue "ExportCrosswalkOptions.ExportSelectionOnly", True | |||
' export | |||
ExportCrosswalk "ExportCrosswalkOptions" | |||
'''[38] fbx export''' | |||
FBXExportLights (false) | |||
FBXExportSelection (true) | |||
' mark FBXExport and hit F1 to get more options | |||
FBXExport (CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\export_test.fbx" ) | |||
'''[39] import an image clip only once''' | |||
image_path = "C:\Users\RRM\Desktop\white_512_512.tga" | |||
Set FSO = CreateObject("Scripting.FileSystemObject") | |||
image_clip = FSO.GetBaseName(image_path) & "_" & FSO.GetExtensionName(image_path) | |||
logmessage image_clip | |||
if not typename(ActiveProject.ActiveScene.ImageClips(image_clip)) = "Nothing" then | |||
logmessage "found image clip" | |||
else | |||
logmessage "image clip not yet present, going to import ..." | |||
SICreateImageClip image_path | |||
' or as script object: | |||
'set oImage = AddImageSource (image_path) | |||
'set oImageClip = AddImageClip (oImage) | |||
end if | |||
'''[40] layers''' | |||
[[Image:ModTool_layers.png|thumb|200px|right|how to access scene layers]] | |||
To access scene layers switch from Main Control Panel (MCP) to Keying Panel/Layers (KP/L) and then click "Scene". | |||
After the user became used to layers, they can help to organize work in a scene. This is especially interesting for some scripting tasks like getting TRGV/FURN data for xml files. | |||
' get current layer | |||
GetCurrentLayer CurrentLayer | |||
logmessage CurrentLayer | |||
' create a new layer named "FurnLayer" if it doesn't already exist | |||
' make new layer the current layer | |||
if typename(ActiveProject.ActiveScene.Layers("FurnLayer")) = "Nothing" then | |||
SICreateLayer , "FurnLayer", FurnLayer | |||
SetCurrentLayer FurnLayer | |||
else | |||
SetCurrentLayer "Layers.FurnLayer" | |||
end if | |||
' get objects in FurnLayer and count objects | |||
' exit sub if there are no objects | |||
SelectMembers "Layers.FurnLayer" | |||
if selection.count = 0 then | |||
MsgBox "No OFGA data found to export.", , "Export canceled" | |||
exit sub | |||
end if | |||
' if there are Furn objects | |||
for each obj in selection | |||
' do something e.g. create xml | |||
next | |||
' '''[41] onisplit update''' | |||
' this downloads and unzips the last attachment from the [http://mods.oni2.net/node/38 onisplit page] | |||
output_dir = "F:\test\" | |||
' get onisplit link ################################################ | |||
set xmlhttp = createobject ("msxml2.xmlhttp.3.0") | |||
xmlhttp.open "get", "http://mods.oni2.net/node/38/index.html", false | |||
xmlhttp.send | |||
<nowiki>webtext = xmlhttp.responseText | |||
webtext = replace(replace(webtext, vbcr,""),vblf,"") | |||
webtext = split(webtext, "<table class=""sticky-enabled""> <thead><tr><th>Attachment</th>" )(1) | |||
webtext = split(webtext, "</td> </tr></tbody></table>") (0)</nowiki> | |||
link_start = instrrev(webtext, "http") | |||
link_end = instrrev(webtext, ".zip"" type") + 4 ' + zip | |||
' mid (text, begin, length) | |||
link = mid(webtext, link_start, link_end - link_start) | |||
logmessage "last link in attachment: " & link | |||
dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP") | |||
dim bStrm: Set bStrm = createobject("Adodb.Stream") | |||
xHttp.Open "GET", link, False | |||
xHttp.Send | |||
' get file name ################################################### | |||
hdr = xHttp.getResponseHeader("Content-Disposition") | |||
hdr = replace (hdr, "attachment; filename=""", "") | |||
hdr = replace (hdr, """", "") | |||
logmessage hdr | |||
' save file ####################################################### | |||
filename = output_dir & hdr | |||
with bStrm | |||
.type = 1 '//binary | |||
.open | |||
.write xHttp.responseBody | |||
.savetofile filename, 2 '//overwrite | |||
end with | |||
' extract file #################################################### | |||
UnzipFile filename, output_dir | |||
Function UnzipFile(ZipFile, ExtractTo) | |||
Set fso = CreateObject("Scripting.FileSystemObject") | |||
If NOT fso.FolderExists(ExtractTo) Then | |||
fso.CreateFolder(ExtractTo) | |||
End If | |||
set objShell = CreateObject("Shell.Application") | |||
set FilesInZip=objShell.NameSpace(ZipFile).items | |||
objShell.NameSpace(ExtractTo).CopyHere(FilesInZip) | |||
Set fso = Nothing | |||
Set objShell = Nothing | |||
End Function | |||
''' | ' '''[42] get vertex color''' | ||
set oGeometry = selection(0).activeprimitive.geometry | |||
set oTriangles = oGeometry.Triangles | |||
for each oTriangle in oTriangles | |||
logmessage oTriangle.Name | |||
for each oVertex in oTriangle.Points | |||
set oColor = oVertex.Color | |||
logmessage vbTab & "RGBA(" & _ | |||
oColor.red & "," & _ | |||
oColor.green & "," & _ | |||
oColor.blue & "," & _ | |||
oColor.alpha & ")" | |||
next | |||
next | |||
' '''[43] get all used textures''' | |||
DeleteAllUnusedMaterials | |||
DeleteUnusedImageClips | |||
'DeleteUnusedImageSources | |||
for each i in Application.ActiveProject.ActiveScene.ExternalFiles | |||
if i.filetype = "Pictures" then | |||
logmessage i | |||
end if | |||
next | |||
' ''' [44] get global point position''' | |||
set oObj = selection(0) | |||
set oTrans = oObj.Kinematics.Local.Transform | |||
set oPoint0 = oObj.ActivePrimitive.Geometry.Points(0) | |||
set oPoint7 = oObj.ActivePrimitive.Geometry.Points(7) | |||
set oPos0 = oPoint0.Position | |||
set oPos7 = oPoint7.Position | |||
' scaling must be frozen to 1 before we can calculate the size from local values | |||
ResetTransform selection(0), siCtr, siScl, siXYZ | |||
logmessage "local p0: "& oPos0.X & " " & oPos0.Y & " " & oPos0.Z | |||
set oGlobalPos0 = XSIMath.MapObjectPositionToWorldSpace( oTrans, oPos0) | |||
logmessage "global p0: "& oGlobalPos0.X & " " & oGlobalPos0.Y & " " & oGlobalPos0.Z | |||
logmessage "local p7: "& oPos7.X & " " & oPos7.Y & " " & oPos7.Z | |||
set oGlobalPos7 = XSIMath.MapObjectPositionToWorldSpace( oTrans, oPos7) | |||
logmessage "global p7: "& oGlobalPos7.X & " " & oGlobalPos7.Y & " " & oGlobalPos7.Z | |||
logmessage "size: " & oPos7.X - oPos0.X & " " & _ | |||
oPos7.Y - oPos0.Y & " " & _ | |||
oPos7.Z - oPos0.Z | |||
' with a rotation of: -3,8792 16,4039 -13,5017 | |||
' INFO : local p0: -4 -4 -4 | |||
' INFO : local p7: 4 4 4 | |||
' INFO : global p0: -5,74764582364017 -3,00250371537919 -2,43916767056426 ' TRGV start point | |||
' INFO : global p7: 5,74764582364017 3,00250371537919 2,43916767056426 | |||
' INFO : size: 8 8 8 | |||
===Interactive Creative Environment (ICE)=== | |||
* [[wikipedia:Autodesk_Softimage#ICE_Interactive_Creative_Environment|ICE]] | |||
'''tutorials:''' | |||
* https://www.youtube.com/watch?v=ioMQ2rBVO4g | |||
* http://dot3d.blogspot.com/2009/10/softimage-ice-tree-building-step-by.html | |||
* [https://www.si-community.com/community/viewtopic.php?f=41&t=1707 an ICE tutorial thread] | |||
* [https://download.autodesk.com/global/docs/softimage2013/en_us/userguide/index.html?url=files/ICE_trees_DebuggingICETrees.htm,topicNumber=d30e269791 ICE trees Debugging] | |||
* <nowiki>https://support.solidangle.com/display/SItoAUG/ICE</nowiki> (dead link) | |||
==Wanted knowledge== | |||
* How to set up particles in Mod Tool? We still need an Oni particle editor! | |||
* How to rig models and then extract the animation data? | |||
* How to make complex new UV maps? | |||
[[Category:Windows-only modding tools]] | [[Category:Modding tutorials]][[Category:Outdated modding tools]][[Category:Windows-only modding tools]] | ||
edits