home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Maximum 3D 3
/
m3d-p3.iso
/
3DS_MAX
/
3DSMAX.2_0
/
SCRIPTS
/
PRTLGHTS.MS
< prev
next >
Wrap
Text File
|
1997-10-19
|
18KB
|
479 lines
-- light_particle.ms
-- John Wainwright
--
-- A scripted utility that lets you attach omni-lights to
-- the particles of a selected particle system and animate
-- a brightness decay and color ramp over the particle life.
--
utility light_particle "Light Particles"
(
local system, master, particles, pcount,
start_times, end_times, noise_ctrlrs,
start_tangent, end_tangent,
start = animationRange.start.frame,
end = animationRange.end.frame, last_age
local lpp -- rollout & fn forwards
rollout aboutbox "About Light Particles"
(
label lp1 "Light Particle System"
label lp3 "John Wainwright and"
label lp4 "Marcus Morgan"
)
group "Particle System"
(
label pps "Pick master particle system:" align:#left
pickbutton pick_system "none" width:90
)
-- particle creation panel - choose frame range and % coverage
-- of particle, create btn turns to recreate after initial creation
-- must recreate particles to change coverage or accomodate psys changes
group "Particle Creation"
(
spinner start_frame "Start frame:" type:#integer range:[start, end, start]
spinner end_frame "End frame:" type:#integer range:[start, end, end]
spinner make_percent "Particle coverage %:" fieldwidth:35 type:#integer range:[0,100,10]
button create_parts "Create Light Particles" offset:[0,5] enabled:false width:127
label status
button delete_parts "Delete Particles" enabled:false
)
fn next_index cur_psi =
(
-- computes next selected particle system index based on coverage %
if make_percent.value == 100 then cur_psi + 1
else if make_percent.value > 50 then
(
-- > 50%, skip every nth
local skip = ceil (particleCount system / (particleCount system * (100.0 - make_percent.value) / 100))
if mod (cur_psi - 1) skip == 0 then cur_psi + 2 else cur_psi + 1
)
else
-- <= 50%, pick every nth
cur_psi + (100 / make_percent.value) as integer
)
-- get base keyable light multiplier controller depending on noise presence
fn get_mult_controller light =
if lpp.add_noise.checked
then light.multiplier.controller.bezier_float.controller
else light.multiplier.controller
-- compute controller keyframe values at start & end frames to
-- ensure correct decay curve and disable lights outside of active
-- frame range
fn add_interpolated_end_frames light =
(
local mc = get_mult_controller light,
cc = light.color.controller,
last_key, new_key, endf_key
-- interpolate multiplier, place keys at start & end frames
last_key = getKey mc (numkeys mc)
new_key = addNewKey mc (last_key.time + system.life)
new_key.value = lpp.end_mult.value
new_key.intangenttype = end_tangent
endf_key = addNewKey mc end_frame.value #interpolate
endf_key.intangenttype = end_tangent
endf_key.outtangenttype = #linear
sortkeys mc
last_key = getKey mc (numkeys mc)
last_key.value = 0
last_key.time = endf_key.time + 1
last_key.intangenttype = #linear
-- interpolate color, place keys at start & end frame
last_key = getKey cc (numkeys cc)
at time (last_key.time + system.life) animate on light.color = lpp.end_color.color
sortkeys cc
new_key = getKey cc (numKeys cc)
new_key.intangenttype = end_tangent
endf_key = addNewKey cc end_frame.value #interpolate
endf_key.intangenttype = end_tangent
endf_key.outtangenttype = #linear
sortkeys cc
last_key = getKey cc (numkeys cc)
last_key.time = endf_key.time + 1
last_key.intangenttype = #linear
)
on pick_system picked obj do
(
-- master particle system picked, remember it in a local
-- and stick name in picker button label
system = obj; pick_system.text = obj.name
create_parts.enabled = true
)
on create_parts pressed do
(
-- create lights to cover chosen % of particles, store them in an array
start_tangent = if lpp.ldecay.checked then #linear else if lpp.sdecay.checked then #slow else #fast
end_tangent = if lpp.ldecay.checked then #linear else if lpp.sdecay.checked then #fast else #slow
-- delete any existing light particles & loop over creation
delete particles
start_times = #(); end_times = #(); noise_ctrlrs = #()
pcount = particleCount system * make_percent.value / 100
particles = for i in 1 to pcount collect
(
local light = omnilight name:"plight" \
contrast:lpp.contrast.value \
farattenstart:lpp.far_start.value \
farattenend:lpp.far_end.value \
nearattenstart:lpp.near_start.value \
nearattenend:lpp.near_end.value \
usenearatten:lpp.use_near.checked \
shownearatten:lpp.show_near.checked \
usefaratten:lpp.use_far.checked \
showfaratten:lpp.show_far.checked \
castshadows:lpp.cast_shad.checked \
useglobalshadowsettings:lpp.use_global.checked \
absolutemapbias:lpp.abs_bias.checked \
mapbias:lpp.map_bias.value \
mapsize:lpp.map_size.value \
samplerange:lpp.map_smprange.value \
raytracebias:lpp.ray_bias.value \
multiplier: 0 \
pos:system.pos
-- ensure we have color & multiplier controllers with a start-frame key
if light.color.controller == undefined then
light.color.controller = bezier_color()
addNewKey light.color.controller start_frame.value
if light.multiplier.controller == undefined then
light.multiplier.controller = bezier_float()
addNewKey light.multiplier.controller start_frame.value
-- build & optionally add noise controller to multiplier
local n = noise_float frequency:lpp.noiz_freq.value
(addNewKey n.noise_strength.controller start_frame.value).value = 0
(addNewKey n.noise_strength.controller end_frame.value).value = 0
noise_ctrlrs[i] = n
if lpp.add_noise.checked then
(
local fl = float_list ()
fl.available.controller = bezier_float ()
fl.available.controller = n
light.multiplier.controller = fl
)
-- init life start & end time arrays
start_times[i] = #(); end_times[i] = #()
light
)
-- animate particles
animate on for t in start_frame.value to end_frame.value do at time t
(
status.text = "Processing frame " + (t as string)
local psi = 1 -- particle system particle index
for i in 1 to pcount do
(
-- grab host system particle
local pos = particlePos system psi,
age = particleAge system psi,
light = particles[i]
-- check for birth/rebirth or dying transitions and plant
-- color & multiplier keys
if last_age[i] != undefined and
(age == undefined or age < last_age[i]) then at time (t-1)
(
-- death, plant end color, multiplier, noise keys
light.color = lpp.end_color.color
light.multiplier = lpp.end_mult.value
-- condition tangent types from decay choice
local mc = get_mult_controller light,
cc = light.color.controller,
ck = getkey cc (getkeyindex cc currentTime),
mk = getkey mc (getkeyindex mc currentTime)
ck.intangenttype = mk.intangenttype = end_tangent
ck.outtangenttype = mk.outtangenttype = #linear
-- add noise key & set tangents
local nk = addNewKey noise_ctrlrs[i].noise_strength.controller currentTime
nk.value = 0
nk.intangenttype = nk.outtangenttype = #step
append end_times[i] currentTime
)
if age != undefined and
(last_age[i] == undefined or age < last_age[i]) then
(
-- birth or rebirth, plant start color, multiplier, noise keys
light.color = lpp.start_color.color
light.multiplier = lpp.start_mult.value
-- condition tangent types from decay choice
local mc = get_mult_controller light,
cc = light.color.controller,
ck = getkey cc (getkeyindex cc currentTime),
mk = getkey mc (getkeyindex mc currentTime)
ck.intangenttype = mk.intangenttype = #linear
ck.outtangenttype = mk.outtangenttype = start_tangent
-- add noise key & set tangents
local nk = addNewKey noise_ctrlrs[i].noise_strength.controller currentTime
nk.value = lpp.noiz_strength.value * lpp.start_mult.value / 100
nk.intangenttype = nk.outtangenttype = #step
append start_times[i] currentTime
)
-- if midlife plant pos key; dead disable light
if pos != undefined then
(
light.pos = pos
)
else
(
light.pos = system.pos
light.multiplier = 0
light.color = color 0 0 0
)
-- record age and bump to next selected source system particle
last_age[i] = age
psi = next_index psi
)
)
-- add interpolated keyframes at end frame for still-alive particles
for i in 1 to pcount where last_age[i] != undefined do
add_interpolated_end_frames particles[i]
-- change create button to recreate button
delete_parts.enabled = true
create_parts.text = "Recreate Light Particles"
)
on delete_parts pressed do
(
delete particles
particles = #(); pcount = 0
create_parts.text = "Create Light Particles"
)
-- particle light parameter controls
rollout lpp "Light Particle Parameters"
(
-- brightness ramp controls
group "Multiplier"
(
spinner start_mult "Start multiplier:" range:[0, 100, 1] fieldwidth:40 align:#center
spinner end_mult "End multiplier:" range:[0, 100, 0] fieldwidth:40 align:#center
label mdl "Multiplier decay:" align:#left
checkbutton ldecay images:#("btn3.bmp", "btn3m.bmp", 6, 1, 4, 1, 4) width:40 align:#left offset:[8,0] checked:true
checkbutton fdecay images:#("btn3.bmp", "btn3m.bmp", 6, 2, 5, 2, 5) width:40 align:#center offset:[4,-35]
checkbutton sdecay images:#("btn3.bmp", "btn3m.bmp", 6, 3, 6, 3, 6) width:40 align:#right offset:[0,-35]
checkbox add_noise "Add noise"
spinner noiz_strength "Noise strength %:" type:#integer fieldwidth:40 range:[0, 200, 50] align:#right enabled:false
spinner noiz_freq "Noise frequency:" fieldwidth:40 range:[0, 10, 0.5] align:#right enabled:false
spinner contrast "Contrast:" fieldwidth:40 align:#center offset:[0,4]
)
-- color ramp controls
group "Color"
(
label cpl "Start color: End color:"
colorpicker start_color across:2 color:(color 255 255 255) offset:[-20,0]
colorpicker end_color color:(color 255 100 9) offset:[-20,0]
)
-- rest of standard life controls - these are not rampable by this tool
group "Attenuation"
(
label al1 "Near Far"
spinner near_start "Start:" fieldwidth:47 across:2 offset:[10,0] range:[0,10000,0]
spinner far_start fieldwidth:47 offset:[3,0] range:[0,10000,80]
spinner near_end "End:" fieldwidth:47 across:2 offset:[10,0] range:[0,10000,40]
spinner far_end fieldwidth:47 offset:[3,0] range:[0,10000,200]
checkbox use_near "Use" across:2 offset:[27,0]
checkbox use_far "Use" offset:[22,0]
checkbox show_near "Show" across:2 offset:[27,0]
checkbox show_far "Show" offset:[22,0]
label adl "Decay:" align:#left offset:[0,20]
radiobuttons atten_decay labels:#("None", "Inverse", "Inverse Square") align:#middle offset:[20,-35]
)
group "Shadow"
(
checkbox cast_shad "Cast Shadows"
checkbox use_global "Use Global Settings"
radiobuttons map_ray labels:#("Use Shadow Maps", "Use Ray-traced Shadows") offset:[3,0]
label mbl "Map Bias Size Smp Range"
spinner map_bias fieldwidth:33 across:3 range:[0,200,4]
spinner map_size fieldwidth:35 type:#integer range:[0,5000,256] offset:[1,0]
spinner map_smprange fieldwidth:33 range:[0,20,4]
checkbox abs_bias "Absolute Map Bias" offset:[1,0] checked:true
spinner ray_bias "Ray Trace Bias:" fieldwidth:30 align:#center range:[0,20,0.2]
)
fn get_mult_controller light =
if add_noise.checked
then light.multiplier.controller.bezier_float.controller
else light.multiplier.controller
-- if ramps changes, recompute interpolated start & end keyframes
fn recompute_end_frame_keys i =
if end_times[i].count > 0 and end_times[i][end_times[i].count] != end_frame.value then
(
-- last end time didn't land on end_frame, so we do have interp'd keys
local light = particles[i],
mc = get_mult_controller light,
cc = light.color.controller
-- delete last two keys in mc & cc, recreate interp'd end keys
deleteKey mc (numkeys mc); deleteKey mc (numkeys mc)
deleteKey cc (numkeys cc); deleteKey cc (numkeys cc)
add_interpolated_end_frames light
)
-- ramp control change handlers
on start_color changed val do
animate on for i in 1 to particles.count do
(
for t in start_times[i] do at time t particles[i].color = val
recompute_end_frame_keys i
)
on end_color changed val do
animate on for i in 1 to particles.count do
(
for t in end_times[i] do at time t particles[i].color = val
recompute_end_frame_keys i
)
on start_mult changed val do
animate on for i in 1 to particles.count do
(
for t in start_times[i] do at time t particles[i].multiplier = val
recompute_end_frame_keys i
)
on end_mult changed val do
animate on for i in 1 to particles.count do
(
for t in end_times[i] do at time t particles[i].multiplier = val
recompute_end_frame_keys i
)
fn set_decay_tan_types =
for i in 1 to particles.count do
(
-- for each light, change the tangent types to create selected ramp
local light = particles[i],
mc = get_mult_controller light,
cc = light.color.controller
for t in start_times[i] do
(getkey cc (getkeyindex cc t)).outtangenttype =
(getkey mc (getkeyindex mc t)).outtangenttype = start_tangent
for t in end_times[i] do
(getkey cc (getkeyindex cc t)).intangenttype =
(getkey mc (getkeyindex mc t)).intangenttype = end_tangent
-- delete & recompute end frame interpolated keys
recompute_end_frame_keys i
)
on ldecay changed state do
(
ldecay.checked = true; fdecay.checked = sdecay.checked = false
start_tangent = end_tangent = #linear
set_decay_tan_types ()
)
on fdecay changed state do
(
fdecay.checked = true; ldecay.checked = sdecay.checked = false
start_tangent = #fast; end_tangent = #slow
set_decay_tan_types ()
)
on sdecay changed state do
(
sdecay.checked = true; fdecay.checked = ldecay.checked = false
start_tangent = #slow; end_tangent = #fast
set_decay_tan_types ()
)
on add_noise changed state do
(
noiz_strength.enabled = noiz_freq.enabled = state
-- add or delete noise controllers in existing lights
for i in 1 to particles.count do
(
local light = particles[i]
if add_noise.checked then
(
local fl = float_list ()
fl.available.controller = light.multiplier.controller
fl.available.controller = noise_ctrlrs[i]
light.multiplier.controller = fl
)
else
light.multiplier.controller = light.multiplier.controller.bezier_float.controller
)
)
on noiz_strength changed val do
for i in 1 to particles.count do
animate on for t in start_times[i] do at time t
noise_ctrlrs[i].noise_strength = val * start_mult.value / 100
on noiz_freq changed val do
for i in 1 to particles.count do
noise_ctrlrs[i].frequency = val
on contrast changed val do particles.contrast = val
on near_start changed val do
(
if val > near_end.value then particles.nearAttenEnd = near_end.value = val
if val > far_start.value then particles.farAttenStart = far_start.value = val
if val > far_end.value then particles.farAttenEnd = far_end.value = val
particles.nearAttenStart = val
)
on far_start changed val do
(
if val < near_end.value then particles.nearAttenEnd = near_end.value = val
if val < near_start.value then particles.nearAttenStart = near_start.value = val
if val > far_end.value then particles.farAttenEnd = far_end.value = val
particles.farAttenStart = val
)
on near_end changed val do
(
if val < near_start.value then particles.nearAttenStart = near_start.value = val
if val > far_start.value then particles.farAttenStart = far_start.value = val
if val > far_end.value then particles.farAttenEnd = far_end.value = val
particles.nearAttenEnd = val
)
on far_end changed val do
(
if val < near_end.value then particles.nearAttenEnd = near_end.value = val
if val < near_start.value then particles.nearAttenStart = near_start.value = val
if val < far_start.value then particles.farAttenStart = far_start.value = val
particles.farAttenEnd = val
)
on show_near changed state do particles.showNearAtten = state
on show_far changed state do particles.showFarAtten = state
on use_near changed state do particles.useNearAtten = state
on use_far changed state do particles.useFarAtten = state
on cast_shad changed state do particles.castShadows = state
on use_global changed state do particles.useglobalshadowsettings = state
on map_bias changed val do particles.mapbias = val
on map_size changed val do particles.mapsize = val
on map_smprange changed val do particles.samplerange = val
on abs_bias changed state do particles.absolutemapbias = state
on ray_bias changed val do particles.raytracebias = val
)
on light_particle open do
(
particles = #(); last_age = #(); pcount = 0
addRollout lpp rolledUp:true
addRollout aboutbox rolledUp:true
)
on light_particle close do
(
removeRollout lpp
removeRollout aboutbox
)
)
--openUtility light_particle