RayCast returns zero normal

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
demiurghg
Posts: 14
Joined: Mon Jun 04, 2012 10:02 am

RayCast returns zero normal

Post by demiurghg »

Hello,

I'm trying to implement plasma-like projectile.
On each frame I perform RayCast against entire physical geometry
with quite small maximunLength set to V * dt (maximunLength ~=0.3), where V is a velocity of projectile and dt is elapaseGameTime in seconds.

In majority of cases RayCast returns zero HitNormal.

On the other hand, I implemented bullet-like projectiles with the same method (but maximumLength is about 10000) and there is no problems.

What is the root of the problem and how to solve it?

Thanks for advance.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: RayCast returns zero normal

Post by Norbo »

If the ray does not impact something, the data in the ray hit is not valid. The ray hit is only valid if the RayCast method returns true. Are you seeing zeroed-out normals when the ray cast returns true?
demiurghg
Posts: 14
Joined: Mon Jun 04, 2012 10:02 am

Re: RayCast returns zero normal

Post by demiurghg »

If the ray does not impact something, the data in the ray hit is not valid. The ray hit is only valid if the RayCast method returns true. Are you seeing zeroed-out normals when the ray cast returns true?
Yes. But only when ray hits the Capsule, that represents a character.
Increasing maximumLength decreases probablity of getting wrong results.
RayCast against dynamic boxes or static geometry always returns valid results.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: RayCast returns zero normal

Post by Norbo »

If the ray cast's origin starts within an object, there is no valid normal. Could the ray be starting inside the character? If the T value is 0, the ray origin was contained.

Assuming the ray casting is stopped upon first intersection, this is only likely to happen if the character is moving. Since the ray does not take into account the swept motion of objects, the discrete update could result in the ray's origin being inside the moving object in the subsequent frame.
Increasing maximumLength decreases probablity of getting wrong results.
Increasing maximum length makes this less likely since the character would have to get 'lucky.'
RayCast against dynamic boxes or static geometry always returns valid results.
The normal associated with a ray hit which is inside an object (T == 0) is treated as 'undefined,' so different types handle it in different ways. Types without ray test special cases default to the GJK implementation, which, if I remember correctly, ends up zeroing out an internal hit. A box test, on the other hand, works through the normals and keeps track of the 'best' one; if the ray turns out to be inside, a value will still be assigned to the normal just because the method doesn't bother zeroing it out.

Static geometry avoids the issue by simply not moving.


As a workaround, you could choose to use the direction of the ray's travel and get a decent result when T == 0.

A more 'proper' option is to treat the ray as a moving particle and perform a swept test based on the relative 'velocities' of the candidate object and the projectile. In other words, modify the ray direction based upon the candidate entity's velocity. Candidate entities are found by using a Space.BroadPhase.QueryAccelerator query, just like the Space.RayCast does internally, and the candidates are checked individually for intersection. Check the Space.RayCast method for an example of using the query accelerator.
demiurghg
Posts: 14
Joined: Mon Jun 04, 2012 10:02 am

Re: RayCast returns zero normal

Post by demiurghg »

The characters (and all other objects) are motionless.

I recorded ray tracing log today.
On each frame projectile performs RayCast with big maximumLength from current position and puts ray origin, hit point, hit normal and T to the log.
Then it performs another RayCast to check whether projectile hit the target.
When projectile hit the target it puts the RayCast results to the log.

Code: Select all

POS:{X:14.57293 Y:0.9985374 Z:8.21363} -> HIT:{X:6.131171 Y:0.8214552 Z:10.26982} {X:0.7264069 Y:0.3481773 Z:-0.5925416} 8.690373
POS:{X:14.24913 Y:0.9917451 Z:8.292499} -> HIT:{X:6.130264 Y:0.8214362 Z:10.27004} {X:0.7415081 Y:0.3003791 Z:-0.5999484} 8.357972
POS:{X:13.92534 Y:0.9849527 Z:8.371367} -> HIT:{X:6.130418 Y:0.8214394 Z:10.27} {X:0.7404518 Y:0.320574 Z:-0.5907312} 8.024481
POS:{X:13.60154 Y:0.9781604 Z:8.450236} -> HIT:{X:6.130349 Y:0.821438 Z:10.27002} {X:0.7351687 Y:0.2928281 Z:-0.6113745} 7.691217
POS:{X:13.27774 Y:0.9713681 Z:8.529105} -> HIT:{X:6.131061 Y:0.8214529 Z:10.26984} {X:0.7093821 Y:0.307808 Z:-0.6340595} 7.35715
POS:{X:12.95394 Y:0.9645758 Z:8.607974} -> HIT:{X:6.131118 Y:0.821454 Z:10.26983} {X:0.7322962 Y:0.2667221 Z:-0.6265793} 7.023757
POS:{X:12.63014 Y:0.9577835 Z:8.686843} -> HIT:{X:6.130594 Y:0.821443 Z:10.26996} {X:0.7347447 Y:0.3307567 Z:-0.5922415} 6.690963
POS:{X:12.30634 Y:0.9509912 Z:8.765712} -> HIT:{X:6.130689 Y:0.821445 Z:10.26993} {X:0.7312253 Y:0.3346756 Z:-0.5943921} 6.35753
POS:{X:11.98255 Y:0.9441989 Z:8.844581} -> HIT:{X:6.131165 Y:0.821455 Z:10.26982} {X:0.7292079 Y:0.3478538 Z:-0.5892822} 6.023707
POS:{X:11.65875 Y:0.9374066 Z:8.92345} -> HIT:{X:6.130768 Y:0.8214467 Z:10.26992} {X:0.7228003 Y:0.287709 Z:-0.6283177} 5.690781
POS:{X:11.33495 Y:0.9306143 Z:9.002318} -> HIT:{X:6.130659 Y:0.8214443 Z:10.26994} {X:0.7302598 Y:0.3335974 Z:-0.5961824} 5.357559
POS:{X:11.01115 Y:0.923822 Z:9.081187} -> HIT:{X:6.130838 Y:0.8214481 Z:10.2699} {X:0.7626828 Y:0.2853604 Z:-0.5804175} 5.024041
POS:{X:10.68735 Y:0.9170297 Z:9.160056} -> HIT:{X:6.13068 Y:0.8214447 Z:10.26994} {X:0.7590504 Y:0.287632 Z:-0.5840465} 4.69087
POS:{X:10.36356 Y:0.9102374 Z:9.238925} -> HIT:{X:6.130532 Y:0.8214417 Z:10.26998} {X:0.7549285 Y:0.2900918 Z:-0.5881579} 4.357687
POS:{X:10.03976 Y:0.9034451 Z:9.317794} -> HIT:{X:6.130404 Y:0.8214389 Z:10.27001} {X:0.750215 Y:0.2927483 Z:-0.5928541} 4.024486
POS:{X:9.71596 Y:0.8966528 Z:9.396663} -> HIT:{X:6.13031 Y:0.8214369 Z:10.27003} {X:0.7447785 Y:0.2956013 Z:-0.598268} 3.691248
POS:{X:9.392161 Y:0.8898605 Z:9.475532} -> HIT:{X:6.130271 Y:0.821436 Z:10.27004} {X:0.7384498 Y:0.2986291 Z:-0.6045764} 3.357953
POS:{X:9.068363 Y:0.8830681 Z:9.5544} -> HIT:{X:6.130323 Y:0.8214371 Z:10.27003} {X:0.7310049 Y:0.3017723 Z:-0.6120175} 3.024566
POS:{X:8.744565 Y:0.8762758 Z:9.633269} -> HIT:{X:6.13052 Y:0.8214413 Z:10.26998} {X:0.7221525 Y:0.3048864 Z:-0.6209186} 2.691029
POS:{X:8.420767 Y:0.8694835 Z:9.712138} -> HIT:{X:6.130348 Y:0.8214376 Z:10.27002} {X:0.7350982 Y:0.3183351 Z:-0.5985761} 2.357872
POS:{X:8.096969 Y:0.8626912 Z:9.791007} -> HIT:{X:6.130292 Y:0.8214364 Z:10.27004} {X:0.7345138 Y:0.2995123 Z:-0.6089187} 2.024595
POS:{X:7.77317 Y:0.8558989 Z:9.869876} -> HIT:{X:6.130262 Y:0.8214358 Z:10.27004} {X:0.73651 Y:0.3077083 Z:-0.6023858} 1.691292
POS:{X:7.449372 Y:0.8491066 Z:9.948745} -> HIT:{X:6.130259 Y:0.8214357 Z:10.27005} {X:0.7369954 Y:0.30608 Z:-0.6026215} 1.357962
POS:{X:7.125574 Y:0.8423143 Z:10.02761} -> HIT:{X:6.130355 Y:0.8214377 Z:10.27002} {X:0.7411771 Y:0.2897199 Z:-0.6055732} 1.024529
POS:{X:6.801776 Y:0.835522 Z:10.10648} -> HIT:{X:5.316247 Y:0.8043603 Z:10.46832} {X:0.7798792 Y:0.3080164 Z:-0.5448983} 1.529278 <<-- Strange T value
POS:{X:6.477978 Y:0.8287297 Z:10.18535} -> HIT:{X:1.436852 Y:0.7229824 Z:11.41323} {X:0.2740156 Y:-0.6355036 Z:-0.7218384} 5.189589 <<-- Strange T value
POS:{X:6.15418 Y:0.8219374 Z:10.26422} -> HIT:{X:5.283859 Y:0.8036808 Z:10.47621} {X:0.7302805 Y:0.3005428 Z:-0.6134854} 0.8959519
POS:{X:5.830381 Y:0.8151451 Z:10.34309} -> HIT:{X:5.830381 Y:0.8151451 Z:10.34309} {X:NaN Y:NaN Z:NaN} 0
Plasma hit the target:
Normal = {X:NaN Y:NaN Z:NaN}
Point  = {X:5.830381 Y:0.8151451 Z:10.34309}
T      = 0
RayCast seems to be approximate. One RayCast does not detect hit, then I move projectile forward and second RayCast tells me that projectils is already inside of the object :(
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: RayCast returns zero normal

Post by Norbo »

Something doesn't look right; a normal should never turn out to be NaN in normal circumstances. If it's not a bug, there may be something in the environment which has invalid geometry.

Could you reproduce the problem in a BEPUphysicsDemos demo for me to debug?
demiurghg
Posts: 14
Joined: Mon Jun 04, 2012 10:02 am

Re: RayCast returns zero normal

Post by demiurghg »

I've reproduced the bug. See attachment.
On each Update() demo writes RayCast() results to the Output window.
RayCastBugDemo.cs
RayCast bug demo
(2.26 KiB) Downloaded 443 times
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: RayCast returns zero normal

Post by Norbo »

While I didn't see any NaN's, I am trying to track down the source of the missed impacts. I'm a bit surprised that this problem has not been reported before. I'll post again once I know more, but it might take me a little while.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: RayCast returns zero normal

Post by Norbo »

It appears to be caused by some numerical difficulties associated with the implicit curved surface of the capsule. The GJK implementation gets extremely close to the surface, but not close enough to trigger an exit by the defined tolerances. So instead of hitting, the simplex evolves into an invalid state due to the difficult numerical situation and a miss is returned.

This can be adjusted slightly by modifying the epsilon associated with termination, but that's trading the problem for greater allowed error.

I would like to return to this and harden the GJK implementation a bit more, but for now, I've created an MPR based ray cast as a replacement which is now used by the ConvexShape.RayTest method. MPR tends to converge better on curved surfaces and, due to the 'direction' the ray casting variation takes, doesn't fail so noticeably when it does have an issue. Specifically, on curved surfaces requiring many iterations, the simplex may become extremely tiny and the normal computed based on that simplex can be a little jumpy. That effect, however, is substantially less noticeable than simply not hitting the target :)

The change can be found in the development version: http://bepuphysics.codeplex.com/SourceC ... evelopment

I might add a special case for a capsule ray test too since it's pretty simple anyway.
Post Reply