Files
2025-09-29 00:52:08 +02:00

1250 lines
62 KiB
Plaintext
Executable File

/*
Library script for the Simplygon pipeline.
Author: Jason Hayes <jason.hayes@rockstarsandiego.com>
*/
filein "pipeline/util/collision_funcs.ms"
filein ( RsConfigGetWildwestDir() + "script/3dsmax/_common_functions/FN_VertexPaint.ms" )
global gRsSimplygonCore = undefined
global gRsSimplygonUtils = undefined
struct RsSimplygonSettingsSection
(
/*
Represents an INI section of a Simplygon settings file.
*/
private
-- The properties for this section.
properties = dotNetObject "System.Collections.Hashtable",
public
-- The raw section name in the INI file.
sectionName = undefined,
-- The order the section will show up in the GUI.
order = 0,
-- The display name for the section in the GUI.
displayName = undefined,
-- If set to true, will show up under the advanced rollout for the LOD level.
advanced = true,
fn getPropertyNames =
(
local propNames = #()
local enum = this.properties.GetEnumerator()
while ( enum.MoveNext() ) do (
append propNames enum.Key
)
propNames
),
fn addProperty propName propValue = (
local result = false
if not ( this.properties.Contains propName ) then (
this.properties.Add propName ( dotNetMxsValue propValue )
result = true
)
result
),
fn getProperty propName = (
local result = undefined
if ( this.properties.Contains propName ) then (
result = this.properties.Item[ propName ].value
)
result
),
fn setProperty propName propValue = (
local result = false
if ( this.properties.Contains propName ) then (
-- Do this to ensure that we keep the struct data.
local formerDataPair = this.properties.Item[ propName ].value
formerDataPair.value = propValue
this.properties.Remove[ propName ]
this.properties.Add propName ( dotNetMxsValue formerDataPair )
result = true
)
result
),
fn writeSettings filename = (
local enum = this.properties.GetEnumerator()
while ( enum.MoveNext() ) do (
local propName = enum.Key
local propValue = enum.Value.value
setINISetting filename this.sectionName propName ( propValue.value as string )
)
)
)
struct RsSimplygonSettings
(
/*
Represents Simplygon settings.
*/
private
-- Track whether somone
dirty = false,
-- The current lod count. This is managed from adding and removing lods.
lodCount = 0,
-- Represents each section of the ini file.
lodCollections = #(),
-- The filename associated with these settings.
settingsFilename = undefined,
public
-- These are settings in the INI file.
lodSwitchQuality = "Normal",
tangentSpaceType = "3ds Max",
cascadedLodChain = false,
overrideStrings = "",
-- Functions
fn isDirty = (
this.dirty
),
fn getSettingsFilename = (
this.settingsFilename
),
fn getLodCount = (
this.lodCount
),
fn getLod lodIndex = (
local result = undefined
if lodIndex > 0 and lodIndex <= this.lodCollections.count then (
result = this.lodCollections[ lodIndex ]
)
result
),
fn getProperty lodIdx sectionName propName = (
local result = undefined
local collection = this.getLod lodIdx
if collection != undefined then (
local sectionData = collection.Item[ sectionName ].value
result = sectionData.getProperty propName
)
result
),
fn setProperty lodIdx sectionName propName propVal = (
local result = false
local collection = this.getLod lodIdx
if collection != undefined then (
local sectionData = collection.Item[ sectionName ].value
result = sectionData.setProperty propName propVal
if result then (
this.lodCollections[ lodIdx ].Remove[ sectionName ]
this.lodCollections[ lodIdx ].Add sectionName ( dotNetMxsValue sectionData )
this.dirty = true
result = true
) else (
result = false
)
)
result
),
fn removeLodLevel = (
this.lodCount -= 1
if this.lodCount > 0 then (
deleteItem this.lodCollections this.lodCount
) else (
this.lodCount = 0
)
this.dirty = true
),
fn save filename = (
setINISetting filename "Root/AutoLODSection" "LODSwitchQuality" this.lodSwitchQuality
setINISetting filename "Root/AutoLODSection" "TangentSpaceType" this.tangentSpaceType
setINISetting filename "Root/AutoLODSection" "CascadedLODChain" ( this.cascadedLodChain as string )
setINISetting filename "Root/AutoLODSection" "OverrideStrings" this.overrideStrings
setINISetting filename "Root/LODCollectionSection" "LODCount" ( this.lodCount as string )
for collection in this.lodCollections do (
local enum = collection.GetEnumerator()
while ( enum.MoveNext() ) do (
local lodSection = enum.Value.value
lodSection.writeSettings filename
)
)
this.settingsFilename = filename
this.dirty = false
),
fn load filename = (
this.settingsFilename = filename
this.lodCollections = #()
struct Property
(
visible = true,
displayName = undefined,
tooltip = "",
value = undefined,
options = undefined
)
this.lodSwitchQuality = getINISetting filename "Root/AutoLODSection" "LODSwitchQuality"
this.tangentSpaceType = getINISetting filename "Root/AutoLODSection" "TangentSpaceType"
this.cascadedLodChain = execute ( getINISetting filename "Root/AutoLODSection" "CascadedLODChain" )
this.overrideStrings = getINISetting filename "Root/AutoLODSection" "OverrideStrings"
this.lodCount = ( getINISetting filename "Root/LODCollectionSection" "LODCount" ) as integer
for lodIdx = 1 to this.lodCount do (
local lodCollection = dotNetObject "System.Collections.Hashtable"
local lodNum = lodIdx - 1
local sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section"
local settingsSection = RsSimplygonSettingsSection displayName:"General" sectionName:sectionIniKey order:1 advanced:false
settingsSection.addProperty "ProcessingType" ( Property displayName:"LOD Type" value:( getINISetting filename sectionIniKey "ProcessingType" ) visible:false options:#( "MeshLOD" ) tooltip:"MeshLODs are created by removing edges and vertices from the original mesh, while preserving critical features and all relevant original vertex data. Mesh LODs are often used for creating a set of AutoLODs for each prop and character in a game, in order to reduce triangle count. ProxyLODs are made by generating one new mesh (proxy mesh) and one new set of textures (proxy maps). The new mesh and texture resemble a copy of the base model, which looks similar to the base model at the defined LOD switch onscreen size. Proxy LODs are often used to replace groups of static objects with many materials and meshes, at a distance in a game scene. Switching to a Proxy LOD thus significantly reduces both the number of draw calls and triangle counts, specially in large outdoor scenes. Using Proxy LODs sometimes be referred to as hierarchical LODs or LOD parents since they replace a group of objects with one proxy LOD." )
settingsSection.addProperty "ReductionMetricType" ( Property displayName:"LOD Switch" value:( getINISetting filename sectionIniKey "ReductionMetricType" ) visible:false options:#( "Number Triangles", "On-Screen Size" ) tooltip:"Set the reduction metric type. 'On-Screen Size' will reduce the geometry until any reduction will result in an error larger than one pixel when viewed at the specified size on-screen. 'Triangle Percent' will reduce until the number of triangles are reached." )
settingsSection.addProperty "ReductionRatio" ( Property displayName:"Number Triangles (%)" value:( ( getINISetting filename sectionIniKey "ReductionRatio" ) as float ) options:[ 0.0, 100.0, 50.0 ] tooltip:"The number of triangles for the MeshLOD, measured as a percentage of the Nr triangles in the base model. For example if the base model has 10 000 triangles, setting Number Triangle to 50% will generate a MeshLOD with 5 000 triangles." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/FeaturePreservationSection"
settingsSection = RsSimplygonSettingsSection displayName:"Feature Preservation" sectionName:sectionIniKey order:3
settingsSection.addProperty "VertexColorImportance" ( Property displayName:"Vertex Color Importance" value:( getINISetting filename sectionIniKey "VertexColorImportance" ) options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "GeometricImportance" ( Property displayName:"Geometric Importance" value:( getINISetting filename sectionIniKey "GeometricImportance" ) options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "MaterialImportance" ( Property displayName:"Material Importance" value:( getINISetting filename sectionIniKey "MaterialImportance" ) options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "ShadingImportance" ( Property displayName:"Shading Importance" value:( getINISetting filename sectionIniKey "ShadingImportance" ) options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "ObjectImportance" ( Property displayName:"Object Importance" value:( getINISetting filename sectionIniKey "ObjectImportance" ) options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "SkinningImportance" ( Property displayName:"Skinning Importance" value:( getINIsetting filename sectionIniKey "SkinningImportance" ) options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/FeaturePreservationSection/VertexWeights"
settingsSection = RsSimplygonSettingsSection displayName:"Vertex Weights" sectionName:sectionIniKey order:2
settingsSection.addProperty "IsEnabled" ( Property displayName:"Use Weights" value:( execute ( getINISetting filename sectionIniKey "IsEnabled" ) ) options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "WeightsMultiplier" ( Property displayName:"Weights Factor" value:( getINIsetting filename sectionIniKey "WeightsMultiplier" ) options:#( "x1/4", "x1/2", "x1", "x2", "x4" ) tooltip:"Use this factor to balance vertex weights" )
settingsSection.addProperty "VertexWeightsChannel" ( Property displayName:"Map Channel" value:( ( getINISetting filename sectionIniKey "VertexWeightsChannel" ) as integer ) visible:false options:[ 8, 8, 8 ] tooltip:"Rockstar's reserved mapping channel for Simplygon. This cannot be changed." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/RepairSection"
settingsSection = RsSimplygonSettingsSection displayName:"Mesh Repair" sectionName:sectionIniKey order:4
settingsSection.addProperty "WeldingThreshold" ( Property displayName:"Welding Threshold" value:( ( getINISetting filename sectionIniKey "WeldingThreshold" ) as float ) options:[ -9999.0, 9999.0, 0.0 ] tooltip:"All the mesh vertices at a distance this threshold will be merged together. Usually this value is set to zero, in order to weld all vertices that happen to be duplicates. In some cases however increasing the value might repair poorly made models." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/RepairSection/NormalCalcSection"
settingsSection = RsSimplygonSettingsSection displayName:"Normal Calculation" sectionName:sectionIniKey order:5
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:( execute ( getINISetting filename sectionIniKey "IsEnabled" ) ) options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "HardAngle" ( Property displayName:"Hard Angle" value:( ( getINISetting filename sectionIniKey "HardAngle" ) as integer ) options:[ 0, 180, 90 ] tooltip:"The Hard Angle Cutoff value specifies an angle at which the normals are considered hard." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/SymmetrySection"
settingsSection = RsSimplygonSettingsSection displayName:"Mesh Symmetry" sectionName:sectionIniKey order:6
settingsSection.addProperty "UseSymmetry" ( Property displayName:"Use Symmetry" value:( execute ( getINISetting filename sectionIniKey "UseSymmetry" ) ) options:undefined tooltip:"If checked, the reduction will take symmetry into calculations." )
settingsSection.addProperty "SymmetryAxis" ( Property displayName:"Symmetry Axis" value:( getINISetting filename sectionIniKey "SymmetryAxis" ) options:#( "X", "Y", "Z" ) tooltip:"Axis to be used for symmetry calculations." )
settingsSection.addProperty "SymmetryOffset" ( Property displayName:"Symmetry Offset" value:( ( getINISetting filename sectionIniKey "SymmetryOffset" ) as float ) options:[ -9999.0, 9999.0, 0.0 ] tooltip:"The position of the symmetry plane along the plane axis." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection"
settingsSection = RsSimplygonSettingsSection displayName:"Material LOD" sectionName:sectionIniKey order:7
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:( execute ( getINISetting filename sectionIniKey "IsEnabled" ) ) tooltip:"Enables this section" )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/TexCoordsGenerationSection"
settingsSection = RsSimplygonSettingsSection displayName:"Auto Unwrap New UVs" sectionName:sectionIniKey order:8
settingsSection.addProperty "GutterSpace" ( Property displayName:"Gutter Space (px)" value:( ( getINISetting filename sectionIniKey "GutterSpace" ) as integer ) options:[ 4, 20, 4 ] tooltip:"Gutter Space setting, in pixels, for the minimum distace between generated texture charts." )
settingsSection.addProperty "MaxStretch" ( Property displayName:"UV Stretch" value:( getINISetting filename sectionIniKey "MaxStretch" ) options:#( "None", "Small", "Medium", "Large", "Very Large" ) tooltip:"This parameter specifies how much stretch is allowed in the auto unwrapped UVs. 'None' means that triangle size and angles have same relative proportions in both geometric and texture space 'Very Large' means it can differ greatly, and two triangles of same size and shape in geometric space can look vastly different in texture space." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/RebakeMapsSection"
settingsSection = RsSimplygonSettingsSection displayName:"Rebake New Maps" sectionName:sectionIniKey order:9
settingsSection.addProperty "Dimensions" ( Property displayName:"Texture Size (px)" value:( getINISetting filename sectionIniKey "Dimensions" ) options:#( "16x16", "32x32", "64x64", "128x128", "256x256", "512x512", "1024x1024", "2048x2048", "4096x4096" ) tooltip:"The pixel size of the generated maps." )
settingsSection.addProperty "Supersampling" ( Property displayName:"Bake Quality" value:( getINISetting filename sectionIniKey "Supersampling" ) options:#( "High", "Medium", "Low", "Poor" ) tooltip:"Rebaking of new maps is done by sampling the old maps, this setting defines the sampling quality. The higher the quality, the longer the processing time." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/Ambient"
settingsSection = RsSimplygonSettingsSection displayName:"Ambient" sectionName:sectionIniKey order:10
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:( execute ( getINISetting filename sectionIniKey "IsEnabled" ) ) options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "sRGB" ( Property displayName:"sRGB" value:( execute ( getINISetting filename sectionIniKey "sRGB" ) ) options:undefined tooltip:"If set, sRGB values will be generated by the caster." )
settingsSection.addProperty "BakeVertexColors" ( Property displayName:"Bake Vertex Colors" value:( execute ( getINISetting filename sectionIniKey "BakeVertexColors" ) ) options:undefined tooltip:"If set, vertex colors will be baked into the result by the caster." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/Diffuse"
settingsSection = RsSimplygonSettingsSection displayName:"Diffuse" sectionName:sectionIniKey order:11
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:( execute ( getINISetting filename sectionIniKey "IsEnabled" ) ) options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "sRGB" ( Property displayName:"sRGB" value:false options:( execute ( getINISetting filename sectionIniKey "sRGB" ) ) tooltip:"If set, sRGB values will be generated by the caster." )
settingsSection.addProperty "BakeVertexColors" ( Property displayName:"Bake Vertex Colors" value:( execute ( getINISetting filename sectionIniKey "BakeVertexColors" ) ) options:undefined tooltip:"If set, vertex colors will be baked into the result by the caster." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/Specular"
settingsSection = RsSimplygonSettingsSection displayName:"Specular" sectionName:sectionIniKey order:12
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:( execute ( getINISetting filename sectionIniKey "IsEnabled" ) ) options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "sRGB" ( Property displayName:"sRGB" value:( execute ( getINISetting filename sectionIniKey "sRGB" ) ) options:undefined tooltip:"If set, sRGB values will be generated by the caster." )
settingsSection.addProperty "BakeVertexColors" ( Property displayName:"Bake Vertex Colors" value:( execute ( getINISetting filename sectionIniKey "BakeVertexColors" ) ) options:undefined tooltip:"If set, vertex colors will be baked into the result by the caster." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/Normals"
settingsSection = RsSimplygonSettingsSection displayName:"Normals" sectionName:sectionIniKey order:13
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:( execute ( getINISetting filename sectionIniKey "IsEnabled" ) ) options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "FlipBackfacingNormals" ( Property displayName:"Flip Backfacing Normals" value:( execute ( getINISetting filename sectionIniKey "FlipBackfacingNormals" ) ) options:undefined tooltip:"If set, then normals in the source geometry that point into the triangles of the processed geometry will be flipped to point outwards. This should only be used on geometries with known normal errors, as the result may be inferior on geometries with well-behaved normals." )
settingsSection.addProperty "TangentSpaceNormals" ( Property displayName:"Tangent Space Normals" value:( execute ( getINISetting filename sectionIniKey "TangentSpaceNormals" ) ) options:undefined tooltip:"If set, generate a normal map with tangent space normals. If not set, the normals in the map will be world-space." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/UserMapSection"
settingsSection = RsSimplygonSettingsSection displayName:"User Channels" sectionName:sectionIniKey order:14
settingsSection.addProperty "MapCount" ( Property displayName:"Num Channels" value:( ( getINISetting filename sectionIniKey "MapCount" ) as integer ) options:[ 0, 0, 0 ] tooltip:"Number of channels" )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/BoneReductionSection"
settingsSection = RsSimplygonSettingsSection displayName:"Bone LOD" sectionName:sectionIniKey order:15
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:( execute ( getINISetting filename sectionIniKey "IsEnabled" ) ) options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "BoneReductionMetricType" ( Property displayName:"Bone LOD Type" value:( getINISetting filename sectionIniKey "BoneReductionMetricType" ) options:#( "Number of Bones" ) tooltip:"Set the reduction metric type. 'On-Screen Size' will reduce the bones until any reduction will result in an error larger than one pixel when viewed at the specified size on-screen. 'Number of Percent' will reduce until the number of bones are reached." )
settingsSection.addProperty "ReductionRatio" ( Property displayName:"Number of Bones (%)" value:( ( getINISetting filename sectionIniKey "ReductionRatio" ) as float ) options:[ 0.0, 100.0, 50.0 ] tooltip:"The number of bones for the BoneLOD, measured as a percentage of the Nr bones in the original model. For example if the base model has 100 bones, setting Number Bones to 25% will generate a BoneLOD with 25 bones." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/BoneReductionSection/BonesPerVertexSection"
settingsSection = RsSimplygonSettingsSection displayName:"Bones Per Vertex" sectionName:sectionIniKey order:16
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:( execute ( getINISetting filename sectionIniKey "IsEnabled" ) ) options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "BonesPerVertex" ( Property displayName:"Num Bones Per Vertex" value:( ( getINISetting filename sectionIniKey "BonesPerVertex" ) as integer ) options:[ 1, 4, 4 ] tooltip:"Sets the maximum number of bones per vertex." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
append this.lodCollections lodCollection
)
),
fn addLodLevel = (
/*
Adds a new lod level to the settings.
*/
struct Property
(
visible = true,
displayName = undefined,
tooltip = "",
value = undefined,
options = undefined
)
this.lodCount += 1
local lodCollection = dotNetObject "System.Collections.Hashtable"
-- The lod number is 0-based for Simplygon.
local lodNum = this.lodCount - 1
local sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section"
local settingsSection = RsSimplygonSettingsSection displayName:"General" sectionName:sectionIniKey order:1 advanced:false
settingsSection.addProperty "ProcessingType" ( Property displayName:"LOD Type" value:"MeshLOD" options:#( "MeshLOD" ) visible:false tooltip:"MeshLODs are created by removing edges and vertices from the original mesh, while preserving critical features and all relevant original vertex data. Mesh LODs are often used for creating a set of AutoLODs for each prop and character in a game, in order to reduce triangle count. ProxyLODs are made by generating one new mesh (proxy mesh) and one new set of textures (proxy maps). The new mesh and texture resemble a copy of the base model, which looks similar to the base model at the defined LOD switch onscreen size. Proxy LODs are often used to replace groups of static objects with many materials and meshes, at a distance in a game scene. Switching to a Proxy LOD thus significantly reduces both the number of draw calls and triangle counts, specially in large outdoor scenes. Using Proxy LODs sometimes be referred to as hierarchical LODs or LOD parents since they replace a group of objects with one proxy LOD." )
settingsSection.addProperty "ReductionMetricType" ( Property displayName:"LOD Switch" value:"Number Triangles" visible:false options:#( "Number Triangles" ) tooltip:"Set the reduction metric type. 'On-Screen Size' will reduce the geometry until any reduction will result in an error larger than one pixel when viewed at the specified size on-screen. 'Triangle Percent' will reduce until the number of triangles are reached." )
settingsSection.addProperty "ReductionRatio" ( Property displayName:"Number Triangles (%)" value:50.0 options:[ 0.0, 100.0, 50.0 ] tooltip:"The number of triangles for the MeshLOD, measured as a percentage of the Nr triangles in the base model. For example if the base model has 10 000 triangles, setting Number Triangle to 50% will generate a MeshLOD with 5 000 triangles." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/FeaturePreservationSection"
settingsSection = RsSimplygonSettingsSection displayName:"Feature Quality" sectionName:sectionIniKey order:3
settingsSection.addProperty "VertexColorImportance" ( Property displayName:"Vertex Color Importance" value:"Normal" options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "GeometricImportance" ( Property displayName:"Geometric Importance" value:"Normal" options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "MaterialImportance" ( Property displayName:"Material Importance" value:"Normal" options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "ShadingImportance" ( Property displayName:"Shading Importance" value:"Normal" options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "ObjectImportance" ( Property displayName:"Object Importance" value:"Normal" options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
settingsSection.addProperty "SkinningImportance" ( Property displayName:"Skinning Importance" value:"Normal" options:#( "Highest", "High", "Normal", "Low", "Lowest", "Off" ) tooltip:"Settings, used to specify the importance of different features to preserve during mesh LOD creation. Note that lowering each feature preservation quality will lead to higher triangle reduction at a certain LOD switch size, at the cost of poorer LOD quality, and vice versa." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/FeaturePreservationSection/VertexWeights"
settingsSection = RsSimplygonSettingsSection displayName:"Vertex Weights" sectionName:sectionIniKey order:2
settingsSection.addProperty "IsEnabled" ( Property displayName:"Use Weights" value:true options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "WeightsMultiplier" ( Property displayName:"Weights Factor" value:"x4" options:#( "x1/4", "x1/2", "x1", "x2", "x4" ) tooltip:"Use this factor to balance vertex weights" )
settingsSection.addProperty "VertexWeightsChannel" ( Property displayName:"Map Channel" value:8 options:[ 8, 8, 8 ] visible:false tooltip:"Rockstar's reserved mapping channel for Simplygon. This cannot be changed." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/RepairSection"
settingsSection = RsSimplygonSettingsSection displayName:"Mesh Repair" sectionName:sectionIniKey order:4
settingsSection.addProperty "WeldingThreshold" ( Property displayName:"Welding Threshold" value:0.0 options:[ -9999.0, 9999.0, 0.0 ] tooltip:"All the mesh vertices at a distance this threshold will be merged together. Usually this value is set to zero, in order to weld all vertices that happen to be duplicates. In some cases however increasing the value might repair poorly made models." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/RepairSection/NormalCalcSection"
settingsSection = RsSimplygonSettingsSection displayName:"Normal Calculation" sectionName:sectionIniKey order:5
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:false options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "HardAngle" ( Property displayName:"Hard Angle" value:90 options:[ 0, 180, 90 ] tooltip:"The Hard Angle Cutoff value specifies an angle at which the normals are considered hard." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/MeshReductionQualitySection/SymmetrySection"
settingsSection = RsSimplygonSettingsSection displayName:"Mesh Symmetry" sectionName:sectionIniKey order:6
settingsSection.addProperty "UseSymmetry" ( Property displayName:"Use Symmetry" value:false options:undefined tooltip:"If checked, the reduction will take symmetry into calculations." )
settingsSection.addProperty "SymmetryAxis" ( Property displayName:"Symmetry Axis" value:"Y" options:#( "X", "Y", "Z" ) tooltip:"Axis to be used for symmetry calculations." )
settingsSection.addProperty "SymmetryOffset" ( Property displayName:"Symmetry Offset" value:0.0 options:[ -9999.0, 9999.0, 0.0 ] tooltip:"The position of the symmetry plane along the plane axis." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection"
settingsSection = RsSimplygonSettingsSection displayName:"Material LOD" sectionName:sectionIniKey order:7
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:false tooltip:"Enables this section" )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/TexCoordsGenerationSection"
settingsSection = RsSimplygonSettingsSection displayName:"Auto Unwrap New UVs" sectionName:sectionIniKey order:8
settingsSection.addProperty "GutterSpace" ( Property displayName:"Gutter Space (px)" value:4 options:[ 4, 20, 4 ] tooltip:"Gutter Space setting, in pixels, for the minimum distace between generated texture charts." )
settingsSection.addProperty "MaxStretch" ( Property displayName:"UV Stretch" value:"Medium" options:#( "None", "Small", "Medium", "Large", "Very Large" ) tooltip:"This parameter specifies how much stretch is allowed in the auto unwrapped UVs. 'None' means that triangle size and angles have same relative proportions in both geometric and texture space 'Very Large' means it can differ greatly, and two triangles of same size and shape in geometric space can look vastly different in texture space." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/RebakeMapsSection"
settingsSection = RsSimplygonSettingsSection displayName:"Rebake New Maps" sectionName:sectionIniKey order:9
settingsSection.addProperty "Dimensions" ( Property displayName:"Texture Size (px)" value:"64x64" options:#( "16x16", "32x32", "64x64", "128x128", "256x256", "512x512", "1024x1024", "2048x2048", "4096x4096" ) tooltip:"The pixel size of the generated maps." )
settingsSection.addProperty "Supersampling" ( Property displayName:"Bake Quality" value:"Low" options:#( "High", "Medium", "Low", "Poor" ) tooltip:"Rebaking of new maps is done by sampling the old maps, this setting defines the sampling quality. The higher the quality, the longer the processing time." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/Ambient"
settingsSection = RsSimplygonSettingsSection displayName:"Ambient" sectionName:sectionIniKey order:10
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:false options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "sRGB" ( Property displayName:"sRGB" value:false options:undefined tooltip:"If set, sRGB values will be generated by the caster." )
settingsSection.addProperty "BakeVertexColors" ( Property displayName:"Bake Vertex Colors" value:false options:undefined tooltip:"If set, vertex colors will be baked into the result by the caster." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/Diffuse"
settingsSection = RsSimplygonSettingsSection displayName:"Diffuse" sectionName:sectionIniKey order:11
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:false options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "sRGB" ( Property displayName:"sRGB" value:false options:undefined tooltip:"If set, sRGB values will be generated by the caster." )
settingsSection.addProperty "BakeVertexColors" ( Property displayName:"Bake Vertex Colors" value:false options:undefined tooltip:"If set, vertex colors will be baked into the result by the caster." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/Specular"
settingsSection = RsSimplygonSettingsSection displayName:"Specular" sectionName:sectionIniKey order:12
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:false options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "sRGB" ( Property displayName:"sRGB" value:false options:undefined tooltip:"If set, sRGB values will be generated by the caster." )
settingsSection.addProperty "BakeVertexColors" ( Property displayName:"Bake Vertex Colors" value:false options:undefined tooltip:"If set, vertex colors will be baked into the result by the caster." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/Normals"
settingsSection = RsSimplygonSettingsSection displayName:"Normals" sectionName:sectionIniKey order:13
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:false options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "FlipBackfacingNormals" ( Property displayName:"Flip Backfacing Normals" value:false options:undefined tooltip:"If set, then normals in the source geometry that point into the triangles of the processed geometry will be flipped to point outwards. This should only be used on geometries with known normal errors, as the result may be inferior on geometries with well-behaved normals." )
settingsSection.addProperty "TangentSpaceNormals" ( Property displayName:"Tangent Space Normals" value:false options:undefined tooltip:"If set, generate a normal map with tangent space normals. If not set, the normals in the map will be world-space." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/ReductionMappingSection/CastChannelsSection/UserMapSection"
settingsSection = RsSimplygonSettingsSection displayName:"User Channels" sectionName:sectionIniKey order:14
settingsSection.addProperty "MapCount" ( Property displayName:"Num Channels" value:0 options:[ 0, 0, 0 ] tooltip:"Number of channels" )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/BoneReductionSection"
settingsSection = RsSimplygonSettingsSection displayName:"Bone LOD" sectionName:sectionIniKey order:15
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:false options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "BoneReductionMetricType" ( Property displayName:"Bone LOD Type" value:"Number of Bones" options:#( "Number of Bones" ) tooltip:"Set the reduction metric type. 'On-Screen Size' will reduce the bones until any reduction will result in an error larger than one pixel when viewed at the specified size on-screen. 'Number of Percent' will reduce until the number of bones are reached." )
settingsSection.addProperty "ReductionRatio" ( Property displayName:"Number of Bones (%)" value:50.0 options:[ 0.0, 100.0, 50.0 ] tooltip:"The number of bones for the BoneLOD, measured as a percentage of the Nr bones in the original model. For example if the base model has 100 bones, setting Number Bones to 25% will generate a BoneLOD with 25 bones." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
sectionIniKey = "Root/LODCollectionSection/LOD" + lodNum as string + "Section/BoneReductionSection/BonesPerVertexSection"
settingsSection = RsSimplygonSettingsSection displayName:"Bones Per Vertex" sectionName:sectionIniKey order:16
settingsSection.addProperty "IsEnabled" ( Property displayName:"Is Enabled" value:false options:undefined tooltip:"Enables this section" )
settingsSection.addProperty "BonesPerVertex" ( Property displayName:"Num Bones Per Vertex" value:4 options:[ 1, 4, 4 ] tooltip:"Sets the maximum number of bones per vertex." )
lodCollection.Add settingsSection.sectionName ( dotNetMXSValue settingsSection )
append this.lodCollections lodCollection
this.dirty = true
),
on create do (
this.addLodLevel()
)
)
struct RsSimplygonXmlSettings
(
private
collisionMaterials = #(),
public
fn getCollisionMaterials = (
this.collisionMaterials
),
fn load = (
this.collisionMaterials = #()
struct CollisionMaterial
(
name = undefined,
pushAmount = undefined
)
local simplygonXmlFile = RsConfigGetToolsDir() + "etc/config/simplygon/simplygon.xml"
if not ( doesFileExist simplygonXmlFile ) then (
gRsPerforce.sync simplygonXmlFile
)
stream = dotNetObject "System.IO.StreamReader" simplygonXmlFile
doc = dotNetObject "System.Xml.XmlDocument"
doc.load stream
root = doc.documentElement
local collisionMaterialNodes = ( root.SelectNodes ".//collisionSettings//collisionMaterials//collisionMaterial" )
for i = 0 to ( collisionMaterialNodes.count - 1 ) do (
local collisionMaterialNode = collisionMaterialNodes.item[ i ]
local collMat = CollisionMaterial()
collMat.name = collisionMaterialNode.attributes.ItemOf[ 0 ].value
collMat.pushAmount = ( collisionMaterialNode.attributes.ItemOf[ 1 ].value ) as float
append this.collisionMaterials collMat
)
doc = undefined
stream.close()
stream.dispose()
stream = undefined
gc()
),
on create do (
this.load()
)
)
struct RsSimplygonCore
(
/*
Core framework for interfacing with Simplygon.
*/
private
pluginFilename = "SimplygonMax2012Releasex64.dlu",
-- Any map verts using the following color will be selected and locked from decimation.
lockedVertColor = [ 1, 0, 0 ],
-- Reserved for artists to paint decimation weighting.
mapChannel = 8,
-- Default Settings
defaultBatchMode = true,
defaultLockSelectedVertices = true,
defaultShowProgress = true,
defaultVertexChannels = #{ 8..30 },
defaultSettingsFilename = RsConfigGetToolsDir() + "etc/config/simplygon/default.ini",
public
settings = RsSimplygonSettings(),
xmlSettings = RsSimplygonXmlSettings(),
fn getPluginFilename = (
this.pluginFilename
),
fn isSdkInstalled = (
local result = true
try (
sgsdk_getBatchMode()
) catch (
result = false
)
result
),
fn getLockedVertColor = (
this.lockedVertColor
),
fn getMapChannel = (
this.mapChannel
),
fn process objs:undefined = (
local result = false
if objs == undefined then (
objs = for obj in selection where ( superClassOf obj ) == GeometryClass or ( classOf obj ) == Col_Mesh collect obj
) else if ( classof objs ) != Array then (
objs = #( objs )
)
if objs.count > 0 then (
clearSelection()
local collObjs = #()
local processedObjs = #()
for obj in objs do (
-- Track collision objects separately, so that we can turn them back into collision once Simplygon has had it's way with them.
if ( classof obj ) == Col_Mesh then (
-- Convert to a mesh so that Simplygon can process it.
col2Mesh obj
append collObjs obj
)
if ( superClassOf obj ) == GeometryClass then (
selectMore obj
append processedObjs obj
)
)
-- TODO: Check if the user cancelled, deal with mid-state data.
local success = false
try (
sgsdk_ProcessSelectedGeometries()
success = true
) catch (
)
result = #()
if success then (
-- Find the processed lod objects from Simplygon, and return them.
for obj in processedObjs do (
local lodObjs = ( execute ( "$" + obj.name + "_LOD*" ) ) as array
-- Convert objects back to collision.
local convertBackToCollision = false
if ( findItem collObjs obj ) != 0 then (
convertBackToCollision = true
)
for lodObj in lodObjs do (
if convertBackToCollision do (
mesh2col lodObj
)
-- Hayes: Fix vertex color issue that's happening on map channels.
-- I suspect that Simplygon is trying to be smart and optimize the data in the vertex color channel, and screwing up the
-- indices.
if not convertBackToCollision then (
local fixMapChannels = #( -2, 9 )
for fixMapChannel in fixMapChannels do (
if ( meshop.getMapSupport lodObj fixMapChannel ) then (
format "[Simplygon Toolkit] Fixing vertex color channel issue on map channel %.\n" fixMapChannel
local vertexPaintMod = VertexPaint()
vertexPaintMod.mapChannel = fixMapChannel
addModifier lodObj vertexPaintMod
collapseStack lodObj
)
)
)
appendIfUnique result lodObj
)
)
)
) else (
MessageBox "You must supply at least one object to process!" title:"Rockstar"
)
result
),
fn loadSettings filename = (
local result = false
if ( doesFileExist filename ) then (
this.settings.load filename
result = sgsdk_ImportSimplygonSettings filename
)
result
),
fn reset = (
sgsdk_Reset()
this.loadSettings this.defaultSettingsFilename
this.showProgress this.defaultShowProgress
this.setBatchMode this.defaultBatchMode
this.setLockSelectedVertices this.defaultLockSelectedVertices
-- Tell map channels to be vertex channels.
local vertexChannels = this.defaultVertexChannels as array
for vc in vertexChannels do (
this.setIsVertexColorChannel vc true
)
),
fn getLockSelectedVertices = (
sgsdk_getLockSelectedVertices()
),
fn setLockSelectedVertices state = (
sgsdk_setLockSelectedVertices state
),
fn setBatchMode state = (
sgsdk_setBatchMode state
),
fn showProgress state = (
sgsdk_setShowProgress state
),
fn setIsVertexColorChannel mapChannel state = (
sgsdk_setIsVertexColorChannel mapChannel state
),
on create do (
if ( this.isSdkInstalled() ) then (
this.reset()
)
)
)
struct RsSimplygonUtils
(
/*
Miscellaneous utilities for working with Simplygon. Some of these are extremely specific to meet workflow needs.
*/
private
fn recurseFindFaceIsland obj faceId &currentIsland &faceList = (
/*
Description:
Recursively finds all of the faces connected to the supplied face id who form an island. Takes a by-reference array to fill up, and a by-reference face list to compare against.
Typically, you'd supply the selected faces as the faceList.
Author:
Jason Hayes <jason.hayes@rockstarsandiego.com>
*/
if ( findItem currentIsland faceId ) == 0 and ( findItem faceList faceId ) != 0 then (
append currentIsland faceId
local edges = polyop.getEdgesUsingFace obj faceId
if edges != undefined then (
for edgeId in edges do (
local faceNeighbors = ( polyop.getFacesUsingEdge obj edgeId ) as array
if faceNeighbors != undefined then (
for faceNeighborId in faceNeighbors do (
this.recurseFindFaceIsland obj faceNeighborId &currentIsland &faceList
)
)
)
)
)
),
public
fn displayMapChannel obj = (
/*
Author: Jason Hayes <jason.hayes@rockstarsandiego.com>
Description:
Set the incoming object to display the Simplygon map channel.
*/
obj.showVertexColors = true
obj.vertexColorType = #map_channel
obj.vertexColorMapChannel = ( gRsSimplygonCore.getMapChannel() )
),
fn floodFillVertsUsingColor obj vertColor vertSelectionOnly:false ignoreRedVerts:false materialIds:undefined = (
/*
Author: Jason Hayes <jason.hayes@rockstarsandiego.com>
Description:
Sets the vertex colors on the object to the incoming color. Optionally only flood fill the selected vertices.
*/
local mapChannel = gRsSimplygonCore.getMapChannel()
if ( classof obj ) == Editable_Mesh then (
convertTo obj Editable_Poly
)
if not ( polyop.getMapSupport obj mapChannel ) then (
polyop.setMapSupport obj mapChannel true
)
local numVerts = polyop.getNumVerts obj
local vertices = #{ 1..numVerts }
local faces = #()
if vertSelectionOnly == true then (
vertices = polyop.getVertSelection obj
)
if materialIds != undefined then (
if materialIds.count > 0 then (
local numFaces = polyop.getNumFaces obj
for faceId = 1 to numFaces do (
local faceMatId = polyop.getFaceMatId obj faceId
if ( findItem materialIds faceMatId ) != 0 then (
appendIfUnique faces faceId
)
)
vertices = polyop.getVertsUsingFace obj ( faces as bitarray )
)
)
local redVerts = undefined
if ignoreRedVerts then (
redVerts = this.getLockedVertsByVertColor obj
for redVert in redVerts do (
local idx = findItem vertices redVert
if idx != 0 then (
deleteItem vertices idx
)
)
)
if faces.count > 0 then (
polyop.setFaceColor obj mapChannel faces vertColor
) else (
polyop.setVertColor obj mapChannel vertices vertColor
)
),
fn getLockedVertsByVertColor obj = (
/*
Author: Jason Hayes <jason.hayes@rockstarsandiego.com>
Description:
Finds and returns all of the vertices who are painted red in the reserved Simplygon map channel. These vertices will be locked
when processed in Simplygon.
*/
local vertColor = gRsSimplygonCore.getLockedVertColor()
local mapChannel = gRsSimplygonCore.getMapChannel()
local vertices = undefined
local threshold = 0.15
if ( classof obj ) == Editable_Mesh then (
convertTo obj Editable_Poly
)
if ( classof obj ) == Editable_Poly then (
if ( polyop.getMapSupport obj mapChannel ) == true then (
vertices = polyop.getVertsByColor obj vertColor threshold threshold threshold channel:mapChannel
) else (
messageBox ( "There is no map channel " + mapChannel as string + " for object (" + obj.name + ")! Cannot get the locked verts using vertex colors." ) title:"Rockstar"
)
)
vertices
),
fn getOpenEdges obj = (
local vertices = undefined
if ( classof obj ) == Editable_Mesh then (
convertTo obj Editable_Poly
)
if ( classof obj ) == Editable_Poly then (
vertices = polyop.getVertsUsingEdge obj ( polyop.getOpenEdges obj )
)
vertices
),
fn getFaceIslands obj faceList = (
/*
Description:
Finds all of the face islands in the supplied face list, and groups them together into a multi-dimensional array.
Author:
Jason Hayes <jason.hayes@rockstarsandiego.com>
*/
local faceIslands = #()
if ( classof obj ) == Editable_Mesh then (
convertTo obj Editable_Poly
)
for faceId in faceList do (
-- Is the face id in any of the current islands. If it isn't, start a new island search.
local faceAlreadyInIsland = false
for faceIsland in faceIslands do (
if ( findItem faceIsland faceId ) != 0 then (
faceAlreadyInIsland = true
)
)
if not faceAlreadyInIsland then (
local currentIsland = #()
-- Start a new island search from the current face id
this.recurseFindFaceIsland obj faceId &currentIsland &faceList
if currentIsland.count > 0 then (
append faceIslands currentIsland
)
)
)
faceIslands
),
fn deselectIslands obj numTriangles:6 = (
/*
Description:
Deselects islands in the current face selection who are equal to or less than the number of triangles specified.
Author:
Jason Hayes <jason.hayes@rockstarsandiego.com>
*/
if obj != undefined then (
undo "Deselect Face Islands" on (
if ( classof obj ) == Editable_Mesh then (
convertTo obj Editable_Poly
setSelectionLevel obj #face
)
local selectedFaces = ( polyop.getFaceSelection obj ) as array
if selectedFaces.count > 0 then (
local faceIslands = this.getFaceIslands obj selectedFaces
selectedFaces = selectedFaces as bitarray
for faceIsland in faceIslands do (
if faceIsland.count <= numTriangles then (
faceIsland = faceIsland as bitarray
selectedFaces = selectedFaces - faceIsland
)
)
polyop.setFaceSelection obj selectedFaces
redrawViews()
)
)
)
),
fn detachAndRenameFaceSelection obj suffix:"_w" = (
/*
Description:
Detaches the current face selection as a new object. If detachFaceIslands is true, then each island in the face selection
will be detached as a separate object.
Author:
Jason Hayes <jason.hayes@rockstarsandiego.com>
*/
if obj != undefined then (
suspendEditing()
undo "Detach and Rename Face Selection" on (
local convertedToPoly = false
if ( classof obj ) == Editable_Mesh then (
convertTo obj Editable_Poly
setSelectionLevel obj #face
convertedToPoly = true
)
faceList = ( polyop.getFaceSelection obj ) as array
if faceList.count > 0 then (
local newName = UniqueName obj.name
if ( polyop.detachFaces obj faceList delete:true asNode:true name:newName ) then (
update obj
local newObj = getNodeByName newName
newObj.name += suffix
newObj.wirecolor = Color ( random 0 255 ) ( random 0 255 ) ( random 0 255 )
select newObj
if convertedToPoly then (
convertToMesh obj
)
) else (
messageBox "An unknown error occurred while attempting to detach the faces!" title:"Rockstar"
)
) else (
messageBox "Please select at least one face!" title:"Rockstar"
)
)
resumeEditing()
)
),
fn operateOnFilteredCollisionVertices hdMesh collMesh collMatData selectVerts pushVerts colorizeVerts ignoreRedVertsOnPush:false = (
-- TODO: Check terrain utils for the terrain map channel.
local terrainMapChannel = 9
fn vertexColorsWithinThreshold a b threshold = (
local x = abs ( b.x - a.x )
local y = abs ( b.y - a.y )
local z = abs ( b.z - a.z )
( x <= threshold ) and ( y <= threshold ) and ( z <= threshold )
)
local result = undefined
if collMesh != undefined then (
if ( classof collMesh ) == Col_Mesh then (
local collMatTable = dotNetObject "System.Collections.Hashtable"
-- Setup hashtable with the incoming collision material data.
for collMat in collMatData do (
collMatTable.Add collMat.type ( dotNetMxsValue collMat )
)
-- Create a copy of the incoming collision mesh and work on it instead.
local newCollMesh = collMesh
if ( classof newCollMesh ) == Col_Mesh then (
col2Mesh newCollMesh
)
-- Transfer terrain paint channel to the collision mesh. This will be used to further refine what verts get pushed and colorized.
convertTo newCollMesh Editable_Poly
if not ( polyop.getMapSupport newCollMesh terrainMapChannel ) then (
polyop.setMapSupport newCollMesh terrainMapChannel true
)
RsProjectVertexMap hdMesh newCollMesh SRCchannel:terrainMapChannel TGTchannel:terrainMapChannel
convertTo newCollMesh Editable_Poly
local filteredVertices = #()
local numFaces = polyop.getNumFaces newCollMesh
local simplygonMapChannel = ( gRsSimplygonCore.getMapChannel() )
local collMat = newCollMesh.material
local vertsToColorBlack = #()
local vertsToColorGreen = #()
local openEdgeVerts = this.getOpenEdges newCollMesh
local redVerts = this.getLockedVertsByVertColor newCollMesh
for faceId = 1 to numFaces do (
local matId = polyop.getFaceMatId newCollMesh faceId
local rexMtl = undefined
if ( classof collMat ) == Multimaterial then (
rexMtl = collMat.materialList[ matId ]
) else (
rexMtl = collMat
)
if ( classof rexMtl ) == RexBoundMtl then (
local collName = RexGetCollisionName rexMtl
if ( collMatTable.Contains collName ) then (
local matData = collMatTable.Item[ collName ].value
-- Look into the terrain map channel.
local faceMapVerts = polyop.getMapFace newCollMesh terrainMapChannel faceId
if colorizeVerts then (
for vertId in faceMapVerts do (
local simplygonMapVert = polyop.getMapVert newCollMesh simplygonMapChannel vertId
local terrainMapVert = polyop.getMapVert newCollMesh terrainMapChannel vertId
-- Only look at verts colored black in the Simplygon map channel.
if ( vertexColorsWithinThreshold simplygonMapVert [ 0, 0, 0 ] 0.1 ) then (
appendIfUnique vertsToColorGreen vertId
for vertColor in matData.vertexColors do (
if ( vertexColorsWithinThreshold terrainMapVert vertColor 0.11 ) then (
appendIfUnique vertsToColorBlack vertId
)
)
)
)
-- Refine by vertex colors.
) else (
if matData.vertexColors.count > 0 then (
for vertId in faceMapVerts do (
local skipLockedVerts = false
if selectVerts or pushVerts then (
if ( findItem openEdgeVerts vertId ) != 0 then (
skipLockedVerts = true
)
if not ignoreRedVertsOnPush then (
if ( findItem redVerts vertId ) != 0 then (
skipLockedVerts = true
)
)
)
if not skipLockedVerts then (
local mapVert = polyop.getMapVert newCollMesh terrainMapChannel vertId
for vertColor in matData.vertexColors do (
if ( vertexColorsWithinThreshold mapVert vertColor 0.1 ) then (
appendIfUnique filteredVertices vertId
appendIfUnique matData.verticesToPush vertId
collMatTable.Remove collName
collMatTable.Add collName ( dotNetMxsValue matData )
)
)
)
)
) else (
for vertId in faceMapVerts do (
appendIfUnique filteredVertices vertId
appendIfUnique matData.verticesToPush vertId
collMatTable.Remove collName
collMatTable.Add collName ( dotNetMxsValue matData )
)
)
)
)
)
)
if selectVerts then (
select newCollMesh
polyop.setVertSelection newCollMesh filteredVertices
subObjectLevel = 1
)
if pushVerts then (
setCommandPanelTaskMode mode:#modify
local newCollMesh = copy collMesh
newCollMesh.name += "__push"
select newCollMesh
local enum = collMatTable.GetEnumerator()
while ( enum.MoveNext() ) do (
local collName = enum.Key
local matData = enum.Value.value
if matData.verticesToPush.count > 0 then (
subObjectLevel = 1
polyop.setVertSelection newCollMesh matData.verticesToPush
modPanel.AddModToSelection ( Push() )
local pushModifier = newCollMesh.modifiers[ #Push ]
if pushModifier != undefined then (
pushModifier.Push_Value = matData.pushAmount
) else (
print ( "ERROR: Could not find the Push modifier for object (" + newCollMesh.name + ")!" )
)
collapseStack newCollMesh
)
)
)
if colorizeVerts then (
if not ( polyop.getMapSupport newCollMesh simplygonMapChannel ) then (
polyop.setMapSupport newCollMesh simplygonMapChannel true
)
polyop.setVertColor newCollMesh simplygonMapChannel vertsToColorGreen [ 0, 255, 0 ]
polyop.setVertColor newCollMesh simplygonMapChannel vertsToColorBlack [ 0, 0, 0 ]
)
result = filteredVertices
) else (
)
) else (
)
result
)
)
gRsSimplygonCore = RsSimplygonCore()
gRsSimplygonUtils = RsSimplygonUtils()