-- -- File:: rockstar/helpers/TerrainLodder.ms -- Description:: Terrain Lodder -- -- Author:: Stuart Macdonald 0 then ( --get the face hit local theIndex = rayMesh.getClosestHit() --get the index of the closest hit by the ray local theFace = rayMesh.getHitFace theIndex --get the barycentric coords of the face hit local baryPt = rayMesh.getHitBary theIndex --get the mapverts for the face hit local faceMapVerts = meshop.getMapFace targetMesh channel theFace --will be in index order --local faceMapVerts = (meshop.getMapVertsUsingMapFace targetMesh channel theFace) as Array --get the mapvert values for the face hit local mapVertValues = #((meshop.getMapVert targetMesh channel faceMapVerts.x), (meshop.getMapVert targetMesh channel faceMapVerts.y), (meshop.getMapVert targetMesh channel faceMapVerts.z)) --result is the barycentric offset weighted value of the mapvert values local colour = (baryPt.x * mapVertValues[1]) + (baryPt.y * mapVertValues[2]) + (baryPt.z * mapVertValues[3]) --set the colour local geoFaces = meshop.getFacesUsingVert sourceMesh vtx as Array for f in geoFaces do ( local geoFaceVerts = getFace sourceMesh f local mapFaceVerts = meshop.getMapFace sourceMesh channel f --will be in index order --match up indices mapVert = case of ( (geoFaceVerts.x == vtx): mapFaceVerts.x (geoFaceVerts.y == vtx): mapFaceVerts.y (geoFaceVerts.z == vtx): mapFaceVerts.z ) meshop.setMapVert sourceMesh channel mapVert colour ) ) ) update source ) on picklodmtl picked mtl do ( LODmat = mtl picklodmtl.caption = mtl.name ) on lodit pressed do ( selset = getCurrentSelection() lodset = #() -- If it's not an editable mesh or poly, exit here rather than possibly after changing some -- selected objects in the next loop. for obj in selset do ( if (( classOf obj != editable_Mesh) and ( classOf obj != editable_Poly)) then ( messagebox "One of the selected objects is not an editable mesh or poly" return false ) ) undo "Create Terrain LOD" on ( clearselection() for n = 1 to selset.count do ( -- Delete any faces with 0 area, as that causes a crash after Multires -- whenever garbage collection is next done. RSFindFacesWithZeroArea selset[n] deleteFaces:true --check it is editable mesh, convert if classOf selset[n] == editable_Mesh then convertTo selset[n] Editable_Poly --check obj is editable poly if classOf selset[n] == editable_Poly then ( selOuterVerts selset[n] newlod = copy selset[n] highLodModel = selset[n] --check whether prefix LOD_ or postfix _LOD if rbt_lod.state == 1 then ( newlod.name = "LOD_" + selset[n].name ) else newlod.name = selset[n].name + "_LOD" -- Automatically link the LOD if (newlod != undefined and highLodModel != undefined) do ( LinkType_LOD = 0 RsSceneLink.AddContainer LinkType_LOD selset[n] RsSceneLink.SetParent LinkType_LOD selset[n] newlod ) append lodset newlod ) ) max modify mode --run push on each object for n = 1 to lodset.count do ( select lodset[n] optlod() pushlod() projectVertexMap lodset[n] selset[n] channel:-2 collapseStack lodset[n] PolyToolsModeling.Quadrify false false --Apply standard material if none picked if LODmat == undefined then ( lodset[n].material = standardMaterial() lodset[n].material.name = "CHANGE_THIS" ) else lodset[n].material = LODmat ) --select the lods select lodset selectMore selset clearselection() select lodset ) ) ) rollout TerrainLodder_MultiRes "MultiRes" ( --variables local LODmat button lodit "LOD IT" pos:[19,125] width:243 height:24 radioButtons rbt_lod "Name Position:" pos:[17,27] width:118 height:30 labels:#("LOD_", "_LOD") default:2 columns:2 materialbutton picklodmtl "Pick LOD Mat" pos:[149,36] width:100 height:23 spinner optrange "Vert" range:[1,100,60] type:#integer pos:[27,81] width:104 height:16 spinner pushrange "Push" range:[-10.0,10.0,-0.2] pos:[27,101] width:104 height:16 range:[0,100,0] label lblVert "Percentage of verts left:" pos:[17,64] width:128 height:16 checkbox chbx_mverts "Keep Base Verts" checked:true tooltip:"keep this on for terrain" pos:[150,85] width:103 height:17 --select inner verts of polymesh fn selInnerVerts n = ( --Get exterior vertices OpenEdges = polyOp.getOpenEdges n SelVerts = polyOp.getVertsUsingEdge n OpenEdges n.selectedVerts = -SelVerts ) --select outer verts of polymesh fn selOuterVerts n = ( --Get exterior vertices OpenEdges = polyOp.getOpenEdges n SelVerts = polyOp.getVertsUsingEdge n OpenEdges n.selectedVerts = SelVerts ) --optimize function fn optlod = ( modPanel.addModToSelection (Multires()) $.modifiers[#MultiRes].resetParams = true $.modifiers[#MultiRes].vertexPercent = optrange.value $.modifiers[#MultiRes].baseVertices = chbx_mverts.state $.modifiers[#MultiRes].reqGenerate = true ) --push function fn pushlod = ( convertTo $ Editable_Poly selInnerVerts $ subObjectLevel = 1 --Add the Push mod pushmod = push() pushmod.push_value = pushrange.value modPanel.addModtoSelection( pushmod ) ) on picklodmtl picked mtl do ( LODmat = mtl picklodmtl.caption = mtl.name ) on lodit pressed do ( if ( false == querybox "Previous MAX crash with Multires has been avoided - do you want to continue? (Save recommended just incase)" ) do ( return false ) gc light:true selset = getCurrentSelection() lodset = #() -- If it's not an editable mesh or poly, exit here rather than possibly after changing some -- selected objects in the next loop. for obj in selset do ( if (( classOf obj != editable_Mesh) and ( classOf obj != editable_Poly)) then ( messagebox "One of the selected objects is not an editable mesh or poly" return false ) ) clearselection() for n = 1 to selset.count do ( -- Delete any faces with 0 area, as that causes a crash after Multires -- whenever garbage collection is next done. RSFindFacesWithZeroArea selset[n] deleteFaces:true --check it is editable mesh, convert if classOf selset[n] == editable_Mesh then convertTo selset[n] Editable_Poly --check obj is editable poly if classOf selset[n] == editable_Poly then ( selOuterVerts selset[n] newlod = copy selset[n] highLodModel = selset[n] --check whether prefix LOD_ or postfix _LOD if rbt_lod.state == 1 then ( newlod.name = "LOD_" + selset[n].name ) else newlod.name = selset[n].name + "_LOD" -- Automatically link the LOD if (newlod != undefined and highLodModel != undefined) do ( LinkType_LOD = 0 RsSceneLink.AddContainer LinkType_LOD selset[n] RsSceneLink.SetParent LinkType_LOD selset[n] newlod ) append lodset newlod ) ) max modify mode --run push on each object for n = 1 to lodset.count do ( select lodset[n] optlod() pushlod() convertTo lodset[n] Editable_Mesh convertTo selset[n] Editable_Mesh --Apply standard material if none picked if LODmat == undefined then ( lodset[n].material = standardMaterial() lodset[n].material.name = "CHANGE_THIS" ) else lodset[n].material = LODmat ) --select the lods select lodset selectMore selset clearselection() select lodset ) ) rollout TerrainLodder_roll "Terrain Lodder" ( --ui hyperlink lnkHelp "Help?" address:"https://devstar.rockstargames.com/wiki/index.php/LOD_Toolkit#Terrain_Lodder" align:#right color:(color 0 0 255) hoverColor:(color 0 0 255) visitedColor:(color 0 0 255) dropDownList ddlMode "Mode:" items:#("ProOptimize", "MultiRes") subRollout lodMode "TerrainLodder_ProOptimize" width:280 height:380 offset:[-10, 0] fn selectedMode arg = ( case ddlMode.selected of ( "ProOptimize": ( RemoveSubRollout lodMode TerrainLodder_MultiRes AddSubRollout lodMode TerrainLodder_ProOptimize lodMode.height = 380 TerrainLodder_roll.height = 380 ) "MultiRes": ( RemoveSubRollout lodMode TerrainLodder_ProOptimize AddSubRollout lodMode TerrainLodder_MultiRes lodMode.height = 250 TerrainLodder_roll.height = 250 ) ) ) on ddlMode selected arg do selectedMode arg on TerrainLodder_roll open do ( AddSubRollout lodMode TerrainLodder_ProOptimize lodMode.height = 380 TerrainLodder_roll.height = 400 ) -- Save rolled-up state: on TerrainLodder_roll rolledUp down do ( RsSettingWrite "TerrainLodder_roll" "rollup" (not down) ) )