Скрипт расставляет машины по дорогам.
- умеет менять плотность машин (с помощью omni lights -> Near Attenuation)
- проецировать машины на дороги со сложным рельефом
- умет работать с прилинкованными объектами к машинам (например люди в салоне и т.п.)
Данный скрипт полезен, когда надо быстро расставить машины по изогнутым, рельефным дорогам.
Пример работы (spline надо сконвертировать в editable spline):
------------------------------start
-- tested in 3DMax 2014
--units: 1 Unit = 1 Centimeters
try destroyDialog CarsBySpline catch()
--global variables
global CarsBySpline
global LengthSeg = 0
global arrTrafficOmni = #()
global arrSplineData = #()
global theMainMesh = undefined
global theMainSelectionCars = #()
global TempArraysCarsForDelete = #()
--functions
fn filter_spline o = superclassof o == shape --filter only shapes
fn filter_Mesh o = superclassof o == GeometryClass --filter only shapes
fn NormPlanter ArrObj theRoad = (
if ArrObj.count >0 and theRoad != undefined and superclassof theRoad == GeometryClass do(
tempMesh = snapshot theRoad
for i in ArrObj do(
theObj = i
theObjT = theObj.transform
theIntRay = intersectRay tempMesh (Ray [theObjT[4].x, theObjT[4].y, theRoad.max.z + 1000] [0,0,-1])
if theIntRay != undefined do(
NaprVecX = theObjT[1]
NaprVecY = theObjT[2]
x0 = theIntRay.pos.x
y0 = theIntRay.pos.y
z0 = theIntRay.pos.z
x1 = theObjT[4][1]
y1 = theObjT[4][2]
z1 = theObjT[4][3]
l = NaprVecX[1]
m = NaprVecX[2]
n = NaprVecX[3]
A1 = y1*n-y0*n-z1*m+z0*m
B1 = -x1*n+x0*n+z1*l-z0*l
C1 = x1*m-x0*m-y1*l+y0*l
A2 = theIntRay.dir[1]
B2 = theIntRay.dir[2]
C2 = theIntRay.dir[3]
--napravlayshiy vector peresecheniya dvuh ploskostey
DirVX = [B1*C2 - B2*C1, C1*A2 - C2*A1, A1*B2 - A2*B1]
DirVX =if (dot DirVX NaprVecX) > 0 then DirVX else -DirVX
nDirVX = normalize DirVX
DirVY = cross nDirVX theIntRay.dir
DirVY = if (dot DirVY NaprVecY) > 0 then DirVY else -DirVY
nDirVY = normalize DirVY
theNewX = nDirVX
theNewY = nDirVY
theNewZ = theIntRay.dir
theNewPos = theIntRay.pos
theObj.transform = (matrix3 theNewX theNewY theNewZ theNewPos)
)--END if theIntRay != undefined do
) -- END for i in ArrObj do
delete tempMesh
) -- END if ArrObj.count >0 and theGround != undefined do
)
fn instanceCar FlipAxis theSh rb1_state distMin distMax densCars arrNum =
(
if FlipAxis then (tM1 = 1; tM2 = 0) else (tM1 = 0; tM2 = 1)
LengthSeg += length(arrSplineData[arrNum] - arrSplineData[arrNum-1])
if LengthSeg >= (random distMin distMax) do
(
LengthSeg = 0
if (random 0 100) <= densCars do
(
--instance new car
GetRandomCar = theMainSelectionCars[random 1 theMainSelectionCars.count]
maxops.clonenodes GetRandomCar cloneType:#instance expandHierarchy:true newNodes:&nnl
new_car = nnl[1]
join TempArraysCarsForDelete nnl
--transform
case rb1_state of
(
1: (
theY = normalize (arrSplineData[arrNum - tM2] - arrSplineData[arrNum - tM1])
theZ = [0,0,1]
theX = cross theY theZ
new_car.transform = matrix3 theY theX theZ (arrSplineData[arrNum] + theY*(random -theSh theSh))
)
2: (
theY = normalize (arrSplineData[arrNum - tM2] - arrSplineData[arrNum - tM1])
theZ = [0,0,1]
theX = cross theY theZ
new_car.transform = matrix3 theX theY theZ (arrSplineData[arrNum] + theX*(random -theSh theSh))
)
)
-- planting to mesh
if theMainMesh != undefined do NormPlanter #(new_car) theMainMesh
)
)
)
fn getOmniByZone_Point mPoint arrOmni =
(
local arrO = arrOmni
local arrDataProc = #()
for o in arrOmni do
(
local theDist = distance mPoint o.pos
local procDist = (theDist - o.nearAttenStart)/(o.nearAttenEnd - o.nearAttenStart)
append arrDataProc procDist
)
local NumOmni = findItem arrDataProc (amin arrDataProc)
return arrO[NumOmni]
)
----END functions
--Interface
rollout CarsBySpline "Cars by Spline"
(
group "Selection:"
(
listbox ListCars "" height:10
button addToListCars "Add cars to list" width:175
listbox ListTraffic "" height:2
button addToListTraffic "Add OMNI as traffic light" width:175
label lbl1 ""
pickbutton chooseShape "Select road spline" width:175 filter:filter_spline
pickbutton chooseMesh "SelectRoadMesh(not necessarily)" width:175 filter:filter_Mesh
)
group "Parameters:"
(
spinner DistCarsMin "DistanceCars-MIN:" range:[501,10000000, 550] type:#integer width:120 align:#right --across:2
spinner DistCarsMax "DistanceCars-MAX:" range:[0,10000000, 4000] type:#integer width:120 align:#right
spinner theShift "Shift:" range:[0,1000, 70] type:#integer width:70 align:#right
spinner densityCars "Density of cars:" range:[0,100, 30] type:#float width:120 align:#right
spinner AccurRead "Step of reading spline:" range:[10,1000, 30] type:#float width:120 align:#right
checkbox DelCars "Delete OLD" checked:true align:#right
label lbl2 "Direction objects by:"
radiobuttons rb1 "" labels:#("X", "Y") default:2 across:2 align:#center
checkbox theFlip "Flip" checked:false align:#center
)
button theGo "Execute" width:175 height:30 align:#left --across:2
on CarsBySpline open do
(
global LengthSeg = 0
global arrTrafficOmni = #()
global arrSplineData = #()
global theMainMesh = undefined
global theMainSelectionCars = #()
global TempArraysCarsForDelete = #()
)
on addToListTraffic pressed do(
arrTrafficOmni = for i in selection where classOf i == Omnilight collect i
local ListName = #()
if arrTrafficOmni.count != 0 then(
for i in arrTrafficOmni do append ListName i.name
ListTraffic.items = ListName
) else ListTraffic.items = #()
)
on addToListCars pressed do(
theMainSelectionCars = for i in selection collect i
local ListName = #()
if theMainSelectionCars.count != 0 then(
for i in theMainSelectionCars do append ListName i.name
ListCars.items = ListName
) else ListCars.items = #()
)
on chooseShape picked main_spl do
(
chooseShape.text = main_spl.name
--reading data of shape
arrSplineData = #()
for numS = 1 to (numSplines main_spl) do
(
progressstart "Reading splines..."
for k =0.0 to 1.0 by (
if AccurRead.value/(getSegLengths main_spl numS)[(getSegLengths main_spl numS).count] < 0.0001 then 0.0001
else AccurRead.value/(getSegLengths main_spl numS)[(getSegLengths main_spl numS).count]
) do (
append arrSplineData (pathInterp main_spl numS k)
progressupdate (k*100.0)
)
progressend ()
) -- END for numS = 1 to (numSplines theMainShape) do
)
on chooseMesh picked obj do (chooseMesh.text = obj.name; theMainMesh = obj)
on theGo pressed do
(
max select none
if DelCars.state do (try(delete TempArraysCarsForDelete)catch();TempArraysCarsForDelete = #())
if arrSplineData.count >= 2 and theMainSelectionCars.count > 0 then
(
if arrTrafficOmni.count > 0 then
(
for i = 2 to arrSplineData.count do
(
--vibor omni po velichine vliyaniya
mainOmni = getOmniByZone_Point arrSplineData[i] arrTrafficOmni
if (distance arrSplineData[i] mainOmni.pos) > mainOmni.nearAttenEnd do instanceCar theFlip.state theShift.value rb1.state DistCarsMin.value DistCarsMax.value densityCars.value i
if (distance arrSplineData[i] mainOmni.pos) < mainOmni.nearAttenStart do instanceCar theFlip.state theShift.value rb1.state 500.0 650.0 100.0 i
if (distance arrSplineData[i] mainOmni.pos) < mainOmni.nearAttenEnd and (distance arrSplineData[i] mainOmni.pos) > mainOmni.nearAttenStart do
(
procDist = ((distance arrSplineData[i] mainOmni.pos) - mainOmni.nearAttenStart)/(mainOmni.nearAttenEnd - mainOmni.nearAttenStart)
theMin = DistCarsMin.value + (DistCarsMin.value - 500)*procDist
theMax = DistCarsMax.value + (DistCarsMax.value - 650)*procDist
theDensity = 100.0 - (100.0 - densityCars.value)*procDist
instanceCar theFlip.state theShift.value rb1.state theMin theMax theDensity i
)
) --END for i = 2 to arrSplineData.count do
)else for i = 2 to arrSplineData.count do instanceCar theFlip.state theShift.value rb1.state DistCarsMin.value DistCarsMax.value densityCars.value i
)else (print "No data")
)-- END on theGo pressed do
) --END rollout
createDialog CarsBySpline width:200
-- Created Alex Yakushev (alexander.yakushev@gmail.com, aly.work@mail.ru)
------------------------------end
- умеет менять плотность машин (с помощью omni lights -> Near Attenuation)
- проецировать машины на дороги со сложным рельефом
- умет работать с прилинкованными объектами к машинам (например люди в салоне и т.п.)
Данный скрипт полезен, когда надо быстро расставить машины по изогнутым, рельефным дорогам.
Пример работы (spline надо сконвертировать в editable spline):
Проецирование на поверхность |
------------------------------start
-- tested in 3DMax 2014
--units: 1 Unit = 1 Centimeters
try destroyDialog CarsBySpline catch()
--global variables
global CarsBySpline
global LengthSeg = 0
global arrTrafficOmni = #()
global arrSplineData = #()
global theMainMesh = undefined
global theMainSelectionCars = #()
global TempArraysCarsForDelete = #()
--functions
fn filter_spline o = superclassof o == shape --filter only shapes
fn filter_Mesh o = superclassof o == GeometryClass --filter only shapes
fn NormPlanter ArrObj theRoad = (
if ArrObj.count >0 and theRoad != undefined and superclassof theRoad == GeometryClass do(
tempMesh = snapshot theRoad
for i in ArrObj do(
theObj = i
theObjT = theObj.transform
theIntRay = intersectRay tempMesh (Ray [theObjT[4].x, theObjT[4].y, theRoad.max.z + 1000] [0,0,-1])
if theIntRay != undefined do(
NaprVecX = theObjT[1]
NaprVecY = theObjT[2]
x0 = theIntRay.pos.x
y0 = theIntRay.pos.y
z0 = theIntRay.pos.z
x1 = theObjT[4][1]
y1 = theObjT[4][2]
z1 = theObjT[4][3]
l = NaprVecX[1]
m = NaprVecX[2]
n = NaprVecX[3]
A1 = y1*n-y0*n-z1*m+z0*m
B1 = -x1*n+x0*n+z1*l-z0*l
C1 = x1*m-x0*m-y1*l+y0*l
A2 = theIntRay.dir[1]
B2 = theIntRay.dir[2]
C2 = theIntRay.dir[3]
--napravlayshiy vector peresecheniya dvuh ploskostey
DirVX = [B1*C2 - B2*C1, C1*A2 - C2*A1, A1*B2 - A2*B1]
DirVX =if (dot DirVX NaprVecX) > 0 then DirVX else -DirVX
nDirVX = normalize DirVX
DirVY = cross nDirVX theIntRay.dir
DirVY = if (dot DirVY NaprVecY) > 0 then DirVY else -DirVY
nDirVY = normalize DirVY
theNewX = nDirVX
theNewY = nDirVY
theNewZ = theIntRay.dir
theNewPos = theIntRay.pos
theObj.transform = (matrix3 theNewX theNewY theNewZ theNewPos)
)--END if theIntRay != undefined do
) -- END for i in ArrObj do
delete tempMesh
) -- END if ArrObj.count >0 and theGround != undefined do
)
fn instanceCar FlipAxis theSh rb1_state distMin distMax densCars arrNum =
(
if FlipAxis then (tM1 = 1; tM2 = 0) else (tM1 = 0; tM2 = 1)
LengthSeg += length(arrSplineData[arrNum] - arrSplineData[arrNum-1])
if LengthSeg >= (random distMin distMax) do
(
LengthSeg = 0
if (random 0 100) <= densCars do
(
--instance new car
GetRandomCar = theMainSelectionCars[random 1 theMainSelectionCars.count]
maxops.clonenodes GetRandomCar cloneType:#instance expandHierarchy:true newNodes:&nnl
new_car = nnl[1]
join TempArraysCarsForDelete nnl
--transform
case rb1_state of
(
1: (
theY = normalize (arrSplineData[arrNum - tM2] - arrSplineData[arrNum - tM1])
theZ = [0,0,1]
theX = cross theY theZ
new_car.transform = matrix3 theY theX theZ (arrSplineData[arrNum] + theY*(random -theSh theSh))
)
2: (
theY = normalize (arrSplineData[arrNum - tM2] - arrSplineData[arrNum - tM1])
theZ = [0,0,1]
theX = cross theY theZ
new_car.transform = matrix3 theX theY theZ (arrSplineData[arrNum] + theX*(random -theSh theSh))
)
)
-- planting to mesh
if theMainMesh != undefined do NormPlanter #(new_car) theMainMesh
)
)
)
fn getOmniByZone_Point mPoint arrOmni =
(
local arrO = arrOmni
local arrDataProc = #()
for o in arrOmni do
(
local theDist = distance mPoint o.pos
local procDist = (theDist - o.nearAttenStart)/(o.nearAttenEnd - o.nearAttenStart)
append arrDataProc procDist
)
local NumOmni = findItem arrDataProc (amin arrDataProc)
return arrO[NumOmni]
)
----END functions
--Interface
rollout CarsBySpline "Cars by Spline"
(
group "Selection:"
(
listbox ListCars "" height:10
button addToListCars "Add cars to list" width:175
listbox ListTraffic "" height:2
button addToListTraffic "Add OMNI as traffic light" width:175
label lbl1 ""
pickbutton chooseShape "Select road spline" width:175 filter:filter_spline
pickbutton chooseMesh "SelectRoadMesh(not necessarily)" width:175 filter:filter_Mesh
)
group "Parameters:"
(
spinner DistCarsMin "DistanceCars-MIN:" range:[501,10000000, 550] type:#integer width:120 align:#right --across:2
spinner DistCarsMax "DistanceCars-MAX:" range:[0,10000000, 4000] type:#integer width:120 align:#right
spinner theShift "Shift:" range:[0,1000, 70] type:#integer width:70 align:#right
spinner densityCars "Density of cars:" range:[0,100, 30] type:#float width:120 align:#right
spinner AccurRead "Step of reading spline:" range:[10,1000, 30] type:#float width:120 align:#right
checkbox DelCars "Delete OLD" checked:true align:#right
label lbl2 "Direction objects by:"
radiobuttons rb1 "" labels:#("X", "Y") default:2 across:2 align:#center
checkbox theFlip "Flip" checked:false align:#center
)
button theGo "Execute" width:175 height:30 align:#left --across:2
on CarsBySpline open do
(
global LengthSeg = 0
global arrTrafficOmni = #()
global arrSplineData = #()
global theMainMesh = undefined
global theMainSelectionCars = #()
global TempArraysCarsForDelete = #()
)
on addToListTraffic pressed do(
arrTrafficOmni = for i in selection where classOf i == Omnilight collect i
local ListName = #()
if arrTrafficOmni.count != 0 then(
for i in arrTrafficOmni do append ListName i.name
ListTraffic.items = ListName
) else ListTraffic.items = #()
)
on addToListCars pressed do(
theMainSelectionCars = for i in selection collect i
local ListName = #()
if theMainSelectionCars.count != 0 then(
for i in theMainSelectionCars do append ListName i.name
ListCars.items = ListName
) else ListCars.items = #()
)
on chooseShape picked main_spl do
(
chooseShape.text = main_spl.name
--reading data of shape
arrSplineData = #()
for numS = 1 to (numSplines main_spl) do
(
progressstart "Reading splines..."
for k =0.0 to 1.0 by (
if AccurRead.value/(getSegLengths main_spl numS)[(getSegLengths main_spl numS).count] < 0.0001 then 0.0001
else AccurRead.value/(getSegLengths main_spl numS)[(getSegLengths main_spl numS).count]
) do (
append arrSplineData (pathInterp main_spl numS k)
progressupdate (k*100.0)
)
progressend ()
) -- END for numS = 1 to (numSplines theMainShape) do
)
on chooseMesh picked obj do (chooseMesh.text = obj.name; theMainMesh = obj)
on theGo pressed do
(
max select none
if DelCars.state do (try(delete TempArraysCarsForDelete)catch();TempArraysCarsForDelete = #())
if arrSplineData.count >= 2 and theMainSelectionCars.count > 0 then
(
if arrTrafficOmni.count > 0 then
(
for i = 2 to arrSplineData.count do
(
--vibor omni po velichine vliyaniya
mainOmni = getOmniByZone_Point arrSplineData[i] arrTrafficOmni
if (distance arrSplineData[i] mainOmni.pos) > mainOmni.nearAttenEnd do instanceCar theFlip.state theShift.value rb1.state DistCarsMin.value DistCarsMax.value densityCars.value i
if (distance arrSplineData[i] mainOmni.pos) < mainOmni.nearAttenStart do instanceCar theFlip.state theShift.value rb1.state 500.0 650.0 100.0 i
if (distance arrSplineData[i] mainOmni.pos) < mainOmni.nearAttenEnd and (distance arrSplineData[i] mainOmni.pos) > mainOmni.nearAttenStart do
(
procDist = ((distance arrSplineData[i] mainOmni.pos) - mainOmni.nearAttenStart)/(mainOmni.nearAttenEnd - mainOmni.nearAttenStart)
theMin = DistCarsMin.value + (DistCarsMin.value - 500)*procDist
theMax = DistCarsMax.value + (DistCarsMax.value - 650)*procDist
theDensity = 100.0 - (100.0 - densityCars.value)*procDist
instanceCar theFlip.state theShift.value rb1.state theMin theMax theDensity i
)
) --END for i = 2 to arrSplineData.count do
)else for i = 2 to arrSplineData.count do instanceCar theFlip.state theShift.value rb1.state DistCarsMin.value DistCarsMax.value densityCars.value i
)else (print "No data")
)-- END on theGo pressed do
) --END rollout
createDialog CarsBySpline width:200
-- Created Alex Yakushev (alexander.yakushev@gmail.com, aly.work@mail.ru)
------------------------------end
Комментариев нет:
Отправить комментарий