Object Hierarchy | 関連する C++クラス:UserDataMap
UserDataMap
v3.0
UserDataMap は、任意のクラスタに割り当てることができる Property です。UserDataMap により、ジオメトリの個々のコンポーネントに可変長のバイナリユーザデータを格納できます。このデータはシーンファイルの一部として保存され、オブジェクトモデルを使用することでプラグインからアクセスできます。
Softimage Plugin(パーシスタントエフェクトおよびイミディエイトエフェクトの双方)は、このプロパティを使い、個々の頂点、ポリゴン、エッジなどのオブジェクトのコンポーネントに関するデータを保存し、取得することができます。考え得るデータを具体的に挙げると、カスタムゲームストラクチャ、ローシミュレーションデータ、行列、コメント、イメージなどがあります。
UserDataMap には、バイナリデータ用に使用する用途とテンプレートデータ用に使用する用途の 2 通りがあります。バイナリ UserDataMap を使用すると、ユーザデータの構造は完全にプラグイン次第となります。これは C++ プラグインに適しています。ただし、以下の例が示すように、文字列を使うことによりスクリプトからこのデータにアクセスできます。テンプレート UserDataMap は、CustomProperty を使用してユーザデータの構造を厳密に定義します(UserDataMap.Template を参照)。テンプレートユーザデータはスクリプト、C++からのアクセスに加え UI からもインスペクトすることができます(InspectUserData を参照)。
UserDataMaps オブジェクトは、CreateUserDataMap または SceneItem.AddProperty を使用して作成できます。
UserDataMap は、クラスタの個々のコンポーネントに対して個別にデータを保存し、この点で CustomProperty オブジェクトや UserDataBlob オブジェクトとは異なります。たとえば、10 個のポリゴンを持つクラスタは、10 個の異なる UserDataItem オブジェクトを持ちます。UserDataItem オブジェクトを列挙する方法には、UserDataMap.Item を使用して UserDataMap に列挙する方法、VBScript の"for each"ループを作成する方法、および JScript の Enumerator オブジェクトを使用する方法があります。また、UserDataMap.ItemValue を使用して UserDataMap の内容に直接アクセスすることも可能です。
コンポーネント別のデータを保存する点で、UserDataMap は ClusterProperty に似ています。ただし、ClusterProperty は各コンポーネントにおいて常に倍精度の定数を保存し、UserDataMap は可変長データを使用できる点で異なります。
この User Data Map は、SAAPHIRE SAA_subelement* UserData 関数で使用できる User Data Map と同様の機能を提供します。たとえば、プロパティの名前(Name)は、SAA_subelementSetUserData などの関数の Tag 引数に対応します。
ユーザデータマップのプリセットを保存しておけば、別のオブジェクトにそのユーザデータを適用できます。最良の結果を得るためには、両クラスタのコンポーネント数を揃えるようにしてください。
'example giving an overview of accessing per-component 'user data on a cluster dim oObj, oCluster, oUDProp, i, oUserDataAtIndex2 set oObj = CreatePrim( "Sphere", "MeshSurface" ) SetValue oObj & ".polymsh.geom.subdivu", 1 SetValue oObj & ".polymsh.geom.subdivv", 1 'Create a cluster covering all edges on the geometry set oCluster = oObj.ActivePrimitive.Geometry.AddCluster( siEdgeCluster,"UserDataCls" ) set oUDProp = oCluster.AddProperty( "UserDataMap",,"UserDataExample" ) 'UserDataMap logmessage oUDProp.Type 'Assign user data to a particular index oUDProp.ItemValue(2) = "Some String Data" 'Another way to do the same thing is to use a UserDataItem object oUDProp.Item(3).Value = "String data for index 3" 'Erase the data we just placed at 3 oUDProp.ClearItem(3) 'Now look at all the user data in the property looking for non-empty content for i = 0 to oUDProp.Count if ( not oUDProp.IsEmpty(i) ) then logmessage "Found data with size " & oUDProp.ItemSize(i) & " at cluster index " & i end if next 'Output of this script is: 'INFO : "UserDataMap" 'INFO : "Found data with size 32 at cluster index 2" |
//example giving an overview of accessing per-component
//user data on a cluster
var oObj = CreatePrim( "Sphere", "MeshSurface" ) ;
SetValue( oObj + ".polymsh.geom.subdivu", 1 ) ;
SetValue( oObj + ".polymsh.geom.subdivv", 1 ) ;
//Create a cluster covering all edges on the geometry
var oCluster = oObj.ActivePrimitive.Geometry.AddCluster( siEdgeCluster, "UserDataCls" ) ;
var oUDProp = oCluster.AddProperty( "UserDataMap",false,"UserDataExample" ) ;
//UserDataMap
logmessage( oUDProp.Type ) ;
//Assign user data to a particular index
oUDProp.ItemValue(2) = "Some String Data"
//Or we can use a UserDataItem object as another way to set data
oUDProp.Item(3).Value = "String data for index 3"
//Erase the data we just placed at 3
oUDProp.ClearItem(3)
//Now look at all the user data in the property looking for non-empty content
for( var i = 0 ; i < oUDProp.Count ; i++ )
{
if ( !oUDProp.IsEmpty(i) )
{
logmessage( "Found data with size " + oUDProp.ItemSize(i) + " at cluster index " + i ) ;
}
}
//Output of this script is:
//INFO : "UserDataMap"
//INFO : "Found data with size 32 at cluster index 2" |
'example demonstrating the how to display the entire contents
'of a binary user data map in the command history window.
'(For an example showing how to show the contents of a templated user data map
'see the Info OM Netview page that is part of XSI Local\Tools)
dim oObj, oCluster, oUDProp, i
'First set up a little demo scenario
set oObj = CreatePrim( "Arc", "NurbsCurve" )
set oCluster = oObj.ActivePrimitive.Geometry.AddCluster( siVertexCluster,"PntCluster",Array(1,4,7,10,13,16) )
set oUDProp = oCluster.AddProperty( "UserDataMap",,"UserDataExample" )
'Fill in the user data with the string version of the index
for i = 0 to oUDProp.Count - 1
oUDProp.Item( i ).Value = CStr( i )
next
SelectObj oUDProp
'Then dump out all the content that was added
TraceSelectedUserDataMap
'Output of this script will look approximately like this:
'INFO : "User Data Map: arc.crvlist.cls.PntCluster.UserDataExample"
'INFO : "Size of User Data Map 6- Size of Cluster 6"
'INFO : "Property was created on little-endian computer"
'INFO : "Contents:"
'INFO : "Item 0 pnt(1): 0 "
'INFO : "Item 1 pnt(4): 1 "
'INFO : "Item 2 pnt(7): 2 "
'INFO : "Item 3 pnt(10): 3 "
'INFO : "Item 4 pnt(13): 4 "
'INFO : "Item 5 pnt(16): 5 "
'The number of components with user data could get huge so this constant
'constrains the size of the output to reasonable proportions
const g_MapItemsDisplay = 256
const g_ShowEmptyItems = false
sub TraceSelectedUserDataMap
'This example could easily to enhanced to loop through multiple selections
'but for the sake of simplicity it only looks at the first item
if ( selection.Count > 0 ) then
if ( typename( selection( 0 ) ) = "UserDataMap" ) then
TraceUserDataMap( selection( 0 ) )
else
logmessage "Please select a user data map and try again"
end if
else
logmessage "Please select a user data map and try again"
end if
end sub
sub TraceUserDataMap( in_oUDM )
dim i, oItem, cntCluster, byteString, j, str, val
cntCluster = in_oUDM.Parent.Elements.Count
Logmessage "User Data Map: " & in_oUDM.FullName
Logmessage "Size of User Data Map " & in_oUDM.Count & "- Size of Cluster " & cntCluster
Logmessage "Contents:"
dim oCluster, oClusterElementsCollection, aElements
set oCluster = in_oUDM.Parent
set oClusterElementsCollection = oCluster.Elements
aElements = oClusterElementsCollection.Array
dim iElementInCluster, strItemDesc
dim cntItems
cntItems = in_oUDM.Count
dim cntDisplayedItems
cntDisplayedItems = 0
for i = 0 to ( cntItems - 1)
if ( i < cntCluster ) then
iElementInCluster = aElements(i)
strItemDesc = "Item " & i & " " & oCluster.type & "(" & iElementInCluster & "): "
else
strItemDesc = "Item " & i & " " & oCluster.type & "(INVALID INDEX): "
end if
set oItem = in_oUDM.Item( i )
if ( not oItem.IsEmpty ) then
'We convert the contents into a byte by byte description
'because we don't know if this is a safe to display unicode string
strItemDesc = strItemDesc & GetUserDataContentsString( oItem )
logmessage strItemDesc
cntDisplayedItems = cntDisplayedItems + 1
if ( cntDisplayedItems = g_MapItemsDisplay ) then
exit for
end if
elseif ( g_ShowEmptyItems ) then
logmessage strItemDesc & " is empty"
end if
next
end sub
'Produces a string representation of the user data
function GetUserDataContentsString( in_UserDataItem )
dim strValue
strValue = in_UserDataItem.Value
dim j
'Also attempt to produce a string representation
dim strAsString
for j = 1 to Len( strValue )
val = Asc( Mid( strValue, j, 1 ) )
'We only accept the basic ascii values - other content is
'not necessary safe to print. For supporting non-English
'characters, line breaks and tabs this logic would need
'to be more sophisticated
if (( val < 127 ) AND ( val > 31 )) then
strAsString = strAsString & Chr( val )
else
'we assume that there is binary content
strAsString = strAsString & "."
end if
next
GetUserDataContentsString = strAsString
end function |
'example of how to access a templated UserDataMap from from scripting.
'In this example we create user data for an imaginary game on the vertices of
'a sphere.
'
'The user data template is designed to match an associated structure in the game engine,
'and consists of 5 parameters ("ImagePath", "AttachmentPoint", "FixedPoint", "ZetaFactor",
'and "Friction")
'
'This example creates the object and sets some example values on a few points. (A user could also
'add and edit these values from the user interface using the InspectUserData command)
'
'When you run this example this is the output in the log window:
'
'INFO : "User data on sphere.polymsh.cls.AllVertices.GameData"
'INFO : "pnt[12]: ZetaFactor:0.2 Friction:64 AttachmentPoint Image: image12.tif"
'INFO : "pnt[31]: ZetaFactor:0.9 Friction:12 AttachmentPoint FixedPoint Image: unknown"
'INFO : "pnt[44]: ZetaFactor:0.5 Friction:28 FixedPoint Image: image1.jpg"
option explicit
const g_ClusterName = "AllVertices"
const g_UserDataMapName = "GameData"
const g_TemplateName = "VertexInfoTemplate"
newscene ,false
dim oSphere, oUserDataMap
set oSphere = ActiveSceneRoot.AddGeometry( "Sphere", "MeshSurface" )
'Create templated user data map - currently it is has no user data
set oUserDataMap = SetupObject( oSphere )
'Set these user data values on vertex 44
call AddUserData( oUserDataMap , 44, "image1.jpg", false, true, 0.5, 28 )
'Set different values on points 12
call AddUserData( oUserDataMap , 12, "background14.tif", true, false, 0.1, 39 )
'Change our minds about point 12
call AddUserData( oUserDataMap , 12, "image12.tif", true, false, 0.2, 64 )
call AddUserData( oUserDataMap , 31, "unknown", true, true, 0.9, 12 )
call LogUserData( oUserDataMap )
'On the given object create a UserDataMap for the game data
function SetupObject( in_oObj )
dim oCluster, oPSet, oUserDataMap
'Test if we have already setup this object
on error resume next
set oUserDataMap = in_oObj.ActivePrimitive.Geometry._
Clusters( g_ClusterName ).Properties( g_UserDataMapName )
on error goto 0
if typename( oUserDataMap ) = "UserDataMap" then
'Our user data map already exists
set SetupObject = oUserDataMap
exit function
end if
set oCluster = in_oObj.ActivePrimitive.Geometry.AddCluster( siVertexCluster, g_ClusterName )
set oPSet = CreateTemplate( oCluster )
set oUserDataMap = oCluster.AddProperty( "UserDataMap",,g_UserDataMapName )
'Associate the template with our user data map
set oUserDataMap.Template = oPSet
'Return the newly created User Data Map
set SetupObject = oUserDataMap
end function
'This function creates the template that defines the format of the data inside our UserDataMap
'The new template is returned.
'Note: this function does not associate the template with any user data map, or set any values on
'the user data map.
function CreateTemplate( in_oParentObject )
dim oPSet
set oPSet = in_oParentObject.AddProperty( "Custom_parameter_list",, g_TemplateName )
oPSet.AddParameter "ImagePath", siString
oPSet.AddParameter "AttachmentPoint", siBool, , , ,, , false
oPSet.AddParameter "FixedPoint", siBool, , , ,, , false
oPSet.AddParameter "ZetaFactor", siDouble, , , , , , 0.0, 0.0, 1.0
oPSet.AddParameter "Friction", siUByte, , , , , , 64, 0, 128
set CreateTemplate = oPSet
end function
'Given specific game parameter values, this routine will save those values
'on the specified vertex of the UserDataMap
sub AddUserData( in_oUDM, in_CompIndex, in_ImagePath, in_AttachPoint, in_FixedPoint, in_ZetaFactor, in_Friction )
'Get access to the Template for this user data map
dim oTemplate
set oTemplate = in_oUDM.Template
'Fill in the parameters on the template
oTemplate.Parameters( "ImagePath" ).Value = in_ImagePath
oTemplate.Parameters( "AttachmentPoint" ).Value = in_AttachPoint
oTemplate.Parameters( "FixedPoint" ).Value = in_FixedPoint
oTemplate.Parameters( "ZetaFactor" ).Value = in_ZetaFactor
oTemplate.Parameters( "Friction" ).Value = in_Friction
'Now that the parameters are specified we need to associated
'these values with the specified vertex
in_oUDM.ItemValue(in_CompIndex) = oTemplate.BinaryData
end sub
'This routine prints out the contents of our user data map
sub LogUserData( in_oUDM )
dim oTemplate, i, strAttachPnt, strFixedPnt
Logmessage "User data on " & in_oUDM
set oTemplate = in_oUDM.Template
for i = 0 to in_oUDM.count
'We can only print out non-empty user data items
if ( NOT in_oUDM.IsEmpty( i ) ) then
'Take the values from the user data and put them in the template
'so that we can read them
oTemplate.BinaryData = in_oUDM.ItemValue( i )
'Look at the boolean values to convert into readable strings
if ( oTemplate.Parameters("AttachmentPoint").Value ) then
strAttachPnt = "AttachmentPoint "
else
strAttachPnt = ""
end if
if ( oTemplate.Parameters("FixedPoint").Value ) then
strFixedPnt = "FixedPoint "
else
strFixedPnt = ""
end if
'Print a 1 line representation of all the values on this particular point
logmessage "pnt[" & i & "]: " & _
" ZetaFactor:" & oTemplate.Parameters("ZetaFactor").Value & _
" Friction:" & oTemplate.Parameters("Friction").Value & _
" " & strAttachPnt & strFixedPnt & _
"Image: " & oTemplate.Parameters("ImagePath").Value
end if
next
end sub |