1579 lines
46 KiB
Plaintext
Executable File
1579 lines
46 KiB
Plaintext
Executable File
Filein (RsConfigGetWildwestDir() + "Script/3dsMax/Maps/Materials/terrain_helperFunctions.ms")
|
|
|
|
global gRsTerrainSeamFinder = Undefined
|
|
|
|
-- RstaCompressBitArray:
|
|
-- Reduce size of bitarray to its last-used bit, to help out with memory-usage.
|
|
fn RstaCompressBitArray thisArray =
|
|
(
|
|
local newSize = 0
|
|
for val in thisArray do
|
|
(
|
|
newSize = val
|
|
)
|
|
thisArray.count = newSize
|
|
)
|
|
|
|
-- Struct for collecting terrain-seam find/fix data:
|
|
struct RstaTerrainSeam
|
|
(
|
|
verts = #{}, name = #Default, obj, chan, subChan,
|
|
fn Dispose =
|
|
(
|
|
verts.count = 0
|
|
)
|
|
)
|
|
struct RstaTerrainSeams
|
|
(
|
|
items = #(),
|
|
itemNames = #(),
|
|
|
|
vertWeights = #(),
|
|
commonBlends = #(),
|
|
terrainFaces = #{},
|
|
borderVerts = #{},
|
|
|
|
hasUberTerrain = False,
|
|
|
|
fn GetItem thisName =
|
|
(
|
|
local outVal = Undefined
|
|
|
|
local findNum = (FindItem itemNames thisName)
|
|
if (findNum != 0) do
|
|
(
|
|
outVal = items[findNum]
|
|
)
|
|
|
|
return outVal
|
|
),
|
|
|
|
fn AddItem thisName obj:Undefined chan:Undefined subChan:Undefined =
|
|
(
|
|
local outVal = (GetItem thisName)
|
|
|
|
if (outVal == Undefined) do
|
|
(
|
|
outVal = (RstaTerrainSeam name:thisName obj:obj chan:chan subChan:subChan)
|
|
Append items outVal
|
|
Append itemNames thisName
|
|
)
|
|
|
|
return outVal
|
|
),
|
|
|
|
-- Does struct store data for a specific seam-type?
|
|
fn HasItem thisName =
|
|
(
|
|
(FindItem itemNames thisName) != 0
|
|
),
|
|
|
|
-- Is fix required/requested for a specific seam-type?
|
|
fn ItemNeedsFix thisName =
|
|
(
|
|
local outVal = False
|
|
local thisItem = GetItem thisName
|
|
|
|
if (thisItem != Undefined) do
|
|
(
|
|
outVal = (thisItem.verts.numberSet != 0)
|
|
)
|
|
|
|
return outVal
|
|
),
|
|
|
|
-- Does this struct store seam-items that will require blend-weights to fix?
|
|
fn FixNeedsWeights =
|
|
(
|
|
local lookupChan = gRsTerrainSeamFinder.lookupChan
|
|
|
|
-- Looku at fix-seam items using the Lookup Colours channel
|
|
local usesLookupChan = False
|
|
for thisItem in items where (thisItem.chan == lookupChan) while (not usesLookupChan) do
|
|
(
|
|
-- Does this item have any verts flagged?
|
|
if (thisItem.verts.numberSet != 0) do
|
|
(
|
|
usesLookupChan = True
|
|
)
|
|
)
|
|
|
|
return usesLookupChan
|
|
),
|
|
|
|
-- Return verts stored for a particular seam-type name, if any:
|
|
fn GetVertsByName thisName =
|
|
(
|
|
local thisItem = GetItem thisName
|
|
if (thisItem == Undefined) then
|
|
(
|
|
return #{}
|
|
)
|
|
else
|
|
(
|
|
return thisItem.verts
|
|
)
|
|
),
|
|
|
|
-- Remove unwanted fix-items:
|
|
fn Clean =
|
|
(
|
|
-- Remove empty/unwanted items:
|
|
items = for item in items where (item.verts.numberSet != 0) collect item
|
|
itemNames = for item in items collect item.name
|
|
|
|
-- Compress bitarrays:
|
|
for item in items do
|
|
(
|
|
RstaCompressBitArray item.verts
|
|
)
|
|
|
|
return OK
|
|
),
|
|
|
|
fn Dispose =
|
|
(
|
|
for item in items do item.Dispose()
|
|
for item in vertWeights do item.count = 0
|
|
vertWeights.count = 0
|
|
terrainFaces.count = 0
|
|
borderVerts.count = 0
|
|
)
|
|
)
|
|
|
|
struct sRsTerrainSeamFinder
|
|
(
|
|
-- Terrain-colour channels:
|
|
effectsMaskChan = (RsGetChanByName #TerrainEffectsMask),
|
|
displaceMaskSubChan = 1,
|
|
curveMaskSubChan = 2,
|
|
|
|
lookupChan = (RsGetChanByName #TerrainLookup),
|
|
wetnessChan = (RsGetChanByName #TerrainWetness),
|
|
|
|
-- We can't currently test to see if texture-lookups use uncommon blends
|
|
-- between materials, so we can flag these for replacement with
|
|
-- common-blend vertexcolour-lookups.
|
|
assumeTexLookupCantBlend = True,
|
|
|
|
-- MakeUniqueVecs:
|
|
-- Extends MakeUniqueArray, now combines close-enough vector3/4 values.
|
|
fn MakeUniqueVecs vals threshold:0.001 =
|
|
(
|
|
-- Initial quick uniquification:
|
|
local outVals = MakeUniqueArray vals
|
|
|
|
-- Double-check for near-enough matches...
|
|
if (outVals.count > 1) do
|
|
(
|
|
for n = 1 to outVals.count do
|
|
(
|
|
local valA = outVals[n]
|
|
for m = outVals.count to (n + 1) by -1 do
|
|
(
|
|
if (Distance valA outVals[m] < threshold) do
|
|
(
|
|
DeleteItem outVals m
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
return outVals
|
|
),
|
|
|
|
-- GetMappingValsPerVert:
|
|
-- Returns lists of channel-values per geometry-vertex:
|
|
fn GetMappingValsPerVert obj chan faces: geomToMapVerts: =
|
|
(
|
|
local objOp = (RsMeshPolyOp obj)
|
|
local objGetFaceVerts = (RsGetFaceFunc obj)
|
|
local objGetMapFace = (RsGetMapFaceFunc obj)
|
|
local objGetMapVert = (objOp.GetMapVert)
|
|
|
|
local facesCount = (objOp.GetNumFaces obj)
|
|
local geomVertsCount = (objOp.GetNumVerts obj)
|
|
|
|
if (faces == Unsupplied) do
|
|
(
|
|
faces = #{1..facesCount}
|
|
)
|
|
if (faces.numberSet == 0) do return #()
|
|
|
|
-- Are we going to collect geometry-to-map-vert array?
|
|
local collectMapVerts = (IsKindOf geomToMapVerts Array)
|
|
if collectMapVerts do
|
|
(
|
|
Join geomToMapVerts (for n = 1 to geomVertsCount collect #())
|
|
)
|
|
|
|
local mapValsPerVert = for n = 1 to geomVertsCount collect #()
|
|
for faceNum in faces do
|
|
(
|
|
-- Get face's geometry/mapping verts:
|
|
local faceGeomVerts = (objGetFaceVerts obj faceNum)
|
|
local faceMapVerts = (objGetMapFace obj chan faceNum)
|
|
|
|
-- Collect values from each face-corner:
|
|
for vertIdx = 1 to faceGeomVerts.count do
|
|
(
|
|
local mapVert = faceMapVerts[vertIdx]
|
|
local geomVert = faceGeomVerts[vertIdx]
|
|
|
|
-- Collect face-corner's mask-colour:
|
|
local vertVal = (objGetMapVert obj chan mapVert)
|
|
Append mapValsPerVert[geomVert] vertVal
|
|
|
|
-- Collect geometry-to-map vert:
|
|
if collectMapVerts do
|
|
(
|
|
AppendIfUnique geomToMapVerts[geomVert] mapVert
|
|
)
|
|
)
|
|
)
|
|
|
|
return mapValsPerVert
|
|
),
|
|
|
|
-- Get per-vertex texmap-weight data for obj:
|
|
fn GetObjWeights obj terrMatInfos: =
|
|
(
|
|
PushPrompt "Collecting per-vertex weight data..."
|
|
|
|
-- Get weights per face-corner:
|
|
if (terrMatInfos == Unsupplied) do
|
|
(
|
|
terrMatInfos = (gRsTerrainHelpers.GetObjTerrainFaceData obj)
|
|
--terrMatInfos = for item in terrMatInfos where (item.typeDef.isUberTerrain) collect item
|
|
)
|
|
if (terrMatInfos.count == 0) do return #()
|
|
|
|
local objOp = (RsMeshPolyOp obj)
|
|
local objGetFaceVerts = (RsGetFaceFunc obj)
|
|
|
|
-- Build per-vertex list:
|
|
local geomVertsCount = (objOp.GetNumVerts obj)
|
|
local geomVertLookupWeights = for n = 1 to geomVertsCount collect #()
|
|
|
|
-- Colect face-corner texmap-weights per geometry-vert:
|
|
for terrMatInfo in terrMatInfos do
|
|
(
|
|
-- Get terrain-material descriptor's faces-list:
|
|
local matFaces = (terrMatInfo.GetMatFaces())
|
|
|
|
-- Get texmap-weighting for each faces' vertices:
|
|
-- (ignore texture-lookup, only pay attention to vertex-lookup)
|
|
local matFaceWeights = terrMatInfo.GetFaceVertTexWeights ignoreBitmaps:True
|
|
|
|
-- Get number of diffuse-texture slots in material
|
|
local diffuseCount = terrMatInfo.diffSlotNums.count
|
|
|
|
-- Convert face-vertex texmap-weights, texmap-indices, and lookup-values to per-face arrays:
|
|
local faceIdx = 0
|
|
for faceNum in matFaces do
|
|
(
|
|
-- Get face's geometry-verts:
|
|
local faceGeomVerts = objGetFaceVerts obj faceNum
|
|
|
|
-- Get corresponding face-corner texmap-weights:
|
|
faceIdx += 1
|
|
local thisFaceWeights = matFaceWeights[faceIdx]
|
|
|
|
-- Face's vert-weights list will be empty if vertex-colour lookup-channel was inactive:
|
|
if (thisFaceWeights.count != 0) do
|
|
(
|
|
-- Convert texmap-weight arrays to Point4 vector-values, to allow for quick distance-comparison:
|
|
for vertIdx = 1 to faceGeomVerts.count do
|
|
(
|
|
-- Convert this face-vert's weights to Point4, to allow for quick distance-tests:
|
|
local vertWeights = thisFaceWeights[vertIdx]
|
|
local weightsVec = [0,0,0,0]
|
|
|
|
for n = 1 to vertWeights.count do
|
|
(
|
|
weightsVec[n] = vertWeights[n]
|
|
)
|
|
vertWeights.count = 0
|
|
|
|
-- Collect converted Point4:
|
|
local geomVert = faceGeomVerts[vertIdx]
|
|
Append geomVertLookupWeights[geomVert] weightsVec
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
PopPrompt()
|
|
|
|
return geomVertLookupWeights
|
|
),
|
|
|
|
-- Collects texmap-comparison info between two Terrain Materials:
|
|
fn GetBlendCompareInfo terrInfoA terrInfoB =
|
|
(
|
|
-- Get diffuse-paths and material-Ids:
|
|
local diffPathsA = terrInfoA.diffuseTexPaths
|
|
local diffPathsB = terrInfoB.diffuseTexPaths
|
|
local matNumA = terrInfoA.matId
|
|
local matNumB = terrInfoB.matId
|
|
|
|
local outInfo = DataPair matIds:#(matNumA, matNumB) texmaps:#()
|
|
local texmapsInfo = outInfo.texmaps
|
|
|
|
-- Find lowest diffuse-paths count:
|
|
local compareCount = (Amin diffPathsA.count diffPathsB.count)
|
|
|
|
for texIdx = 1 to compareCount do
|
|
(
|
|
-- Get UV-channels used for this texmap-index:
|
|
local texUVchanA = (terrInfoA.GetTexmapUVchan texIdx)
|
|
local texUVchanB = (terrInfoB.GetTexmapUVchan texIdx)
|
|
|
|
-- Get texmap-paths for this texmap-index:
|
|
local diffPathA = diffPathsA[texIdx]
|
|
local diffPathB = diffPathsB[texIdx]
|
|
|
|
Append texmapsInfo (DataPair paths:#(diffPathA, diffPathB) chans:#(texUVchanA, texUVchanB))
|
|
)
|
|
|
|
return outInfo
|
|
),
|
|
|
|
-- Calculates common-blends between two Terrain Material descriptors:
|
|
fn GetCommonBlends terrInfoA terrInfoB =
|
|
(
|
|
local commonTexIdxs = #{}
|
|
|
|
local compareInfo = (this.GetBlendCompareInfo terrInfoA terrInfoB)
|
|
|
|
-- Find texmap-paths/indexes that are common between these two terrain-materials:
|
|
local texmapsInfo = compareInfo.texmaps
|
|
for texIdx = 1 to texmapsInfo.count do
|
|
(
|
|
-- Get materials' data for this texmap-index:
|
|
local texIdxInfo = texmapsInfo[texIdx]
|
|
|
|
-- Do these materials use the same UV-channel for this texmap-index?
|
|
local texUVchanA = texIdxInfo.chans[1]
|
|
local texUVchanB = texIdxInfo.chans[2]
|
|
local isMatchingTexmap = (texUVchanA == texUVchanB)
|
|
|
|
-- Do these materials have the same texmap-path for this texmap-index?
|
|
if isMatchingTexmap do
|
|
(
|
|
local diffPathA = texIdxInfo.paths[1]
|
|
local diffPathB = texIdxInfo.paths[2]
|
|
isMatchingTexmap = (PathConfig.PathsResolveEquivalent diffPathA diffPathB)
|
|
)
|
|
|
|
commonTexIdxs[texIdx] = isMatchingTexmap
|
|
)
|
|
|
|
return commonTexIdxs
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
-- Find verts using two-layer terrain-shader:
|
|
-- these should only have red/blue blend-colours
|
|
------------------------------------------------------------------------------------------------------
|
|
fn GetTwoLayerVerts obj terrMatInfos: =
|
|
(
|
|
-- Get weights per face-corner:
|
|
if (terrMatInfos == Unsupplied) do
|
|
(
|
|
terrMatInfos = (gRsTerrainHelpers.GetObjTerrainFaceData obj)
|
|
terrMatInfos = for item in terrMatInfos where (item.typeDef.isUberTerrain) collect item
|
|
)
|
|
|
|
local objOp = (RsMeshPolyOp obj)
|
|
|
|
local twoLayerFaces = #{}
|
|
for item in terrMatInfos where (item.diffSlotNums.count == 2) do
|
|
(
|
|
Join twoLayerFaces (item.GetMatFaces())
|
|
)
|
|
|
|
local twoLayerVerts = (objOp.GetVertsUsingFace obj twoLayerFaces)
|
|
RstaCompressBitArray twoLayerVerts
|
|
|
|
return twoLayerVerts
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
-- FindSeams:
|
|
-- Finds vertices that have seamed or invalid terrain-paint data
|
|
------------------------------------------------------------------------------------------------------
|
|
fn FindProblems obj getFixData:False justSelVerts:False =
|
|
(
|
|
if (not IsValidNode obj) do return Undefined
|
|
if not ((IsKindOf obj Editable_Poly) or (IsKindOf obj Editable_Mesh)) do return Undefined
|
|
if (obj.modifiers.count != 0) do return Undefined
|
|
|
|
-- Set up error-collection struct for object:
|
|
local seamInfo = RstaTerrainSeams()
|
|
|
|
local objOp = (RsMeshPolyOp obj)
|
|
|
|
local facesCount = (objOp.GetNumFaces obj)
|
|
local geomVertsCount = (objOp.GetNumVerts obj)
|
|
if (facesCount == 0) or (geomVertsCount == 0) do return seamInfo
|
|
|
|
-- Get object's terrain_uber material-descriptors:
|
|
local terrMatInfos = (gRsTerrainHelpers.GetObjTerrainFaceData obj)
|
|
--terrMatInfos = for item in terrMatInfos where (item.typeDef.isUberTerrain) collect item
|
|
|
|
-- Does this mesh use Terrain_Uber shaders?
|
|
seamInfo.hasUberTerrain = False
|
|
for item in terrMatInfos while (not seamInfo.hasUberTerrain) do
|
|
seamInfo.hasUberTerrain = item.typeDef.isUberTerrain
|
|
|
|
-- Abort if no terrain-materials are used on this object:
|
|
if (terrMatInfos.count == 0) do
|
|
return seamInfo
|
|
|
|
-- Build list of all terrain-material faces, and material-border-verts:
|
|
local terrainFaces = #{}
|
|
for terrMatInfo in terrMatInfos do
|
|
(
|
|
Join terrainFaces (terrMatInfo.GetMatFaces())
|
|
)
|
|
|
|
local selVerts = #{}
|
|
if justSelVerts do
|
|
(
|
|
-- Get selected verts on obj
|
|
-- This is converted from other subobject selections, if currently non-vertex
|
|
local objVertSel = RSTAGeometry_GetSelectionDetails objs:#(obj) selType:#Vertex
|
|
selVerts = objVertSel[1].selSubObjs
|
|
)
|
|
|
|
local maskChan = Undefined
|
|
local tintMaskSubChan = Undefined
|
|
local lookupMaskSubChan = Undefined
|
|
|
|
-- Process tint/lookup mask-channel:
|
|
(
|
|
local tintMaskVerts = Undefined
|
|
local lookupMaskSeamVerts = Undefined
|
|
|
|
-- Bitarrays for finding mask-seams
|
|
if seamInfo.hasUberTerrain then
|
|
(
|
|
maskChan = (RsGetChanByName #TerrainMask)
|
|
tintMaskSubChan = 1
|
|
lookupMaskSubChan = 2
|
|
tintMaskVerts = (seamInfo.AddItem #TintMask obj:obj chan:maskChan subChan:tintMaskSubChan).verts
|
|
lookupMaskSeamVerts = (seamInfo.AddItem #LookupMask obj:obj chan:maskChan subChan:lookupMaskSubChan).verts
|
|
)
|
|
else
|
|
(
|
|
maskChan = (RsGetChanByName #TerrainCbMask)
|
|
lookupMaskSeamVerts = (seamInfo.AddItem #LookupMask obj:obj chan:maskChan).verts
|
|
)
|
|
|
|
local hasVertLookupVerts = #{}
|
|
local hasTexLookupVerts = #{}
|
|
|
|
-- Is mask-channel active?
|
|
local hasMaskChan = (objOp.GetMapSupport obj maskChan)
|
|
|
|
if (hasMaskChan) do
|
|
(
|
|
PushPrompt "Finding Tint/Lookup Mask seams..."
|
|
|
|
-- Initialise sizes of bitarrays:
|
|
local maskSeamArrays = for item in \
|
|
#(tintMaskVerts, hasVertLookupVerts, hasTexLookupVerts, lookupMaskSeamVerts) \
|
|
where (item != Undefined) collect item
|
|
|
|
for thisArray in maskSeamArrays do
|
|
thisArray.count = geomVertsCount
|
|
|
|
-- Find geometry-verts with multiple mask-values:
|
|
local geomVertVals = GetMappingValsPerVert obj maskChan faces:terrainFaces
|
|
for geomVert = 1 to geomVertsCount where ((not justSelVerts) or selVerts[geomVert]) do
|
|
(
|
|
local maskVals = geomVertVals[geomVert]
|
|
|
|
-- Ignore verts where no data was collected:
|
|
if (maskVals.count != 0) do
|
|
(
|
|
-- This vertex is probably a seam if it has multiple mask-values:
|
|
maskVals = (MakeUniqueVecs maskVals)
|
|
|
|
-- Process tint-mask value(s)
|
|
if seamInfo.hasUberTerrain and (tintMaskVerts != Undefined) do
|
|
(
|
|
local maxTintMask = Undefined
|
|
if (maskVals.count == 1) then
|
|
(
|
|
maxTintMask = maskVals[1][tintMaskSubChan]
|
|
)
|
|
else
|
|
(
|
|
local vals = for val in maskVals collect val[tintMaskSubChan]
|
|
maxTintMask = (Amax vals)
|
|
vals.count = 0
|
|
)
|
|
|
|
-- Does vert have non-zero tint-mask value?
|
|
-- (these should all be set to zero, i.e. should completely use Texture Tint)
|
|
if (maxTintMask > 0.001) do
|
|
tintMaskVerts[geomVert] = True
|
|
)
|
|
|
|
-- Process lookup-mask value(s)
|
|
(
|
|
local minLookupMask
|
|
local maxLookupMask
|
|
if (maskVals.count == 1) then
|
|
(
|
|
local val = maskVals[1]
|
|
if seamInfo.hasUberTerrain then
|
|
minLookupMask = val[lookupMaskSubChan]
|
|
else
|
|
minLookupMask = Amin val[1] val[2] val[3]
|
|
maxLookupMask = minLookupMask
|
|
)
|
|
else
|
|
(
|
|
local vals = MakeUniqueArray \
|
|
(
|
|
for val in maskVals collect
|
|
(
|
|
if seamInfo.hasUberTerrain then
|
|
val[lookupMaskSubChan]
|
|
else
|
|
(Amin val[1] val[2] val[3])
|
|
)
|
|
)
|
|
minLookupMask = (Amin vals)
|
|
maxLookupMask = (Amax vals)
|
|
|
|
-- Is this a lookup-mask seam?
|
|
if (vals.count > 1) do
|
|
(
|
|
lookupMaskSeamVerts[geomVert] = True
|
|
)
|
|
vals.count = 0
|
|
)
|
|
|
|
-- Does vert have non-zero lookup-mask?
|
|
-- (i.e. does it use any Vertex Colour lookup)
|
|
if (maxLookupMask > 0.001) do
|
|
(
|
|
hasVertLookupVerts[geomVert] = True
|
|
)
|
|
|
|
-- Does vert have non-full lookup-mask?
|
|
-- (i.e. does it use any Texture lookup)
|
|
if (minLookupMask < 0.999) do
|
|
(
|
|
hasTexLookupVerts[geomVert] = True
|
|
)
|
|
)
|
|
|
|
-- Dipose of array:
|
|
maskVals.count = 0
|
|
)
|
|
)
|
|
geomVertVals.count = 0
|
|
|
|
-- Reduce bitarrays down to minimal-required sizes:
|
|
-- (i.e. set to size to max-used bit)
|
|
for thisArray in maskSeamArrays do
|
|
RstaCompressBitArray thisArray
|
|
|
|
PopPrompt()
|
|
)
|
|
)
|
|
-- (end of tint/lookup mask channel processing)
|
|
|
|
-- Process effects-mask channel
|
|
if seamInfo.hasUberTerrain do
|
|
(
|
|
-- Bitarrays for finding mask-seams:
|
|
local curvMaskSeamVerts = (seamInfo.AddItem #CurveMask obj:obj chan:effectsMaskChan subChan:curveMaskSubChan).verts
|
|
local dispMaskSeamVerts = (seamInfo.AddItem #DisplaceMask obj:obj chan:effectsMaskChan subChan:displaceMaskSubChan).verts
|
|
|
|
-- Is mask-channel active?
|
|
local hasEffectsMaskChan = (objOp.GetMapSupport obj effectsMaskChan)
|
|
|
|
if (hasEffectsMaskChan) do
|
|
(
|
|
PushPrompt "Finding Effects Mask seams..."
|
|
|
|
-- Initialise sizes of bitarrays:
|
|
local maskSeamArrays = #(curvMaskSeamVerts, dispMaskSeamVerts)
|
|
for thisArray in maskSeamArrays do
|
|
(
|
|
thisArray.count = geomVertsCount
|
|
)
|
|
|
|
-- Find geometry-verts with multiple mask-values:
|
|
local geomVertVals = GetMappingValsPerVert obj effectsMaskChan faces:terrainFaces
|
|
for geomVert = 1 to geomVertsCount where ((not justSelVerts) or selVerts[geomVert]) do
|
|
(
|
|
local maskVals = geomVertVals[geomVert]
|
|
|
|
-- Ignore verts where no data was collected:
|
|
if (maskVals.count != 0) do
|
|
(
|
|
-- This vertex is probably a seam if it has multiple mask-values:
|
|
maskVals = (MakeUniqueVecs maskVals)
|
|
|
|
-- Process curvature-mask value(s)
|
|
if (maskVals.count > 1) do
|
|
(
|
|
local curveMaskVals = MakeUniqueArray (for val in maskVals collect val[curveMaskSubChan])
|
|
|
|
-- Is this a displacement-mask seam?
|
|
if (curveMaskVals.count > 1) do
|
|
(
|
|
curvMaskSeamVerts[geomVert] = True
|
|
)
|
|
)
|
|
|
|
-- Process displacement-mask value(s)
|
|
if (maskVals.count > 1) do
|
|
(
|
|
local displaceMaskVals = MakeUniqueArray (for val in maskVals collect val[displaceMaskSubChan])
|
|
|
|
-- Is this a displacement-mask seam?
|
|
if (displaceMaskVals.count > 1) do
|
|
(
|
|
dispMaskSeamVerts[geomVert] = True
|
|
)
|
|
)
|
|
|
|
-- Dipose of array:
|
|
maskVals.count = 0
|
|
)
|
|
)
|
|
geomVertVals.count = 0
|
|
|
|
-- Reduce bitarrays down to minimal-required sizes:
|
|
-- (i.e. set to size to max-used bit)
|
|
for thisArray in maskSeamArrays do
|
|
(
|
|
RstaCompressBitArray thisArray
|
|
)
|
|
|
|
PopPrompt()
|
|
)
|
|
)
|
|
-- (end of effects-mask channel processing)
|
|
|
|
-- Process wetness-channel
|
|
if seamInfo.hasUberTerrain do
|
|
(
|
|
-- Is wetness-channel active?
|
|
local hasWetnessChan = (objOp.GetMapSupport obj wetnessChan)
|
|
|
|
if (hasWetnessChan) do
|
|
(
|
|
PushPrompt "Finding Wetness seams..."
|
|
local wetnessSeamVerts = (seamInfo.AddItem #WetnessSeam obj:obj chan:wetnessChan).verts
|
|
wetnessSeamVerts.count = geomVertsCount
|
|
|
|
-- Find geometry-verts with multiple wetness-values:
|
|
local geomVertVals = GetMappingValsPerVert obj wetnessChan faces:terrainFaces
|
|
for geomVert = 1 to geomVertsCount where ((not justSelVerts) or selVerts[geomVert]) do
|
|
(
|
|
local wetVals = geomVertVals[geomVert]
|
|
if (wetVals.count > 1) do
|
|
(
|
|
wetVals = MakeUniqueArray (for val in wetVals collect val[1])
|
|
|
|
if (wetVals.count > 1) do
|
|
(
|
|
wetnessSeamVerts[geomVert] = True
|
|
)
|
|
)
|
|
)
|
|
|
|
geomVertVals.count = 0
|
|
RstaCompressBitArray wetnessSeamVerts
|
|
|
|
PopPrompt()
|
|
)
|
|
)
|
|
-- (end of wetness channel processing)
|
|
|
|
-- Collect lookup-weights for each terrain-material
|
|
local geomVertLookupWeights = this.GetObjWeights obj terrMatInfos:terrMatInfos
|
|
|
|
-- Find material-border verts:
|
|
(
|
|
PushPrompt "Finding material-border verts..."
|
|
|
|
-- We'll find material-border verts:
|
|
local matBorderVerts = #()
|
|
|
|
for terrMatInfo in terrMatInfos do
|
|
(
|
|
-- Get terrain-material descriptor's faces-list:
|
|
local matFaces = (terrMatInfo.GetMatFaces())
|
|
|
|
-- Find verts shared between this material and other terrain-materials:
|
|
local matVerts = (objOp.GetVertsUsingFace obj matFaces)
|
|
local nonMatVerts = (objOp.GetVertsUsingFace obj (terrainFaces - matFaces))
|
|
local thisMatBorderVerts = (matVerts * nonMatVerts)
|
|
|
|
-- Collect indices for currently-selected verts:
|
|
Append matBorderVerts thisMatBorderVerts
|
|
)
|
|
|
|
for thisArray in matBorderVerts do
|
|
(
|
|
RstaCompressBitArray thisArray
|
|
)
|
|
|
|
PopPrompt()
|
|
)
|
|
-- (end of lookup-weight collection)
|
|
|
|
-- Find all texture-weight seams:
|
|
(
|
|
PushPrompt "Finding texmap-weight seams..."
|
|
local weightSeamVerts = (seamInfo.AddItem #WeightSeam obj:obj chan:lookupChan).verts
|
|
weightSeamVerts.count = geomVertsCount
|
|
|
|
for geomVert = 1 to geomVertsCount where ((not justSelVerts) or selVerts[geomVert]) do
|
|
(
|
|
local weights = MakeUniqueVecs geomVertLookupWeights[geomVert]
|
|
|
|
-- Is there more than one vertex-weight in use here?
|
|
if (weights.count > 1) do
|
|
(
|
|
weightSeamVerts[geomVert] = True
|
|
)
|
|
)
|
|
|
|
RstaCompressBitArray weightSeamVerts
|
|
PopPrompt()
|
|
)
|
|
-- (end of weight-seam processing)
|
|
|
|
-- Find material-border (i.e. non-common-blend seams)
|
|
(
|
|
PushPrompt "Finding blend-seams..."
|
|
|
|
local blendSeamVerts = (seamInfo.AddItem #BlendSeam obj:obj chan:lookupChan).verts
|
|
blendSeamVerts.count = geomVertsCount
|
|
|
|
-- Collect common-blend info, if requested:
|
|
local commonsPerVert = #()
|
|
if getFixData do
|
|
(
|
|
commonsPerVert.count = geomVertsCount
|
|
)
|
|
|
|
-- Test verts on borders between each matId-descriptor:
|
|
for matIdxA = 1 to (terrMatInfos.Count - 1) do
|
|
(
|
|
-- Get info for first comparison-material:
|
|
local terrInfoA = terrMatInfos[matIdxA]
|
|
|
|
for matIdxB = (matIdxA + 1) to terrMatInfos.count do
|
|
(
|
|
-- Find verts that are shared by compared matids:
|
|
local betweenMatVerts = (matBorderVerts[matIdxA] * matBorderVerts[matIdxB])
|
|
|
|
-- Skip comparison if these matids don't have any shared verts:
|
|
if (betweenMatVerts.numberSet != 0) do
|
|
(
|
|
-- Get info for second comparison-material:
|
|
local terrInfoB = terrMatInfos[matIdxB]
|
|
|
|
-- Get bitarray of common-blend texture-indices:
|
|
local commonTexIdxs = (this.GetCommonBlends terrInfoA terrInfoB)
|
|
|
|
-- Do these terrain-materials have any common texmaps?
|
|
local hasCommonTex = (commonTexIdxs.numberSet != 0)
|
|
|
|
-- Test verts that haven't already been marked as being seams:
|
|
if (not hasCommonTex) then
|
|
(
|
|
-- Consider all border-verts to be a blend-seam if they have no common blend:
|
|
Join blendSeamVerts betweenMatVerts
|
|
)
|
|
else
|
|
(
|
|
-- Create multiplier-vector, for fixer to use:
|
|
local commonTexVec = [0,0,0,0]
|
|
for texIdx in commonTexIdxs do
|
|
(
|
|
commonTexVec[texIdx] = 1.0
|
|
)
|
|
|
|
local uncommonTexIdxs = (-commonTexIdxs) as Array
|
|
|
|
for geomVert in betweenMatVerts where ((not justSelVerts) or selVerts[geomVert]) do
|
|
(
|
|
local isBlendSeamVert = False
|
|
local checkForVertSeam = True
|
|
|
|
if hasMaskChan and hasTexLookupVerts[geomVert] do
|
|
(
|
|
-- We can't validate common blends for texture-lookup, so we can assume it has a seam:
|
|
if assumeTexLookupCantBlend then
|
|
(
|
|
isBlendSeamVert = True
|
|
)
|
|
else
|
|
(
|
|
-- Only check vertex-colours if vert is not fully-masked
|
|
checkForVertSeam = hasVertLookupVerts[geomVert]
|
|
)
|
|
)
|
|
|
|
if checkForVertSeam and (not isBlendSeamVert) do
|
|
(
|
|
local vertWeights = MakeUniqueVecs geomVertLookupWeights[geomVert]
|
|
|
|
-- Find non-zero weights for non-common texture-ids:
|
|
local onlyCommon = True
|
|
for weights in vertWeights while onlyCommon do
|
|
(
|
|
for texIdx in uncommonTexIdxs while onlyCommon do
|
|
(
|
|
if (weights[texIdx] > 0.001) do
|
|
(
|
|
onlyCommon = False
|
|
)
|
|
)
|
|
)
|
|
|
|
-- Mark vert as being a seam if it uses any uncommon blends:
|
|
if (not onlyCommon) do
|
|
(
|
|
isBlendSeamVert = True
|
|
)
|
|
)
|
|
|
|
if isBlendSeamVert do
|
|
(
|
|
blendSeamVerts[geomVert] = True
|
|
|
|
-- Store common-blends multiplier for vert:
|
|
if getFixData do
|
|
(
|
|
for vertNum in betweenMatVerts do
|
|
(
|
|
commonsPerVert[vertNum] = commonTexVec
|
|
)
|
|
)
|
|
)
|
|
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
RstaCompressBitArray blendSeamVerts
|
|
|
|
-- Don't include common-blend seams in generic weight-seams list, as they'll be fixed separately:
|
|
weightSeamVerts -= blendSeamVerts
|
|
|
|
PopPrompt()
|
|
)
|
|
|
|
-- Find verts whose texmap-weights don't add up to 1.0
|
|
-- and two-layer-shader verts with lookup colours for more than two blends
|
|
(
|
|
PushPrompt "Finding unbalanced vert-blends..."
|
|
|
|
-- Find verts using two-layer terrain-shader:
|
|
-- (these should only have red/green blend-colours)
|
|
local twoLayerVerts = GetTwoLayerVerts obj terrMatInfos:terrMatInfos
|
|
local hasTwoLayer = (twoLayerVerts.numberSet != 0)
|
|
if hasTwoLayer do
|
|
(
|
|
local badTwoLayerVerts = (seamInfo.AddItem #BadTwoLayer obj:obj chan:lookupChan).verts
|
|
badTwoLayerVerts.count = geomVertsCount
|
|
)
|
|
|
|
local badBlendSumVerts = (seamInfo.AddItem #BadBlendSum obj:obj chan:lookupChan).verts
|
|
badBlendSumVerts.count = geomVertsCount
|
|
|
|
for geomVert = 1 to geomVertsCount where ((not justSelVerts) or selVerts[geomVert]) do
|
|
(
|
|
local blendsOnVert = MakeUniqueVecs geomVertLookupWeights[geomVert]
|
|
|
|
local isTwoLayerVert = (hasTwoLayer and twoLayerVerts[geomVert])
|
|
local isBadBlendSum = False
|
|
local isBadTwoLayer = False
|
|
|
|
for weights in blendsOnVert do
|
|
(
|
|
-- Find two-layer lookups with blue/black values
|
|
if isTwoLayerVert do
|
|
(
|
|
for n = 3 to 4 do
|
|
(
|
|
if (weights[n] != 0) do
|
|
(
|
|
isBadTwoLayer = True
|
|
isBadBlendSum = True
|
|
)
|
|
)
|
|
)
|
|
|
|
-- Validate sum of rgb values
|
|
local weightSum = 0.0
|
|
local texCount = if isTwoLayerVert then 2 else 4
|
|
for n = 1 to texCount do
|
|
(
|
|
weightSum += weights[n]
|
|
)
|
|
|
|
if isTwoLayerVert then
|
|
(
|
|
-- Two-layer red/green must sum to 1.0
|
|
if (weightSum < 0.999) or (weightSum > 1.001) do
|
|
(
|
|
isBadBlendSum = True
|
|
)
|
|
)
|
|
else
|
|
(
|
|
-- Four-layer values shouldn't sum to more than 1.0
|
|
if (weightSum > 1.001) do
|
|
(
|
|
isBadBlendSum = True
|
|
)
|
|
)
|
|
)
|
|
|
|
if isBadBlendSum do
|
|
(
|
|
badBlendSumVerts[geomVert] = True
|
|
)
|
|
if isBadTwoLayer do
|
|
(
|
|
badTwoLayerVerts[geomVert] = True
|
|
)
|
|
)
|
|
|
|
-- Resize bitarrays down to last-required bit
|
|
RstaCompressBitArray badBlendSumVerts
|
|
if hasTwoLayer do
|
|
(
|
|
RstaCompressBitArray badTwoLayerVerts
|
|
)
|
|
|
|
PopPrompt()
|
|
)
|
|
|
|
-- Remove unused items:
|
|
seamInfo.Clean()
|
|
|
|
------------------------------------------------------
|
|
-- STORE DATA FOR FIX:
|
|
------------------------------------------------------
|
|
|
|
-- Store terrain-faces list, if required/requested:
|
|
if getFixData and (seamInfo.items.count != 0) then
|
|
(
|
|
-- Store terrain-shader faces:
|
|
(
|
|
seamInfo.terrainFaces = terrainFaces
|
|
)
|
|
|
|
-- Store material-border edges:
|
|
(
|
|
--local objOpenEdges = (objOp.GetOpenEdges obj)
|
|
--local borderVerts = (objOp.GetVertsUsingEdge obj objOpenEdges)
|
|
--objOpenEdges.count = 0
|
|
|
|
local borderVerts = #{}
|
|
for thisArray in matBorderVerts do
|
|
(
|
|
Join borderVerts thisArray
|
|
)
|
|
RstaCompressBitArray borderVerts
|
|
|
|
seamInfo.borderVerts = borderVerts
|
|
)
|
|
)
|
|
else
|
|
(
|
|
terrainFaces.count = 0
|
|
)
|
|
|
|
-- Store per-vertex texmap-weights, if required/requested:
|
|
if getFixData and seamInfo.FixNeedsWeights() then
|
|
(
|
|
seamInfo.vertWeights = geomVertLookupWeights
|
|
)
|
|
else
|
|
(
|
|
-- Dispose of unneeded weight-arrays:
|
|
for item in geomVertLookupWeights do
|
|
(
|
|
item.count = 0
|
|
)
|
|
geomVertLookupWeights.count = 0
|
|
)
|
|
|
|
-- Store per-vertex common-blends, if required/requested:
|
|
if getFixData and (seamInfo.ItemNeedsFix #BlendSeam) then
|
|
(
|
|
seamInfo.commonBlends = commonsPerVert
|
|
)
|
|
else
|
|
(
|
|
-- Dispose of unneeded blend-arrays:
|
|
commonsPerVert.count = 0
|
|
)
|
|
|
|
-- Dispose of arrays:
|
|
for item in matBorderVerts do
|
|
(
|
|
item.count = 0
|
|
)
|
|
|
|
return seamInfo
|
|
),
|
|
|
|
fn FindProblemVerts obj =
|
|
(
|
|
local seamInfo = gRsTerrainSeamFinder.FindProblems obj
|
|
if (not IsKindOf seamInfo RstaTerrainSeams) do return #{}
|
|
|
|
local verts = #{}
|
|
for item in seamInfo.items do
|
|
(
|
|
Join verts item.verts
|
|
)
|
|
|
|
return verts
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
-- FixSeams:
|
|
-- Finds and fixes (where possible) seams in terrain-paint channels
|
|
------------------------------------------------------------------------------------------------------
|
|
fn FixObjProblems obj fixNames: justSelVerts:False =
|
|
(
|
|
-- Collect current seam-error data for object:
|
|
local seamInfo = this.FindProblems obj getFixData:True justSelVerts:justSelVerts
|
|
if (not IsKindOf seamInfo RstaTerrainSeams) do
|
|
return False
|
|
|
|
-- Only fix requested seam-types, if specified:
|
|
if (fixNames != Unsupplied) do
|
|
(
|
|
for item in seamInfo.items do
|
|
(
|
|
if (FindItem fixNames item.name == 0) do
|
|
(
|
|
item.verts.count = 0
|
|
)
|
|
)
|
|
)
|
|
|
|
-- Clear irrelevant/unwanted items:
|
|
seamInfo.Clean()
|
|
|
|
-- Abort if no fix-items were found, or remain:
|
|
if (seamInfo.items.count == 0) do
|
|
return OK
|
|
|
|
local objOp = (RsMeshPolyOp obj)
|
|
local objGetFaceVerts = (RsGetFaceFunc obj)
|
|
local objGetMapFace = (RsGetMapFaceFunc obj)
|
|
local objSetMapVert = (objOp.SetMapVert)
|
|
|
|
local maskChan = if seamInfo.hasUberTerrain then (RsGetChanByName #TerrainMask) else (RsGetChanByName #TerrainCbMask)
|
|
local lookupMaskSubChan = if seamInfo.hasUberTerrain then 2 else Undeined
|
|
|
|
-- Make sure we have corresponding lookup-mask edits queued for all lookup-edits:
|
|
(
|
|
-- Will we be fixing texmap-lookup seams?
|
|
local lookupFixVerts = #{}
|
|
for seamName in #(#WeightSeam, #BlendSeam) do
|
|
(
|
|
local seamVerts = (seamInfo.GetVertsByName seamName)
|
|
Join lookupFixVerts seamVerts
|
|
)
|
|
|
|
if (lookupFixVerts.numberSet != 0) do
|
|
(
|
|
-- Get/create lookup-mask edit:
|
|
local lookupMaskFix = seamInfo.GetItem #LookupMask
|
|
if (lookupMaskFix == Undefined) do
|
|
lookupMaskFix = (seamInfo.AddItem #LookupMask chan:maskChan subChan:lookupMaskSubChan)
|
|
|
|
-- These verts will now all be modified to show Vertexcolour Lookup:
|
|
Join lookupMaskFix.verts lookupFixVerts
|
|
)
|
|
lookupFixVerts.count = 0
|
|
)
|
|
|
|
-- Perform changes on copy of node's baseObject, to simplify undo:
|
|
undo off
|
|
(
|
|
local editObj = (Copy obj.baseObject)
|
|
if (objOp == meshOp) do
|
|
(
|
|
editObj = editObj.mesh
|
|
)
|
|
|
|
local facesCount = (objOp.GetNumFaces editObj)
|
|
local geomVertsCount = (objOp.GetNumVerts editObj)
|
|
|
|
-- Fix tint/lookup mask seams:
|
|
local maskFixes = for thisName in #(#TintMask, #LookupMask) collect (seamInfo.GetItem thisName)
|
|
maskFixes = for item in maskFixes where (item != Undefined) collect item
|
|
if (maskFixes.count != 0) do
|
|
(
|
|
PushPrompt "Fixing Terrain Mask seams..."
|
|
|
|
local maskChan = (seamInfo.GetItem #LookupMask).chan
|
|
local tintMaskSubChan = Undefined
|
|
if (seamInfo.GetItem #TintMask) != Undefined do
|
|
tintMaskSubChan = (seamInfo.GetItem #TintMask).subChan
|
|
local lookupMaskSubChan = (seamInfo.GetItem #LookupMask).subChan
|
|
|
|
local usesSubChans = (lookupMaskSubChan != Undefined)
|
|
|
|
-- Make sure verts aren't inappropriately welded:
|
|
RsDecompressVertChan editObj maskChan
|
|
|
|
-- Get verts that need to be fixed on Mask channel:
|
|
local fixGeomVerts = #{}
|
|
for item in maskFixes do
|
|
(
|
|
fixGeomVerts += item.verts
|
|
)
|
|
local fixFaces = (objOp.GetFacesUsingVert editObj fixGeomVerts) * (seamInfo.terrainFaces)
|
|
|
|
local tintMaskFixVerts = (seamInfo.GetVertsByName #TintMask)
|
|
local lookupMaskFixVerts = (seamInfo.GetVertsByName #LookupMask)
|
|
|
|
-- Get map-verts/colours per geometry-vert:
|
|
local geomToMapVerts = #()
|
|
local perVertVals = GetMappingValsPerVert editObj maskChan faces:fixFaces geomToMapVerts:geomToMapVerts
|
|
|
|
-- Which verts are on the edges of materials?
|
|
local borderVerts = seamInfo.borderVerts
|
|
|
|
-- Set average colour for each mask-seam vert:
|
|
for geomVert in fixGeomVerts do
|
|
(
|
|
local mapVerts = geomToMapVerts[geomVert]
|
|
local vertVals = perVertVals[geomVert]
|
|
|
|
-- Which fixes need to be made here?
|
|
local fixTint = tintMaskFixVerts[geomVert]
|
|
local fixLookup = lookupMaskFixVerts[geomVert]
|
|
|
|
for vertIdx = 1 to mapVerts.count do
|
|
(
|
|
local mapVert = mapVerts[vertIdx]
|
|
local vertVal = vertVals[vertIdx]
|
|
|
|
-- Set tint-mask to 0% (i.e. Texture Tint only)
|
|
if fixTint do
|
|
(
|
|
if usesSubChans then
|
|
vertVal[tintMaskSubChan] = 0.0
|
|
else
|
|
vertVal = [0,0,0]
|
|
)
|
|
-- Set lookup-mask value to 1.0% (i.e. Vertex Tint only)
|
|
if fixLookup do
|
|
(
|
|
if usesSubChans then
|
|
vertVal[lookupMaskSubChan] = 1.0
|
|
else
|
|
vertVal = [1,1,1]
|
|
)
|
|
|
|
objSetMapVert editObj maskChan mapVert vertVal
|
|
)
|
|
)
|
|
|
|
-- Dipose of arrays:
|
|
for thisArray in #(geomToMapVerts, perVertVals) do
|
|
(
|
|
for item in thisArray do (item.count = 0)
|
|
thisArray.count = 0
|
|
)
|
|
|
|
PopPrompt()
|
|
)
|
|
|
|
-- Fix curvature/displacement effects-mask seams:
|
|
local maskFixes = for thisName in #(#CurveMask, #DisplaceMask) collect (seamInfo.GetItem thisName)
|
|
maskFixes = for item in maskFixes where (item != Undefined) collect item
|
|
if (maskFixes.count != 0) do
|
|
(
|
|
PushPrompt "Fixing Terrain Mask seams..."
|
|
|
|
-- Make sure verts aren't inappropriately welded:
|
|
RsDecompressVertChan editObj effectsMaskChan
|
|
|
|
-- Get verts that need to be fixed on Mask channel:
|
|
local fixGeomVerts = #{}
|
|
for item in maskFixes do
|
|
(
|
|
fixGeomVerts += item.verts
|
|
)
|
|
local fixFaces = (objOp.GetFacesUsingVert editObj fixGeomVerts) * (seamInfo.terrainFaces)
|
|
|
|
local curveMaskFixVerts = (seamInfo.GetVertsByName #CurveMask)
|
|
local displaceMaskFixVerts = (seamInfo.GetVertsByName #DisplaceMask)
|
|
|
|
-- Get map-verts/colours per geometry-vert:
|
|
local geomToMapVerts = #()
|
|
local perVertVals = GetMappingValsPerVert editObj effectsMaskChan faces:fixFaces geomToMapVerts:geomToMapVerts
|
|
|
|
-- Which verts are on the edges of materials?
|
|
local borderVerts = seamInfo.borderVerts
|
|
|
|
-- Set average colour for each mask-seam vert:
|
|
for geomVert in fixGeomVerts do
|
|
(
|
|
local mapVerts = geomToMapVerts[geomVert]
|
|
local vertVals = perVertVals[geomVert]
|
|
|
|
-- Which fixes need to be made here?
|
|
local fixCurve = curveMaskFixVerts[geomVert]
|
|
local fixDisplace = displaceMaskFixVerts[geomVert]
|
|
|
|
for vertIdx = 1 to mapVerts.count do
|
|
(
|
|
local mapVert = mapVerts[vertIdx]
|
|
local vertVal = vertVals[vertIdx]
|
|
|
|
-- Set as fully-masked - i.e. no curvature:
|
|
if fixCurve do
|
|
(
|
|
vertVal[curveMaskSubChan] = 1.0
|
|
)
|
|
-- Set as fully-masked - i.e. no displacement:
|
|
if fixDisplace do
|
|
(
|
|
vertVal[displaceMaskSubChan] = 1.0
|
|
)
|
|
|
|
objSetMapVert editObj effectsMaskChan mapVert vertVal
|
|
)
|
|
)
|
|
|
|
-- Dipose of arrays:
|
|
for thisArray in #(geomToMapVerts, perVertVals) do
|
|
(
|
|
for item in thisArray do (item.count = 0)
|
|
thisArray.count = 0
|
|
)
|
|
|
|
PopPrompt()
|
|
)
|
|
|
|
-- Make sure verts aren't inappropriately welded on lookup-channel, if it's going to be edited:
|
|
local fixingLookup = False
|
|
for lookupFixName in #(#WeightSeam, #BlendSeam, #BadBlendSum, #BadTwoLayer) while (not fixingLookup) do
|
|
(
|
|
fixingLookup = (seamInfo.ItemNeedsFix lookupFixName)
|
|
)
|
|
if fixingLookup do
|
|
(
|
|
RsDecompressVertChan editObj lookupChan
|
|
)
|
|
|
|
-- Fix blend-lookup seams:
|
|
local lookupDecompressed = False
|
|
if (seamInfo.ItemNeedsFix #WeightSeam) or (seamInfo.ItemNeedsFix #BlendSeam) do
|
|
(
|
|
PushPrompt "Fixing Texmap Lookup seams..."
|
|
|
|
local vertWeights = seamInfo.vertWeights
|
|
local commonsPerVert = seamInfo.commonBlends
|
|
|
|
local weightSeamVerts = (seamInfo.GetVertsByName #WeightSeam)
|
|
local blendSeamVerts = (seamInfo.GetVertsByName #BlendSeam)
|
|
|
|
-- Get combined list of verts that need to be fixed:
|
|
local fixGeomVerts = #{}
|
|
Join fixGeomVerts weightSeamVerts
|
|
Join fixGeomVerts blendSeamVerts
|
|
|
|
-- Get faces used by verts that need to be fixed:
|
|
local fixFaces = (objOp.GetFacesUsingVert editObj fixGeomVerts) * (seamInfo.terrainFaces)
|
|
|
|
-- Collect geometry-to-mapping vertex-lookup data:
|
|
local geomToMapVerts = (for n = 1 to geomVertsCount collect #())
|
|
for faceNum in fixFaces do
|
|
(
|
|
-- Get face's geometry/mapping verts:
|
|
local faceGeomVerts = (objGetFaceVerts editObj faceNum)
|
|
local faceMapVerts = (objGetMapFace editObj lookupChan faceNum)
|
|
|
|
-- Collect values from each face-corner:
|
|
for vertIdx = 1 to faceGeomVerts.count do
|
|
(
|
|
local mapVert = faceMapVerts[vertIdx]
|
|
local geomVert = faceGeomVerts[vertIdx]
|
|
AppendIfUnique geomToMapVerts[geomVert] mapVert
|
|
)
|
|
)
|
|
|
|
local BalanceTexWeights = gRsTerrainHelpers.BalanceTexWeights
|
|
|
|
local GetClrFromWeights = if seamInfo.hasUberTerrain then
|
|
RsTerrainShaderType_Uber.GetClrFromWeights
|
|
else
|
|
RsTerrainShaderType_CB.GetClrFromWeights
|
|
|
|
local zeroWeights = [0,0,0,0]
|
|
|
|
for geomVert in fixGeomVerts do
|
|
(
|
|
local newWeights = Undefined
|
|
|
|
-- Is this a material-border or mid-material vertex?
|
|
if blendSeamVerts[geomVert] then
|
|
(
|
|
-- Find average common-blend values for material-border verts:
|
|
local commonMult = commonsPerVert[geomVert]
|
|
|
|
-- We can only fix this vert if it has any Common Blends available:
|
|
if (commonMult != Undefined) do
|
|
(
|
|
local newWeights = [0,0,0,0]
|
|
local geomVertWeights = vertWeights[geomVert]
|
|
for weights in geomVertWeights do
|
|
(
|
|
newWeights += weights
|
|
)
|
|
|
|
-- Get rid of non-common weights:
|
|
newWeights *= commonMult
|
|
|
|
-- Use all common-weights by default, if none were used on this vert:
|
|
if (Distance newWeights zeroWeights < 0.001) do
|
|
(
|
|
newWeights = commonMult
|
|
)
|
|
)
|
|
)
|
|
else
|
|
(
|
|
-- Find total weight-values for mid-material verts:
|
|
local newWeights = [0,0,0,0]
|
|
local geomVertWeights = vertWeights[geomVert]
|
|
for weights in geomVertWeights do
|
|
(
|
|
newWeights += weights
|
|
)
|
|
)
|
|
|
|
if (newWeights != Undefined) do
|
|
(
|
|
-- Convert to array, balance values to add to 1.0:
|
|
local weightsArray = for n = 1 to 4 collect newWeights[n]
|
|
weightsArray = (BalanceTexWeights weightsArray)
|
|
|
|
-- Update value in source-array, to allow the following step to use this data
|
|
local newVal = [weightsArray[1], weightsArray[2], weightsArray[3], weightsArray[4]]
|
|
vertWeights[geomVert] = #(newVal)
|
|
|
|
-- Convert weights to vertex-colour, and apply to mapping-verts:
|
|
newVal = (GetClrFromWeights newVal)
|
|
local mapVerts = geomToMapVerts[geomVert]
|
|
for mapVert in mapVerts do
|
|
(
|
|
objSetMapVert editObj lookupChan mapVert newVal
|
|
)
|
|
)
|
|
)
|
|
|
|
-- Dipose of arrays:
|
|
for thisArray in #(geomToMapVerts) do
|
|
(
|
|
for item in thisArray do (item.count = 0)
|
|
thisArray.count = 0
|
|
)
|
|
|
|
PopPrompt()
|
|
)
|
|
|
|
-- Fix two-layer verts that have blends for layer 3/4,
|
|
-- and bad blend-weight sums
|
|
if (seamInfo.ItemNeedsFix #BadBlendSum) or (seamInfo.ItemNeedsFix #BadTwoLayer) do
|
|
(
|
|
local BalanceTexWeights = gRsTerrainHelpers.BalanceTexWeights
|
|
local vertWeights = seamInfo.vertWeights
|
|
|
|
-- All verts with inappropriate blend-weight sum
|
|
local badBlendSumVerts = (seamInfo.GetVertsByName #BadBlendSum)
|
|
|
|
-- Two-layer verts with blend-problems
|
|
local badTwoLayerVerts = (seamInfo.GetVertsByName #BadTwoLayer)
|
|
local hasTwoLayer = (badTwoLayerVerts.numberSet != 0)
|
|
|
|
-- Get faces used by verts that need to be fixed:
|
|
local fixVerts = (badBlendSumVerts + badTwoLayerVerts)
|
|
local fixFaces = (objOp.GetFacesUsingVert editObj fixVerts) * (seamInfo.terrainFaces)
|
|
|
|
-- Collect geometry-to-mapping vertex-lookup data:
|
|
local geomToMapVerts = (for n = 1 to geomVertsCount collect #())
|
|
for faceNum in fixFaces do
|
|
(
|
|
-- Get face's geometry/mapping verts:
|
|
local faceGeomVerts = (objGetFaceVerts editObj faceNum)
|
|
local faceMapVerts = (objGetMapFace editObj lookupChan faceNum)
|
|
|
|
-- Collect values from each face-corner:
|
|
for vertIdx = 1 to faceGeomVerts.count do
|
|
(
|
|
local mapVert = faceMapVerts[vertIdx]
|
|
local geomVert = faceGeomVerts[vertIdx]
|
|
AppendIfUnique geomToMapVerts[geomVert] mapVert
|
|
)
|
|
)
|
|
fixFaces.count = 0
|
|
|
|
for geomVert in fixVerts do
|
|
(
|
|
-- Find total weight-values for vert:
|
|
local newWeights = [0,0,0,0]
|
|
local geomVertWeights = vertWeights[geomVert]
|
|
for weights in geomVertWeights do
|
|
(
|
|
newWeights += weights
|
|
)
|
|
|
|
-- How many texmap-weights should this vert use?
|
|
local isTwoLayerVert = (hasTwoLayer and badTwoLayerVerts[geomVert])
|
|
local texCount = if isTwoLayerVert then 2 else 4
|
|
|
|
-- Convert to weights-array, then balance values to add to 1.0:
|
|
local weightsArray = for n = 1 to texCount collect newWeights[n]
|
|
|
|
if isTwoLayerVert and (weightsArray[1] == 0) and (weightsArray[2] == 0) then
|
|
(
|
|
-- If both two-layer values are zero, default to full-blend on texmap id 1
|
|
weightsArray[1] = 1.0
|
|
)
|
|
else
|
|
(
|
|
-- Balance values to add up to 1.0
|
|
weightsArray = (BalanceTexWeights weightsArray)
|
|
)
|
|
|
|
-- Convert modified blend-weights to lookup-colour value
|
|
local newVal = [0,0,0]
|
|
for n = 1 to (if isTwoLayerVert then 2 else 3) do
|
|
(
|
|
newVal[n] = weightsArray[n]
|
|
)
|
|
|
|
-- Apply new value to mapping-verts:
|
|
local mapVerts = geomToMapVerts[geomVert]
|
|
for mapVert in mapVerts do
|
|
(
|
|
objSetMapVert editObj lookupChan mapVert newVal
|
|
)
|
|
)
|
|
|
|
-- Dipose of arrays:
|
|
for thisArray in #(geomToMapVerts) do
|
|
(
|
|
for item in thisArray do (item.count = 0)
|
|
thisArray.count = 0
|
|
)
|
|
)
|
|
|
|
-- Fix wetness seams:
|
|
if (seamInfo.ItemNeedsFix #WetnessSeam) do
|
|
(
|
|
PushPrompt "Fixing Terrain Wetness Seams..."
|
|
|
|
-- Make sure verts aren't inappropriately welded:
|
|
RsDecompressVertChan editObj wetnessChan
|
|
|
|
-- Get values used on each vert that needs to be fixed:
|
|
local fixGeomVerts = (seamInfo.GetVertsByName #WetnessSeam)
|
|
local fixFaces = (objOp.GetFacesUsingVert editObj fixGeomVerts) * (seamInfo.terrainFaces)
|
|
|
|
local geomToMapVerts = #()
|
|
local perVertVals = GetMappingValsPerVert editObj wetnessChan faces:fixFaces geomToMapVerts:geomToMapVerts
|
|
|
|
-- Set average colour for each wetness-seam vert:
|
|
for geomVert in fixGeomVerts do
|
|
(
|
|
local vertVals = perVertVals[geomVert]
|
|
if (vertVals.count != 0) do
|
|
(
|
|
-- Find average colour:
|
|
local newVal = [0,0,0]
|
|
for thisVal in vertVals do
|
|
(
|
|
newVal += thisVal
|
|
)
|
|
newVal /= vertVals.count
|
|
|
|
-- Apply new colour to mapping-verts corresponding to this geometry-vert:
|
|
local mapVerts = geomToMapVerts[geomVert]
|
|
for mapVert in mapVerts do
|
|
(
|
|
objSetMapVert editObj wetnessChan mapVert newVal
|
|
)
|
|
)
|
|
)
|
|
|
|
-- Dipose of arrays:
|
|
for thisArray in #(geomToMapVerts, perVertVals) do
|
|
(
|
|
for item in thisArray do (item.count = 0)
|
|
thisArray.count = 0
|
|
)
|
|
|
|
PopPrompt()
|
|
)
|
|
)
|
|
|
|
-- Apply changed baseobject to original node:
|
|
undo "Fix Terrain Seams" on
|
|
(
|
|
obj.baseObject = editObj
|
|
)
|
|
|
|
return OK
|
|
)
|
|
)
|
|
global gRsTerrainSeamFinder = sRsTerrainSeamFinder()
|
|
|
|
-- TEST BITS:
|
|
if False do
|
|
(
|
|
ClearListener()
|
|
--GC()
|
|
undo "Test Seam Fixer" on
|
|
(
|
|
for obj in GetCurrentSelection() do
|
|
(
|
|
local timeClass = (DotnetClass "System.DateTime")
|
|
local timeStart = (timeClass.now)
|
|
|
|
--local probVerts = gRsTerrainSeamFinder.FindProblemVerts obj; print probVerts
|
|
--SubObjectLevel = 1; polyop.SetVertSelection obj probVerts
|
|
|
|
--local vals = gRsTerrainSeamFinder.FindProblems obj getFixData:True
|
|
--gRsTerrainSeamFinder.FixObjProblems obj fixNames:#(#blendSeam)
|
|
gRsTerrainSeamFinder.FixObjProblems obj
|
|
|
|
print vals
|
|
|
|
local timeTaken = ((timeClass.now.Subtract timeStart).totalSeconds as Float)
|
|
Format "%\n\tTime taken: %s\n" obj timeTaken
|
|
)
|
|
)
|
|
)
|