Notifications
Clear all

[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

15 Replies
1 Reply
(@bobo)
Joined: 10 months ago

Posts: 0

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…?

Solved

Thanks for the suggestions guys.

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.

Page 1 / 2