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

592 lines
16 KiB
Plaintext
Executable File

-- Required for building fragment-proxys:
filein "pipeline/export/maps/mapsetup.ms"
struct RsPropRenderSettings
(
buildFragsBool=undefined,
p4checkoutBool=undefined,
syncTexturesBool=undefined,
renderOutputPath=undefined,
renderStandardBool=undefined,
renderScaleObjectBool=undefined,
renderAngle=undefined,
minCamZoom = undefined,
jpgQualitySetting =undefined,
batchMode = false
)
struct RsPropRenderUtils
(
fn GenerateAndSaveImages filename renderSmall:false edgeFaces:false ThumbSize:[640,480] RatioDiff:1.0 =
(
clearSelection()
-- Large img
viewport.setShowEdgeFaces edgeFaces
redrawviews()
img = gw.getViewportDib()
img.filename = filename
save img
-- format "Render: %\n" (RsMakeBackSlashes filename)
if (RatioDiff != 1.0) do
(
local tempTexture = bitmapTexture bitmap:img
case of
(
(RatioDiff > 1):
(
tempTexture.coords.U_Tiling /= RatioDiff
)
(RatioDiff < 1):
(
tempTexture.coords.V_Tiling *= RatioDiff
)
)
img = renderMap tempTexture size:ThumbSize filter:False
img.filename = filename
save img
)
-- Small img
if renderSmall do
(
smallImg = bitmap (ThumbSize.X / 2) (ThumbSize.Y / 2)
copy img smallImg
smallImg.filename = (getFilenamePath filename) + (getFilenameFile filename) + "_Small.jpg"
-- format "Render: %\n" smallImg.filename
save smallImg
close smallImg
)
close img
),
--
-- fn: GetObjDimensions
-- desc: Returns the object's dimensions
--
fn GetObjDimensions obj bb =
(
widthX = bb[2].x - bb[1].x
lengthY = bb[2].y - bb[1].y
heightZ = bb[2].z - bb[1].z
-- Incase these come out negative, make them positive
if (widthX < 0 ) do
(
widthX *= -1
)
if (lengthY < 0 ) do
(
lengthY *= -1
)
if (heightZ < 0 ) do
(
heightZ *= -1
)
objDim = Point3 widthX lengthY heightZ
),
fn getObjRadius obj objCentre xyRadius:false=
(
-- Get the max radius of the object:
local centreOffset = objCentre - obj.pos - obj.objectoffsetpos
if xyRadius do
(
centreOffset.z = 0
)
local objMesh = copy obj.mesh
local objRadius = 0.0
local vertPos, vertDist
for vert in objMesh.verts do
(
vertPos = vert.pos
if xyRadius do (vertPos.z = 0)
vertDist = distance (vertPos * obj.scale) centreOffset
if (vertDist > objRadius) do (objRadius = vertDist)
)
objRadius
),
--
-- fn: PositionScaleObj
-- desc: Places the scale-object (i.e. standing human) depending on the size of the object being rendered
--
fn PositionScaleObj ScaleObj objDim objCentre ScaleObjDim ScaleObjRadius camAngle=
(
ScaleObj.isHidden = false
ScaleObj.wirecolor = case of
(
-- Object is shown as pink if object is over 10 units
(objDim.z >= 10):(color 255 64 200)
-- Yellow if between 2 and 10 units
(objDim.z >= 2):(color 200 200 32)
-- Green if smaller than 2 units
Default:(color 0 128 0)
)
ScaleObj.pos = objCentre
-- The origin isn't consistent for all objects - some have their z origin in their centre
-- so make sure the ScaleObj is 'standing' at same level as the prop is, rather than just
-- relying on the origin to always start on the 'ground' plane
ScaleObj.pos.z = objCentre.z - (objDim.z / 2)
local posMults = #([1,1,0],[1,-1,0],[-1,-1,0],[-1,1,0])
local posMultNum = case of
(
(camAngle == (eulerAngles 0 0 90)):1
(camAngle == (eulerAngles 0 0 0)):2
(camAngle == (eulerAngles 0 0 180)):3
(camAngle == (eulerAngles 0 0 -90)):4
)
-- If obj is longer (x axis) than longer (y axis), put ScaleObj in front/behind
-- Otherwise, put ScaleObj to left of object
local posMult = if (objDim.x < objDim.y) then posMults[posMultNum]
else
(
if (objDim.z > ScaleObjDim.z) then
(
posMultNum -= 1
)
else
(
posMultNum += 1
)
posMultNum = mod posMultNum 4
if (posMultNum == 0) do (posMultNum = 4)
posMult = posMults[posMultNum] * [0,1,0]
)
ScaleObj.pos += (posMult * (ScaleObjRadius + (objDim / 2)))
),
-- this should be called directly after creating the camera, but before you transform the camera at all... it is a simple setup.
fn placeTextInRender parentCamera renderTextString=
(
local placedTextObj = text size:0.25 text:renderTextString render_renderable:true wirecolor:[255,0,0] pos:parentCamera.target.pos render_thickness:0.05
rotate placedTextObj (eulerAngles 90 0 90)
move placedTextObj [-10, 0, -2.5]
placedTextObj.parent = parentCamera
),
-- This needs to be extended to work from a settings file in the future. for now it is hard coded
fn generateTextFlags filepath=
(
local textFlag = undefined
local pathCases = #(datapair name:"lev_des" value:"DESIGN ONLY", datapair name:"areas" value:"AREA FILE TEST")
for pattern in pathCases do
(
if (matchpattern (toLower filepath) pattern:("*" + pattern.name + "*")) then
(
if textFlag == undefined then
(
textFlag = pattern.value
)
else
(
textFlag = textFlag + ", " + pattern.value
)
)
)
textFlag
),
--
-- fn: SetupCamera
-- desc: Returns a camera and sets the viewport to use it for the render
--
fn SetupCamera cam objCentre objRadius camDistanceFactor camMinZoom camAngle =
(
if (objRadius < camMinZoom) do -- Set minimum object-size for zooming:
(
objRadius = camMinZoom
)
local camDirMult = case of
(
( camAngle == (eulerAngles 0 0 90)):[-1,1,1]
(camAngle == (eulerAngles 0 0 0)):[1,1,1]
(camAngle == (eulerAngles 0 0 180)):[-1,-1,1]
(camAngle == (eulerAngles 0 0 -90)):[1,-1,1] -- Default direction
)
cam.target.pos = objCentre
cam.fovType = 1
local camDistance = (objRadius * 1.0) / (tan (0.5 * cam.curFOV))
cam.pos = objCentre + (camDirMult * camDistance * camDistanceFactor)
cam.clipManually = true
cam.nearclip = 0.0
viewport.setcamera cam
cam
),
--
-- fn: RenderSelected
-- desc: Render selected objects out to network drive, two images.
-- One rendered textured, another with edged faces and a standing-human scale-object.
--
--fn RenderObjs objs buildFrags:chkRebuildFrags.checked p4checkout:chkPerforce.checked syncTextures:chkSyncTextures.checked =
fn RenderObjs objs settingsObject quiet:true ThumbSize:[640,480] =
(
local modelsDir = RsConfigGetModelSourceDir()
local modelsDirCount = modelsDir.count
local currentPath = RsMakeSafeSlashes (maxfilePath + (getFilenameFile maxfileName))
print ("Cur Path:" + currentPath)
if not (matchPattern currentPath pattern:(modelsDir + "*")) do
(
messageBox ("Can't render props - Maxfile must be saved under:\n\n" + modelsDir) title:"Error: Invalid Maxfile path"
return false
)
local textFlag = generateTextFlags currentPath --used to generate text in the render
--print ("TEXTFLAGS:" + textFlag)
local exportPath = RsMakeSafeSlashes (settingsObject.renderOutputPath + "/" + (substring currentPath modelsDirCount -1) + "/")
RsMakeSurePathExists exportPath
if settingsObject.buildFragsBool do
(
gRsMapExportFragments.preExportRename()
gRsMapExportFragments.buildAllFragments silent:true objs:objs
gRsMapExportFragments.postExportRename()
)
-- Filter objs down to what we're actually going to render
local doObjs = for obj in objs where (isValidNode obj) collect
(
local useObj = obj
local isFragProxy = False
-- If this is a frag object, render its proxy
if (matchpattern obj.name pattern:"*_frag_") do
(
local fragProxy = getNodeByName (substring obj.name 1 (obj.name.count - 6))
useObj = fragProxy
if (useObj != undefined) do
(
isFragProxy = True
)
)
if
(
-- Only render for Gta Objects:
(GetAttrClass useObj == "Gta Object") and
-- Don't render if object-parent is geometry too:
(GetAttrClass useObj.parent != "Gta Object") and
-- Don't render for X/RsRefs:
(not isRefObj useObj) and
-- Don't render thumbs for objects with SceneLink children: (i.e. LODs of all kinds)
(
local getObjs = #()
RsSceneLink.GetChildren -1 obj &getObjs
(getObjs.count == 0)
) and
-- Don't render "Dont Export" geometry, unless it's a Frag Proxy:
(isFragProxy or ((GetAttr useObj (GetAttrIndex "Gta Object" "Dont Export")) != true))
)
then useObj else dontCollect
)
-- Pre-generate the object-filenames:
local renderFiles = #()
local defaultFilenames = #()
local scaleFilenames = #()
for obj in doObjs do
(
local filenameStart = exportPath + obj.name
if settingsObject.renderStandardBool do
(
append defaultFilenames (filenameStart + ".jpg")
)
if settingsObject.renderScaleObjectBool do
(
append scaleFilenames (filenameStart + "_Jaxx.jpg")
)
)
local renderFiles = #()
join renderFiles defaultFilenames
join renderFiles scaleFilenames
-- Exit if no files are to be rendered:
if (renderFiles.count == 0) do
(
return true
)
if settingsObject.p4checkoutBool do
(
-- Perforce-add/edit all render-files:
pushPrompt "Preparing Perforce for export"
local perforceSuccess = gRsPerforce.add_or_edit renderFiles queueAdd:true
popPrompt()
if (not perforceSuccess) and (queryBox "Problems were encountered accessing Perforce.\nCancel render?" title:"Prop Render: Perforce Errors") do
(
return false
)
)
if settingsObject.syncTexturesBool do
(
local matsUsed = #()
for obj in doObjs do
(
local objMats = RsGetMaterialsOnObjFaces obj
join matsUsed objMats
)
local textureList = #()
for mat in (makeUniqueArray matsUsed) do
(
RsGetMaterialTextures mat textureList:textureList
)
RsP4syncTextures textureList
)
undo off
(
-- Changing render-options is slow when Diplay panel is up, so this'll speed it up:
max create mode
-- Remember which things were hidden/shown
local selectionWas = selection as array
local objectsWas = objects as array
local hiddenWas = for obj in objectsWas collect obj.isHidden
for object in objects do (object.isHidden = true)
local activeViewport = viewport.activeViewport
local gridVisWas = viewport.getGridVisibility activeViewport
viewport.setGridVisibility #all false
local renderLevelWas = viewport.getRenderLevel()
viewport.setRenderLevel #smoothhighlights
local jpegQualityWas = jpeg.getQuality()
jpeg.setQuality settingsObject.jpgQualitySetting
local BGColorWas = getUIColor 41
setUIColor 41 [0.49,0.49,0.49]
local displayColorWireframeWas = displayColor.wireframe
local displayColorShadedWas = displayColor.shaded
displayColor.wireframe = #object
displayColor.shaded = #material
local edgeFacesWas = viewport.getShowEdgeFaces()
local viewCamWas = getActiveCamera()
local viewTypeWas = viewport.getType()
viewport.setType #view_persp_user
local viewTMWas = viewport.getTM()
local fovWas = viewport.getFOV()
local focalWas = viewport.getFocalDistance()
local windowSizeWas = [gw.getWinSizeX(), gw.getWinSizeY()]
local camDistanceFactor = 1.1
-- Set viewport size/shape:
local currentSizeRatio = (windowSizeWas.X / windowSizeWas.Y)
local ThumbSizeRatio = (ThumbSize.X / ThumbSize.Y)
local RatioDiff = (currentSizeRatio / ThumbSizeRatio)
local newViewSize = ThumbSize
case of
(
(RatioDiff > 1):
(
newViewSize = [ThumbSize.X * RatioDiff, ThumbSize.Y]
camDistanceFactor *= RatioDiff
)
(RatioDiff < 1):
(
newViewSize = [ThumbSize.X, ThumbSize.Y / RatioDiff]
)
)
--format "%, % : %\n" currentSizeRatio ThumbSizeRatio newViewSize
gw.setPos 0 0 newViewSize.X newViewSize.Y
-- If the viewcube or stats is visible, turn it off for renders.
-- Turned back on at end, if it was visible before this script was called.
local viewCubeWas
if (ViewCubeOps != undefined) do
(
viewCubeWas = ViewCubeOps.Visibility
ViewCubeOps.Visibility = false
)
popPrompt()
local cam = TargetCamera target:(TargetObject())
if textFlag != undefined then
(
placeTextInRender cam textFlag -- add text into the render...
)
local ScaleObj = undefined
local copyObj = undefined
-- try
(
progressStart "Rendering objects:"
format "Rendering % objects to \"%\"\n%\n" doObjs.count exportPath (doObjs as string)
-- Create scale-object:
ScaleObj = P_Standing()
local ScaleObjBB = nodeLocalBoundingBox ScaleObj
local ScaleObjDim = GetObjDimensions ScaleObj ScaleObjBB
local ScaleObjRadius = 0.45 --getObjRadius ScaleObj [0,0,0] xyRadius:true
local ScaleObjRot = settingsObject.renderAngle
rotate ScaleObj ScaleObjRot
for objNum = 1 to doObjs.count while (progressupdate ((100.0 * objNum) / doObjs.count)) do
(
local obj = doObjs[objNum]
local bb = nodeLocalBoundingBox obj
local objCentre = (bb[1]+ bb[2]) / 2
local objDim = GetObjDimensions obj bb
local objRadius = getObjRadius obj objCentre
cam = SetupCamera cam objCentre objRadius camDistanceFactor settingsObject.minCamZoom settingsObject.renderAngle
filenameConcat = exportPath + obj.name
-- Show object:
obj.isHidden = false
-- Make inverted copy, to make up for lack of 2-sidedness in some shaders:
copyObj = copy obj
copyObj.name += "_TEMPCOPY"
addModifier copyObj (Mesh_Select())
addModifier copyObj (Normalmodifier flip:true)
select obj
-- Render default image:
if settingsObject.renderStandardBool do
(
ScaleObj.isHidden = true
GenerateAndSaveImages defaultFilenames[objNum] edgeFaces:false ThumbSize:ThumbSize RatioDiff:RatioDiff
)
-- Render scale-object image
if settingsObject.renderScaleObjectBool do
(
ScaleObj.isHidden = false
scaleFilename = scaleFilenames[objNum]
PositionScaleObj ScaleObj objDim objCentre ScaleObjDim ScaleObjRadius settingsObject.renderAngle
select #(obj, ScaleObj)
GenerateAndSaveImages scaleFilename edgeFaces:true ThumbSize:ThumbSize RatioDiff:RatioDiff
)
delete copyObj
-- Hide object again for now
obj.isHidden = true
)
)
-- catch
(
-- format "Exception caught while rendering the props:\n%\n" (getCurrentException())
)
progressEnd()
for TempObj in #(Cam, ScaleObj, CopyObj) do
(
if (isValidNode TempObj) do
(
delete TempObj
)
)
pushPrompt "Restoring viewport settings"
-- Revert object-hidden states
for n = 1 to objectsWas.count do
(
objectsWas[n].isHidden = hiddenWas[n]
)
clearSelection()
select selectionWas
-- Revert viewport settings
gw.setPos 0 0 windowSizeWas.X windowSizeWas.Y
viewport.setFocalDistance focalWas
viewport.setFOV fovWas
viewport.setTM viewTMWas
viewport.setType viewTypeWas
viewport.setGridVisibility activeViewport gridVisWas
viewport.setRenderLevel renderLevelWas
viewport.setShowEdgeFaces edgeFacesWas
displayColor.wireframe = displayColorWireframeWas
displayColor.shaded = displayColorShadedWas
setUIColor 41 BGColorWas
jpeg.setQuality jpegQualityWas
if (viewCubeWas != undefined) do
(
ViewCubeOps.Visibility = viewCubeWas
)
popPrompt()
)
-- Add queued files to Perforce, if any:
gRsPerforce.postExportAdd showProgress:showProgress
if quiet == false then
(
messageboxmessage = "Successfully rendered " + doObjs.count as string + " objects."
messagebox messageboxmessage title:"Render Finished" beep:false
)
setFocus RsRenderPropsRoll
return true
)
)