[Closed] How to tell if an object is casting a shadow on another
Hey everyone,
I was curious to know if anyone knew of a way to check if an object in a scene is casting an object on another object via maxscript or the API. I’ve though of a work-around using a shadow render element, but was curious if anyone had a better solution as the one I’m thinking of is quite a bit of work.
Thanks,
Colin
Depending on how precise you want it, you could start shooting rays from the light through the vertices of object A and see if the ray hits object B. The first ray that hits the object is proof enough that A casts a shadow on B.
You can use the RayGridIntersect functions since you want it to be fast and you don’t really care where the hit was, as long as there was one (getting the actual hit’s data is a bit more complicated with this method than with the regular intersectRay and intersectRayEx functions, but the intersecting itself can be performed much faster).
If I missed the point, please explain why you want to do that.
Thanks Bobo, this is much faster than what I was intending and should work very well.
I was about to render a separate shadow element pass and compare the pixel data from that to the viewport, which would take significantly longer.
I’ll look into this in depth and will post back if I have any questions, thanks again.
Bobo,
Where can I find the information for shooting rays through a light? How do I calculate where they originate from and how many will be shot? Is there a .tm property or something I can start at? What if I wanted to shoot them through a camera? A simple answer will suffice
Many thanks as always,
Colin
Cant you do something like the shadow mapping algorithm? Render from the light position (you may need more than one render, for example six to cover the whole field of view of a point light) then if the object has any pixel in the rendered image it means it is not completely occluded, then it is not 100% in shadow.
Yes Xissburg that is possible, but the RayGridIntersect functions would be much faster.
I gave it a good shot yesterday and got some really good progress.
I shot a ray from the camera through an object and tested for intersection with another object and did it successfully. As far as any of you know will I run into Camera FOV problems or anything? Just curious.
Shoot from the camera? I thought you want to shoot from a lightsource…?
How?
Where can I find the information for shooting rays through a light?
Try intersectRay
Hi Colin,
I’m glad you solved the problem. Since I’ve been playing with this, I hope you don’t mind if I post my solution. It follows what Bobo said, cast rays from each vertex of source object taking into account the light source and its quality. To use it, you must select a light, then in order the object that casts shadows, then every target object to test. Run the script and get the results in a messageBox. If you need higher accuracy, can add a temporary Tassellate modifier on the shadow casting object.
The code is not super polished and optimized, but does the job.
macroscript ShadowCastChecker
Category:"ShadowCastChecker"
(
local rmgi = RayMeshGridIntersect()
function initRMGI theNode =
(
rmgi.initialize 10
rmgi.free()
rmgi.addNode theNode
rmgi.buildGrid()
)
local getV = meshOp.getVert
on execute do
(
local theSelection = selection as Array
local theLight = undefined
local theSource = undefined
local aoTargets = #()
if (theSelection.count >= 3) do
(
for theNode in theSelection do
(
if ((superClassOf theNode) == Light) then
(
theLight = theNode
)
else if (superClassOf theNode == GeometryClass) then
(
if (theSource == undefined) then
theSource = theNode
else
append aoTargets theNode
)
)
local p3VertPos = [0,0,0]
local p3LightDir = [0,0,0]
local iHitCount = 0
local aoShadowTargets = #()
if ( ((classOf theLight) == TargetSpot) or ((classOf theLight) == FreeSpot) or
((classOf theLight) == OmniLight) or
((classOf theLight) == miAreaLightOmni) or ((classOf theLight) == miAreaLight) or
((classOf theLight) == Target_Light) or ((classOf theLight) == Free_Light) ) then
(
local iNumVerts = meshOp.getNumVerts theSource.mesh
for oTarget in aoTargets do
(
initRMGI oTarget
for iVert = 1 to iNumVerts do
(
p3VertPos = getV theSource.mesh iVert node:theSource
p3LightDir = normalize (p3VertPos - theLight.pos)
iHitCount = rmgi.intersectRay p3VertPos p3LightDir true
if (iHitCount > 0) do
(
append aoShadowTargets oTarget
exit
)
)
)
)
else if ( ((classOf theLight) == TargetDirectionalLight) or ((classOf theLight) == DirectionalLight) ) then
(
local iNumVerts = meshOp.getNumVerts theSource.mesh
for oTarget in aoTargets do
(
initRMGI oTarget
for iVert = 1 to iNumVerts do
(
p3VertPos = getV theSource.mesh iVert node:theSource
p3LightDir = -theLight.dir
iHitCount = rmgi.intersectRay p3VertPos p3LightDir true
if (iHitCount > 0) do
(
append aoShadowTargets oTarget
exit
)
)
)
)
local ssMessage = stringStream ""
if (aoShadowTargets.count != 0) then
(
format "Light: %
" theLight.name to:ssMessage
format "Object: %
" theSource.name to:ssMessage
format "Object(s) in % shadow
" theSource.name to:ssMessage
for theNode in aoShadowTargets do
format "- %
" theNode.name to:ssMessage
)
else
(
format "Light: %
" theLight.name to:ssMessage
format "Object: %
" theSource.name to:ssMessage
format "No objects are in % shadow
" theSource.name to:ssMessage
)
messageBox (ssMessage as String) title:"Shadow Cast Checker"
)
)
)
- Enrico
the casting rays from a light source through the vertices doesn’t solve all situations. How to solve the situation when a small object just behind a big cube?
I would stay with a shadow render element… It’s slower in most cases but can guarantee the result.