global gExportString = stringstream "" global gOptimisedMesh = undefined filein "pipeline/util/scene.ms" fn RsIsVertOnPolyEdge vMiddleIndex obj connectedVerts:undefined &hasNoSurface:undefined = ( -- set edge selection to visible edges setedgeselection obj.mesh #{} local edgeSelSet=#() for face = 1 to obj.mesh.numfaces do -- Go through all faces for edgei = 1 to 3 do -- And for every of the 3 edges if (getedgevis obj.mesh face edgei) do ( append edgeSelSet (((face-1)*3)+edgei) ) setEdgeSelection (obj.mesh) edgeSelSet local edges = meshop.getEdgesUsingVert obj vMiddleIndex local selEdges = getEdgeSelection obj.mesh edges = edges * selEdges local allVerts = meshop.getVertsUsingEdge obj edges local vertArray = allverts as array -- print vertArray -- print vMiddleIndex if undefined!=connectedVerts then for v in vertArray where v!=vMiddleIndex do append connectedVerts v -- print ("num edges: "+edges as string) if edges.numberSet >2 or edges.numberSet <2 then ( return true ) local vertDataArray = for v in vertArray where v!=vMiddleIndex collect getVert obj.mesh v if vertDataArray.count<2 then ( return true ) local vMiddleData = getvert obj.mesh vMiddleIndex -- print vertDataArray local vec1 = vertDataArray[1] - vMiddleData vec1 = normalize vec1 local vec2 = vertDataArray[2] - vMiddleData vec2 = normalize vec2 if undefined!=hasNoSurface then ( print ("cross prod length:"+(length (cross vec1 vec2)) as string) hasNoSurface = (length (cross vec1 vec2)) < 0.1 ) -- print (vec1 as string +", "+ vec2 as string +" dot product:"+(dot vec1 vec2) as string) return (dot vec1 vec2) > -0.95 ) fn RsSnapVert v gridSize dirx:0 diry:0 = ( local halfTileSize = gridSize/2 local modX = mod v.x gridSize v.x = if modX>halfTileSize or dirx>0 then (v.x+(gridSize-modX)) else (v.x-modX) local modY = mod v.y gridSize v.y = if modY>halfTileSize or diry>0 then (v.y+(gridSize-modY)) else (v.y-modY) ) -- $RsWaterHelper002.optimise() plugin Helper RsWaterHelper extends:dummy name:"RSWaterMesh" classID:#(0x32ab796e, 0x4322237a) category:"Gta Helpers" ( local WATER_TILE_SIZE = 4 parameters main rollout:ParticleParams ( meshObj type:#maxObject ) struct sTreeNode(size, children) fn getQuadTree = ( refsArray = (refs.dependents this) local theNode = for i in refsArray where isvalidnode i collect i if (classof theNode)==Array then theNode = theNode[1] local bb = nodeGetBoundingBox theNode (matrix3 1) local startX = bb[1].x local startY = bb[1].y local endX = bb[2].x local endY = bb[2].y --meshOps.startSlicePlane meshObj.mesh while startXv.x then minTri.x = v.x if minTri.y>v.y then minTri.y = v.y if maxTri.x too small to cut" if undefined!=isTooSmall then isTooSmall = true ) local maxXFound = for v in vertDataArray where (isAbout v.x maxTri.x) collect v -- print ("maxXFound:"+maxXFound.count as string) local minXFound = for v in vertDataArray where (isAbout v.x minTri.x) collect v -- print ("minXFound:"+minXFound.count as string) local maxYFound = for v in vertDataArray where (isAbout v.y maxTri.y) collect v -- print ("maxYFound:"+maxYFound.count as string) local minYFound = for v in vertDataArray where (isAbout v.y minTri.y) collect v -- print ("minYFound:"+minYFound.count as string) -- print "*********" local colour = (color 0 0 0) if minXFound.count==2 and minYFound.count==2 and maxXFound.count!=2 and maxYFound.count!=2 then (type =2; colour = (color 255 0 0)) else if minXFound.count==2 and maxYFound.count==2 and maxXFound.count!=2 and minYFound.count!=2 then (type =3; colour = (color 0 255 0)) else if maxXFound.count==2 and maxYFound.count==2 and minXFound.count!=2 and minYFound.count!=2 then (type =4; colour = (color 0 0 255)) else if maxXFound.count==2 and minYFound.count==2 and minXFound.count!=2 and maxYFound.count!=2 then (type =5; colour = (color 255 0 255)) else if maxXFound.count==2 and minYFound.count==2 and minXFound.count==2 and maxYFound.count==2 then (type =1; colour = (color 255 255 255)) -- print type return type ) fn SnapVertsToClosestGridPoint obj maximise:false = ( local objBB = #() local allVerts = for i=1 to getnumVerts obj.mesh collect (getVert obj.mesh i) TestIsRectAngle allVerts bb:objBB local bbmin = objBB[1] local bbmax = objBB[2] local objCenter = (bbmax + bbmin) / 2 for vi=1 to obj.mesh.numverts do ( local currVert = getvert obj.mesh vi local dirx=0 local diry=0 if maximise then ( if currVert.x>objCenter.x then ( currVert.x = bbmax.x dirx = 1 ) else ( currVert.x = bbmin.x dirx = -1 ) if currVert.y>objCenter.y then ( currVert.y = bbmax.y diry = 1 ) else ( currVert.y = bbmin.y diry = -1 ) ) RsSnapVert currVert WATER_TILE_SIZE -- dirx:dirx diry:diry setvert obj.mesh vi currVert ) ) fn OptimiseFaceRec obj recurseFunction depth createMesh:false = ( -- is valid poly -- 1) go thruogh verts and optimise away ones not on corners -- 2) snap verts to closest grid to make closest to a valid face - inconsitencies come from subdivision cutting on sloped adges -- 3) subdivide if still not valid local allVertsOnPolyEdge = false local allVerts = #() local catcher = 1 allVerts = for i=1 to getnumVerts obj.mesh collect (getVert obj.mesh i) while false==allVertsOnPolyEdge and catcher<10 do ( allVerts = for i=1 to getnumVerts obj.mesh collect (getVert obj.mesh i) -- print allVerts -- print "******" try ( for vi=1 to allVerts.count do ( local connectedVerts = #() if not RsIsVertOnPolyEdge vi obj connectedVerts:connectedVerts then ( -- for channels = for i=1 to 1 do collect meshop.getMapVert obj i formerVert local formerVert = connectedVerts[1] -- print ("formerVert:"+formerVert as string) meshop.weldVertSet obj #{vi,formerVert} weldpoint:allVerts[formerVert] --deleteVert obj.mesh vi throw "welded vertex - vertcount out of sync." -- for ci=1 to channels.count do -- ( -- meshop.setMapVert obj i formerVert -- ) ) ) -- print "all fine - go ahead" allVertsOnPolyEdge = true )catch( -- print (getCurrentException()) ) catcher = catcher+1 ) -- subdivide if still not valid local tooSmall = false local type = TestIsRectAngle allVerts isTooSmall:&tooSmall local doSubdivide = false if allVerts.count>4 then ( doSubdivide = true ) else if allVerts.count>2 and (type == 0) and not tooSmall then ( doSubdivide = true ) else if allVerts.count<=2 then ( print ("poly with less than 3 verts?!:"+allVerts.count as string) return false ) -- snap to closest grid point if (not doSubdivide) or tooSmall then SnapVertsToClosestGridPoint obj maximise:true if doSubdivide then ( local oldNumVerts = obj.mesh.numverts local startVertIndex = 1 local hasNoSurface = false while obj.mesh.numverts == oldNumVerts and allVerts.count>=startVertIndex and (RsIsVertOnPolyEdge startVertIndex obj hasNoSurface:&hasNoSurface) do ( local currVert = allVerts[startVertIndex] meshOp.slice obj obj.mesh.faces (point3 0 1 0) currVert.y startVertIndex = startVertIndex + 1 -- print ("obj.mesh.numverts:"+obj.mesh.numverts as string) ) startVertIndex = 1 while obj.mesh.numverts == oldNumVerts and allVerts.count>=startVertIndex and (RsIsVertOnPolyEdge startVertIndex obj hasNoSurface:&hasNoSurface) do ( local currVert = allVerts[startVertIndex] meshOp.slice obj obj.mesh.faces (point3 1 0 0) currVert.x startVertIndex = startVertIndex + 1 -- print ("obj.mesh.numverts:"+obj.mesh.numverts as string) ) if obj.mesh.numverts == oldNumVerts then ( print "couldnt subdivide mesh" return true ) else if hasNoSurface then ( print "poly has no surface!" return false ) else if undefined!=recurseFunction and depth<10 then ( WalkThroughPolys obj recurseFunction depth:(depth+1) createMesh:createMesh return true ) return true ) -- else print "poly is perfect" return true ) fn OptimiseFace obj polyfaces depth createMesh:false = ( -- print (obj as string + " polyfaces to detach :"+polyfaces as string) local mYMesh = createinstance Editable_Mesh mYMesh.mesh = meshop.detachFaces obj.mesh polyfaces delete:false asMesh:true local validMeshProduced = OptimiseFaceRec mYMesh OptimiseFace depth createMesh:createMesh -- print (depth as string + " was optimised "+wasoptimised as string) if validMeshProduced then ( return mYMesh ) else ( local newMesh = Editable_Mesh name:"Abandoned geom" newMesh.mesh = mYMesh.mesh return undefined ) ) fn Optimise = ( gOptimisedMesh = createinstance Editable_Mesh -- name:"newMesh" WalkThroughPolys meshobj OptimiseFace depth:0 createMesh:true meshobj.mesh = gOptimisedMesh.mesh ) fn setMyMesh obj optimiseMesh:false = ( local copyObj = copy obj converttomesh copyObj if "Gta Object"==(getattrclass copyObj) then ( meshObj = copyObj.mesh delete copyObj for vi=1 to getNumVerts meshObj.mesh do ( local v = (getvert meshObj.mesh vi) RsSnapVert v WATER_TILE_SIZE --v.z = if (mod v.z 1)>0.5 then ceil v.z else floor v.z setvert meshObj.mesh vi v ) if optimiseMesh then Optimise() refsArray = (refs.dependents this) local theNode = for i in refsArray where isvalidnode i collect i if (classof theNode)==Array then theNode = theNode[1] theNode.transform = obj.transform return true ) return false ) fn ExtractCallback obj polyfaces depth = ( local allVerts = meshop.getVertsUsingFace meshObj.mesh polyfaces local polyVertArray = allVerts as array local vertDataArray = #() local mapVertChannel1DataArray = #() local mapVertChannel2DataArray = #() for v in polyVertArray do ( local vd = (getVert meshObj.mesh v) append vertDataArray vd local vdc1 = (point3 0 0 0)--(meshop.getMapVert meshObj.mesh 1 v) append mapVertChannel1DataArray vdc1 local vdc2 = (point3 0 0 0)--(meshop.getMapVert meshObj.mesh 2 v) append mapVertChannel2DataArray vdc2 ) local isTriangle = polyVertArray.count ==3 local type = 1 if isTriangle then ( if polyVertArray.count!=3 then ( messagebox ("vert count in triangle not correct:"+polyVertArray.count as string+" on poly using faces "+polyfaces as string) setFaceSelection meshObj.mesh polyfaces continue ) type = TestIsRectAngle vertDataArray ) else ( if polyVertArray.count!=4 then ( messagebox ("vert count in quad not correct:"+polyVertArray.count as string+" on poly using faces "+polyfaces as string) setFaceSelection meshObj.mesh polyfaces continue ) ) refsArray = (refs.dependents this) local theNode = for i in refsArray where isvalidnode i collect i if (classof theNode)==Array then theNode = theNode[1] -- print ("theNode:"+theNode as string) isVisible = getattr theNode (getattrindex "Gta Water" "Visible") isLimitedDepth = getattr theNode (getattrindex "Gta Water" "Limited Depth") isStandard = getattr theNode (getattrindex "Gta Water" "Standard") isCalming = getattr theNode (getattrindex "Gta Water" "Calming") valCalmness = getattr theNode (getattrindex "Gta Water" "Calmness") outputFlags = 0 -- print ("isVisible:"+isVisible as string) -- print ("isLimitedDepth:"+isLimitedDepth as string) -- print ("isStandard:"+isStandard as string) -- print ("isCalming:"+isCalming as string) -- print ("valCalmness:"+valCalmness as string) if isVisible == true then ( outputFlags = outputFlags + 1 ) if isLimitedDepth == true then ( outputFlags = outputFlags + 2 ) if isStandard == true then ( outputFlags = outputFlags + 4 ) if isCalming == true then ( outputFlags = outputFlags + 8 ) for vi=1 to vertDataArray.count do ( format "% % % % % % % " \ vertDataArray[vi].x vertDataArray[vi].y vertDataArray[vi].z \ -- position mapVertChannel1DataArray[vi].x mapVertChannel1DataArray[vi].y \ -- flow direction mapVertChannel2DataArray[vi].x \ -- big wave streength mapVertChannel2DataArray[vi].y \ -- small wave strength to:gExportString ) format " % % %\n" outputFlags valCalmness type to:gExportString return undefined ) fn getWaterpolys = ( gExportString = stringstream "" WalkThroughPolys meshobj ExtractCallback return gExportString as string ) fn getMesh = meshObj rollout ParticleParams "" ( pickbutton btnPickMesh "pick new mesh" across:2 checkbox chckOptimise "optimise" offset:[13,5] checked:true button btnMeshConvert "Extract mesh" width:130 on btnPickMesh picked obj do ( if undefined==getattrclass or "Gta Object"==(getattrclass obj) then setMyMesh obj optimiseMesh:(chckOptimise.state) ) on btnMeshConvert pressed do ( refsArray = (refs.dependents this) local theNode = for i in refsArray where isvalidnode i collect i if (classof theNode)==Array then theNode = theNode[1] local newMesh = Editable_Mesh name:theNode.name transform:theNode.transform newMesh.mesh = meshObj.mesh select newMesh --delete theNode ) ) --fn getDisplayMesh = on getDisplayMesh do ( --print ("forceRebuild:"+gForceParticleHelperRebuild as string) if undefined==meshobj then ( local newMesh = createinstance plane newMesh.width=1 newMesh.length=1 newMesh.lengthsegs=1 newMesh.widthsegs=1 meshobj = newMesh ) return meshObj.mesh ) tool create ( on mousePoint click do ( if undefined!=RsMouseclickBoundsIntersect then ( in coordsys screen objs = RsMouseclickBoundsIntersect viewPoint:viewPoint for o in objs do ( if not o.isHiddenInVpt then ( print ("found:"+o as string) setMyMesh o optimiseMesh:(ParticleParams.chckOptimise.state) return #stop ) ) messagebox "No node was hit, creatin at origin. Please link to object via according button." ) return false ) on mouseAbort clickno do print "aborted" on end do print "Ending" ) )