Files
gtav-src/tools_ng/wildwest/script/3dsMax/Characters/Materials/FN_CPVFromTexture.ms
T
2025-09-29 00:52:08 +02:00

276 lines
8.9 KiB
Plaintext
Executable File

-- Data structures
TBCPV_UVimageOutputSize = #(256,512,1024)
TBCPV_paddingSizeArray = #(16,10,4)
-- Dump textures to here, this is for debug only
TBCPV_outputTextureFolder = RsConfigGetWildWestDir() + "assets/texture_based_data/texture_based_CPV"
-- Struct to hold vertex index, its colour, and its uv coords
struct RsTa_cpvVertData
(
vertMeshIndex = undefined,
vertCPVColour = undefined,
vertUVArray = #()
)
-- Function that collects all the map/UV verts from the mesh verts
-- Returns data as an array where each index corresponds to the mesh index
-- Save the UV coordinate too
fn RsTa_TBCPV_meshVertToUVVert meshobj UVChannel =
(
-- Work on a mesh version of the geometry
local tempMesh = snapshotasmesh meshobj
local numMeshFaces = tempMesh.numFaces
local UVMappingArray = #()
-- Run through the mesh and collect the UV data for each face
-- Each triangle will have 3 verts, so 3 values will be returned
startTime = timeStamp()
for faceIndex=1 to numMeshFaces do
(
theMeshFace = getFace tempMesh faceIndex
theTFace = getTVFace tempMesh faceIndex
-- The Mesh face has 3 points, x, y, and z
-- These correspond to the x, y and z of the tvert
-- Store the mapping plus the U, V and W of the Tvert
local VertMapping = #(theMeshFace.x as integer, theTFace.x as integer, (getTVert tempMesh theTFace.x))
append UVMappingArray VertMapping
local VertMapping = #(theMeshFace.y as integer, theTFace.y as integer, (getTVert tempMesh theTFace.y))
append UVMappingArray VertMapping
local VertMapping = #(theMeshFace.z as integer, theTFace.z as integer, (getTVert tempMesh theTFace.z))
append UVMappingArray VertMapping
)
endTime = timeStamp()
format "Collection mapping time :% seconds\n" ((endTime-startTime )/ 1000)
-- The mapping array is very full, I need to make is as small as possible
local parsedUVMappingArray = #(UVMappingArray[1])
local mappingcount = UVMappingArray.count
startTime = timeStamp()
-- Loop through the collected data, collecting any unique vert/texture vert mappings
-- This can get slow with large data sets - ~10 seconds for 3000 verts
for UVMappingArrayIndex = 2 to mappingcount do
(
-- Grab the mapped entry
local theMappingEntry = UVMappingArray[UVMappingArrayIndex]
-- Set a found flag to be false
matchfound = false
-- Check each in sequence
currentParsedCount = parsedUVMappingArray.count
for checkIndex = 1 to currentParsedCount do
(
local chkMappingEntry = parsedUVMappingArray[checkIndex]
-- Have already stored that mesh vert?
if theMappingEntry[1] == chkMappingEntry[1] then
(
-- Have we go that Texture vert too?
if theMappingEntry[2] == chkMappingEntry[2] then
(
matchfound = true
)
)
)
-- If no match is found then we want to save this data
if matchfound == false then append parsedUVMappingArray theMappingEntry
) -- End parsing
endTime = timeStamp()
format "Search time :% seconds\n" ((endTime-startTime )/ 1000)
-- Sort this parsed array to make things easier later
qsort parsedUVMappingArray sortArraybySubIndex subIndex:1
parsedUVMappingArray -- return this mapping
)
-- Collect the vert data
-- Takes an object and returns a breakdown of the verts
fn RsTa_TBCPV_CollectMeshData meshObject theObjectUVChannel =
(
-- Switch to modify mode
max modify mode
local numObjectVerts = meshObject.numVerts
-- Loop through all the verts in index order and for each vertex get its colour from channel 11
local cpvVertListData = #()
for vertIndex = 1 to numObjectVerts do
(
-- Create a struct to hold this data
RsTa_cpvVertDataInstance = RsTa_cpvVertData vertMeshIndex:vertIndex
if (classOf meshObject.baseObject == Editable_Poly) then
(
polyop.setVertSelection meshObject vertIndex
RsTa_cpvVertDataInstance.vertCPVColour = meshObject.GetVertexColor 11
)
else
(
)
append cpvVertListData RsTa_cpvVertDataInstance
) -- End vertex loop
-- Now we need to map this CPV data to the UV data
-- This will be used so that for each mesh vert I know what UV vert to use
local meshTextureVertMapping = RsTa_TBCPV_meshVertToUVVert meshObject theObjectUVChannel
-- For each vert, find the corresponsing map vert and the UV coordinate
local theCount = cpvVertListData.count
for meshVertIndex = 1 to theCount do
(
for textureVertIndex = 1 to meshTextureVertMapping.count do
(
if meshTextureVertMapping[textureVertIndex][1] == meshVertIndex then
(
append cpvVertListData[meshVertIndex].vertUVArray meshTextureVertMapping[textureVertIndex]
)
)
) -- end vertex loop
cpvVertListData -- return the collected data
)
-- Function that creates RGB texture from the CPV colour data
fn RsTa_TBCPV_writeCPVToTexture meshObject collectedMeshData outputTextureFolder saveDataName outputTextureSize paddingSizeArray =
(
-- Make sure the folder exists
outputTextureFolder = outputTextureFolder + "/"
makeDir outputTextureFolder all:true
-- Create a texture of the specified size and fill it with black
theTextureName = meshObject.name + ".tga"
theCPVImage = bitmap outputTextureSize outputTextureSize color:black
theCPVImage.filename = outputTextureFolder + theTextureName
-- Now write the CPV colour into this texture
-- So, loop through all the verts and see if they use this bone
for theVertIndex = 1 to collectedMeshData.count do
(
local theMeshVert = collectedMeshData[theVertIndex]
-- The get the current vert's colour
local cpvColour = theMeshVert.vertCPVColour
-- Use a the padding array input parameter to add the fuzziness to the blocks
-- Create this as a new bitmap, then paste it into the bigger image
theCPVBlockRGB = bitmap paddingSizeArray[1] paddingSizeArray[1] color:cpvColour
theCPVBlockG = bitmap paddingSizeArray[2] paddingSizeArray[2] color:cpvColour
theCPVBlockB = bitmap paddingSizeArray[3] paddingSizeArray[3] color:cpvColour
g_offset = (paddingSizeArray[1] - paddingSizeArray[2])/2
b_offset = g_offset + ((paddingSizeArray[2] - paddingSizeArray[3])/2)
pasteBitmap theCPVBlockG theCPVBlockRGB (box2 0 0 paddingSizeArray[2] paddingSizeArray[2]) [g_offset, g_offset]
pasteBitmap theCPVBlockB theCPVBlockRGB (box2 0 0 paddingSizeArray[3] paddingSizeArray[2]) [b_offset, b_offset]
-- There might be multiple texture co-ordinates for the mesh vert
for tvertIndex = 1 to theMeshVert.vertUVArray.count do
(
local UVCoordinate = theMeshVert.vertUVArray[tvertIndex][3]
local paddingOffset = (paddingSizeArray[1] - 1)/2
local bitmapUVCoordinate = [((UVCoordinate.x * outputTextureSize) - paddingOffset), ((outputTextureSize - (UVCoordinate.y * outputTextureSize)) - paddingOffset)]
pasteBitmap theCPVBlockRGB theCPVImage (box2 0 0 paddingSizeArray[1] paddingSizeArray[1]) bitmapUVCoordinate
) -- end tvert loop
) -- end mesh vert loop
-- debug: display the created image
--display theCPVImage
-- Save the texture
save theCPVImage
-- Let the user know that this has worked
messagebox ("CPV texture data written to the folder " + outputTextureFolder)
)
-- Function that loads CPV colours from an image onto a mesh
fn RsTa_TBCPV_loadCPVFromTexture meshObject collectedMeshData texToLoad =
(
if collectedMeshData == undefined then
(
messagebox "There is no saved CPV data." title:"ERROR"
return false
)
pushPrompt "Loading CPV Colours..."
-- open the image and get its size
theimageFile = openBitmap texToLoad
theImageSize = theimageFile.width
local theCount = collectedMeshData.count
allstartTime = timeStamp()
for collectedVert = 1 to theCount do
(
theUVpos = collectedMeshData[collectedVert].vertUVArray[1][3]
-- Calculate the UV coordiante based on the image size
-- Bitmaps are upside down, so invert the Y
xyUV = [theUVpos.x * theImageSize, theImageSize - (theUVpos.y * theImageSize)]
thePixelColour = getPixels theimageFile xyUV 1
if (classOf meshObject.baseObject == Editable_Poly) then
(
polyOp.setVertColor meshObject 11 collectedVert thePixelColour[1]
)
else if (classOf meshObject.baseObject == Editable_mesh) then
(
meshOp.setVertColor meshObject 11 collectedVert thePixelColour[1]
)
)
allendTime = timeStamp()
format "Search time for all verts in all images was :% seconds\n" ((allendTime-allstartTime )/ 1000)
-- close the image
close theimageFile
free theimageFile
popPrompt()
print "Finished Loading Skin Weights."
messagebox "Finished Loading Skin Weights."
)
-- turns on display of the wind channel vertex colours
fn RsTa_TBCPV_setDisplayMode theObject=
(
theObject.showVertexColors = true
theObject.vertexColorsShaded = false
theObject.vertexColorType = #Map_Channel
theObject.vertexColorMapChannel = 11
)