Best way to figure out if two objects throw the same shadow!?

Hey all,

sorry for the strange title, but I will explain, what i mean. So I am trying to find a elegant solution to the following scenario:

  1. I have a GameObject1 in my scene, which throws a shadow onto a near plane resulting in a neat “silhouette”
  2. I have a second GameObject2 in the scene, which the user has to rotate so that the “silhouette” of GO2 matches the one of GO1

I tried comparing their rotations in euler angles, what works, but only to a certain extent. I will explain why:
-Imagine GO1 is a cube with 1,1,0.1f in scale and its rotation = Vector3.zero

  • if GO2s rotation would be Vector3.zero aswell we can assume they throw the same shadow
    BUT: that would as well be the case if GO2s rotation vector would be (0,180,0) or (0, 0 , 90) or (180,0,0) etc.

So does anyone know, if there is a clean way to cover all that cases, when GO2s rotation vector does not match GO1s, but they still throw the same shadow?

Any help is highly appreciated, thanks in advance!

So first thing, Euler angles are terrible and you’d have been better off trying Quaternion.Angle. But, this doesn’t really solve the issue, just remember for the future that Euler angles are terrible.

So, for the actual issue, the only thing I can imagine possibly working would be raycasts. Like a lot of raycasts. Imagine a grid of tiles (A) on the floor, and each tile shoots a ray upward. Now create an identical floor of tiles (B) next to the second object, and cast a bunch of rays up from there. Loop through each one, and if A’s raycast for (6,4) hits and B’s raycast for (6,4) doesn’t, you know their shadows aren’t identical.

It’s hard to know how many raycasts you’ll need, but it’ll be a lot. For a generically useful script, probably at least 20x20.

If you’re doing hundreds and hundreds of raycasts, you’ve got to use multithreading or everything will slow to a crawl. Check out this for a code example.

Hey StarManta,
Thank you very much for the detailed answer. As I am developing for mobile only, I guess this solution is too performance heavy to work there?

I don’t think so. It strengthens the need to make it multithreaded, and you might have to be more selective about how often you check for alignment (e.g. maybe every half-second rather than attempting to check every frame), or more careful about how many rays you use, but phones are surprisingly powerful.

Hm what if I would surround every object with an invisible cage out of a cube so I can define one clear “forward” for every object. Now I cast a ray from the middle of the forward facing side , do the same from the other object and compare the angle between those two lines??

if all the objects are going to have the same shape, size, and position, then that would work… to an extent. Just comparing the silhouette between two cubes there are 24 unique rotations cube B can take to match with just one side of Cube A, scaling upto infinite rotations if both objects being compared are spheres.

Is position relevant? Is scale? are the two objects always the same shape? Is the comparison of shadows meant to be orthographic or perspective?

Exactly what do you need this for? Depending on how you want to be using this feature you can take shortcuts to calculating the comparison. And this can really save on performance and even improve player interaction (if it was,say, a shadow puzzle) by making the calculation more forgiving.

1 Like

Calculating such a thing can get complicated. Performance, accuracy (including false positives), and more.

As JoshuaMcKenzi brings up, you may be able to just simplify this depending on the conditions of YOUR game.

Like if the object being rotated by the player that they need to get to match… if it’s a known quantity, as in you as the developer are aware of exactly what the object is that they’re rotating, you should be able to simplify this a lot. Case in point:

Known state:
Player enters a dungeon room, there is a statue at one end and a sunbeam coming through a crack in the roof casts a shadown on the ground. There is another similar sunbeam on the other end of the room and 3 statues you can slide into place in that sunbeam and rotated.

This is a known state because you know precisely what statues exist, where the sunbeams are and angled, etc. You as the developer can just go into the game figure out where the correct statue needs to be placed and what angle it needs to have, store that information, then just test that. No fuss, no muss. “Statue B at position X and rotation Y”

Unknown state:
Player is given the ability to stack random objects to make a shape. This shape casts a shadow and they need to stack several generic objects until it makes the shadow we expect.

This is an unknown state since the player should be able to stack a variable amount of objects. The number of combinations they could stack is pretty much infinite. And more than 1 state can be considered valid. In this case we have to actually calculate the shadow and compare because there’s really know way to store all possible success states.

Hey all,
thanks for all that replies!
Ok so let me explain more what I am after here :slight_smile:
Yes this will be a shadow puzzle game.

  1. Position will be preset → it will not matter!
  2. Yes, the objects will always have the same scale. That is because I fake the shadow by using real GameObjects with unlit shaders. So for example if you start a round you will see a plane with let´s say a square shaped shadow/unlit GameObject on it on the left hand side of the screen. On the right hand side you have for example a mobile phone…or anything square shaped, throwing its “shadow” next to the other on the wall. Now you have to rotate the phone so that your shadow matches the other.
  3. So yes, there must be a considerable amount of “forgivingness” to that whole concept. Else its just unplayable.
  4. I have experimented with an perspective camera at the moment, but if you tell me, that things would be more easy with an orthographic one, I definitely could make it work :slight_smile:

Then all you really need to compare is two rotations. Perform a Quaternion.Dot() between the puzzle’s quaternion, and the correct quaternion. This will return a float in the range of -1 to +1. -1 means that the two rotations are exactly opposite while +1 means the rotations are exactly the same. So simply check that the dot product result is greater than a threshold to give that desired wiggle room (like 0.97 which gives decent freedom, for reference 45 degrees of freedom is ~0.7, AKA, sin(45)).

Performance friendly and easy to implement!

I already thought about that. But this does not account for the “special cases” where GO1 throws the same shadow but is not rotated the same way GO2 is.
Example:
Rectangular shadow on the wall (= GO2)
A square Cellphone/Tablet (=GO1)

Now GO1 will throw the same shadow either its facing towards the camera or for example flipped around 180° on the y axis:

If GO1.rotation == GO2.rotation → same shadow → Quaternion.Dot(GO1.r , GO2.r) = 1
If GO1.rotation = (0,180,0) → same shadow → Quaternion.Dot(GO1.r , GO2.r) = 0
If GO1.rotation = (0,0,90) → same shadow → Quaternion.Dot(GO1.r , GO2.r) = 0.7
etc

The object will still have a finite number of orientations (and since position is static this keeps it rather low). Maybe 4, 6, but never a ton.

Just figure out what those orientations, stick em’ in a collection, and loop over them when you test. If it succeeds one of them, they’ve won.

Hey hey,

yes I guess its a lot of “manual” work, but this would be the best solution! Thanks!

What you could also do is write a ‘slow/naive’ program that ran an object through all its orientations and ran raycast tests to get all the answers. Frontloading all the work in your dev pipeline and outputting the results to a lookup table of some sort.

This way even if your algorithm is slow, it doesn’t matter. You’re running it at dev time, not the user running it in game on their phone.

2 Likes

That is actually a really sweet approach! I will try it! Thanks!