Public Group

# Ray - Sphere intersection test not working. What am I doing wrong?

## Recommended Posts

Posted (edited)

I'm stuck trying to make a simple ray sphere intersection test. I'm using this tutorial as my guide and taking code from there. As of now, I'm pretty sure I have the ray sorted out correctly. The way I'm testing my ray is by using the direction of the ray as the position of a cube, just to make sure it's in front of me.

cube.transform.position.x = Camera.main.ray.origin.x + Camera.main.ray.direction.x * 4;
cube.transform.position.y = Camera.main.ray.origin.y + Camera.main.ray.direction.y * 4;
cube.transform.position.z = Camera.main.ray.origin.z + Camera.main.ray.direction.z * 4;

So if I rotate the camera, the cube follows. So it's looking good.

The problem occurs with the actual intersection algorithm. Here are the steps I'm taking, I'll be very brief:

1) I subtract the sphere center with the ray origin:

L.x = entity.rigidbody.collider.center.x - ray.origin.x;
L.y = entity.rigidbody.collider.center.y - ray.origin.y;
L.z = entity.rigidbody.collider.center.z - ray.origin.z;
L.normalize();

2) I get the dot product of L and the ray direction:

const b = Mathf.dot(L, ray.direction);

3) And also the dot product  of L with itself (I'm not sure if I'm doing this step right):

const c = Mathf.dot(L, L);

4) So now I can check if B is less than 0, which means it's behind the object. That's working very nicely.

L.x = entity.rigidbody.collider.center.x - ray.origin.x;
L.y = entity.rigidbody.collider.center.y - ray.origin.y;
L.z = entity.rigidbody.collider.center.z - ray.origin.z;

const b = Mathf.dot(L, ray.direction);
const c = Mathf.dot(L, L);

if (b < 0) return false;

## Problem starts here

5) I now do this:

let d2 = (c * c) - (b * b);

6) ...and check if d2 > (entity.radius * entity.radius) and if it's greater: stop there by returning false. But it always passes, unless I don't normalize L and d2 ends up being a larger number and then it return false:

const radius2 = entity.rigidbody.collider.radius * entity.rigidbody.collider.radius;
if (d2 > radius2) return false;

but again, since I'm normalizing, it NEVER stops in that step. Which worries me.

7) I then do this:

let t1c = Math.sqrt(radius2 - d2);

...but it always returns a number in the range of 0.98, 0.97, if I'm standing still. But if I strafe left and right, the number lowers. If I rotate the camera, it makes no difference. Only if I strafe.

So I'm clearly doing something wrong and stopped there. Hopefully I made sense

Edited by Hashbrown

##### Share on other sites

Do you have checked with a second cube, that your ray is pointing in the right direction?

##### Share on other sites

Hey what's up Shaarigan? You mean instantiating another cube and testing the direction of the ray? I honestly haven't since I already tried with the one cube I show in the gifs above.

cube.transform.position.x = Camera.main.ray.origin.x + Camera.main.ray.direction.x * 4;
cube.transform.position.y = Camera.main.ray.origin.y + Camera.main.ray.direction.y * 4;
cube.transform.position.z = Camera.main.ray.origin.z + Camera.main.ray.direction.z * 4;

..and the cube remains in front of me. Also, before this implementation I had another one, and that one was working perfectly only if I don't move the camera. I wasn't considering the direction I guess.  So I'm guessing my ray is pointing towards the right direction. You got me wondering now.

##### Share on other sites

Found one bug where you squared a squared distance: c*c - b*b should be c - b*b

Returning on b<0 might be also wrong, but depends on your needs.

This should work i hope:

L.x = entity.rigidbody.collider.center.x - ray.origin.x;
L.y = entity.rigidbody.collider.center.y - ray.origin.y;
L.z = entity.rigidbody.collider.center.z - ray.origin.z;

const b = Mathf.dot(L, ray.direction);
const c = Mathf.dot(L, L);

//if (b < 0) return false; bad test: the ray could start inside the sphere, so pointing away but still hitting it
if (b < 0 && c < radius2) return false; // better: additionally test if the ray starts inside

let d2 = c - (b * b); // c is already squared distance, so don't square again

if (d2 > radius2) return false;

let t1c = Math.sqrt(radius2 - d2);

// first intersection:	ray.origin + ray.direction * (b - t1c);
// second intersection:	ray.origin + ray.direction * (b + t1c);

##### Share on other sites

I see you are confused about normalizing L or not. My own practice here is: First write the code normalizing stuff so it's easy to understand. Second, when it works try to remove square roots. But after that the code becomes often unreadable. The code from my snippet above is optimized and not very intuitive. You could rewrite it for an exercise, but don't forget to store the length of L before you normalize

##### Share on other sites
5 hours ago, Hashbrown said:

You mean instantiating another cube and testing the direction of the ray

In my professional all-day practise we draw some test stuff (Unity calls it Gizmos) to see if our calculations go right. This also means drawing a line from where we assume the ray to start to where it is calculated to go/end. This helps to see if your ray is logical/optical hitting the sphere before doing optimizations/bugfixing in your hit-test calculation.

I have had a lot of issues seen in my career that were caused by wrong calculated data rather than any test using them

##### Share on other sites

Thanks a lot guys, Shaarigan was right, there something going on with my ray too. I'll do what unity does and draw lines and get that sorted out first. And JoeJ, you're also right, I was confused about when to normalize, I copied your code and as soon as I fix my ray issue, I'll use your code.

I'll share what I learn once I do, thanks again guys

• ### Similar Content

• By cozzie
Hi guys,
I've been struggling to create a function to draw an arrow with 2 lines making up the arrowhead.
The challenge is that I somehow can't get the rotation right.
I've pasted the code below and an image of the result.
Findings so far, when I replace the 3x3 part of the transform matrix to identity, I get the same visual result.
Also when I switch colums A and C in the matrix, this specific arrow looks good (with is pointing in the positive X direction).
Any input would be appreciated.

Aimed/ correct result (independent of arrow direction):

• Hello Everyone!
I am looking for a small team to do a rendering project with me. The roles I need are:
-Character Modeller
-Environment Designer
-Environment Modeller(Found)
You can use this in your portfolio and you will be credited at the end.
If you are interested, please email me at marfo343@gmail.com. Thank you!
• By D34DPOOL
Edit Your Profile D34DPOOL 0 Threads 0 Updates 0 Messages Network Mod DB GameFront Sign Out Add jobEdit jobDeleteC# Programmer for a Unity FPS at Anywhere   Programmers located Anywhere.
Posted by D34DPOOL on May 20th, 2018
Hello, my name is Mason, and I've been working on a Quake style arena shooter about destroying boxes on and off for about a year now. I have a proof of concept with all of the basic features, but as an artist with little programming skill I've reached the end of my abilities as a programmer haha. I need someone to help fix bugs, optomize code, and to implent new features into the game. As a programmer you will have creative freedom to suggest new features and modes to add into the game if you choose to, I'm usually very open to suggestions :).
What is required:
Skill using C#
Experience with Unity
Experience using UNET (since it is a multiplayer game), or the effort and ability to learn it
Compensation:
Since the game currently has no funding, we can split whatever revenue the game makes in the future. However if you would perfer I can create 2D and/or 3D assets for whatever you need in return for your time and work.
It's a very open and chill enviornment, where you'll have relative creative freedom. I hope you are interested in joining the team, and have a good day!

To apply email me at mangemason@yahoo.com

• I am a talented 2D/3D artist with 3 years animation working experience and a Degree in Illustration and Animation. I have won a world-wide art competition hosted by SFX magazine and am looking to develop a survival game. I have some knowledge of C sharp and have notes for a survival based game with flexible storyline and PVP. Looking for developers to team up with. I can create models, animations and artwork and I have beginner knowledge of C sharp with Unity. The idea is Inventory menu based gameplay and is inspired by games like DAYZ.
Here is some early sci-fi concept art to give you an idea of the work level. Hope to work with like minded people and create something special. email me andrewparkesanim@gmail.com.
Developers who share the same passion please contact me, or if you have a similar project and want me to join your team email me.
Many thanks, Andrew.

• I made this post on Reddit. I need ideas and information on how to create the ground mesh for my specifications.

• GOVERNOR is a modernized version of the highly popular series of “Caesar” games. Our small team has already developed maps, written specifications, acquired music and performed the historical research needed to create a good base for the programming part of the project.

Our ultimate goal is to create a world class multi-level strategic city building game, but to start with we would like to create some of the simpler modules to demonstrate proof of concept and graphical elegance.

We would like programmers and graphical artists to come onboard to (initially) create:

A module where Province wide infrastructure can be built on an interactive 3D map of one of the ancient Roman Provinces.
A module where city infrastructure can be built on a real 3D interactive landscape.
For both parts, geographically and historically accurate base maps will be prepared by our team cartographer. Graphics development will be using Blender. The game engine will be Unity.

More information, and examples of the work carried out so far can be found at http://playgovernor.com/ (most of the interesting content is under the Encyclopedia tab).

This project represents a good opportunity for upcoming programmers and 3D modeling artists to develop something for their portfolios in a relatively short time span, working closely with one of Canada’s leading cartographers. There is also the possibility of being involved in this project to the point of a finished game and commercial success! Above all, this is a fun project to work on.

Best regards,

• Hi
I’ve been working on a game engine for years and I’ve recently come back to it after a couple of years break.  Because my engine uses DirectX9.0c I thought maybe it would be a good idea to upgrade it to DX11. I then installed Windows 10 and starting tinkering around with the engine trying to refamiliarise myself with all the code.
It all seems to work ok in the new OS but there’s something I’ve noticed that has caused a massive slowdown in frame rate. My engine has a relatively sophisticated terrain system which includes the ability to paint roads onto it, ala CryEngine. The roads are spline curves and built up with polygons matching the terrain surface. It used to work perfectly but I’ve noticed that when I’m dynamically adding the roads, which involves moving the spline curve control points around the surface of the terrain, the frame rate comes to a grinding halt.
There’s some relatively complex processing going on each time the mouse moves - the road either side of the control point(s) being moved, is reconstructed in real time so you can position and bend the road precisely. On my previous OS, which was Win2k Pro, this worked really smoothly and in release mode there was barely any slow down in frame rate, but now it’s unusable. As part of the road reconstruction, I lock the vertex and index buffers and refill them with the new values so my question is, on windows 10 using DX9, is anyone aware of any locking issues? I’m aware that there can be contention when locking buffers dynamically but I’m locking with LOCK_DISCARD and this has never been an issue before.
Any help would be greatly appreciated.

• I have a problem with SSAO. On left hand black area.
Texture2D<uint> texGBufferNormal : register(t0); Texture2D<float> texGBufferDepth : register(t1); Texture2D<float4> texSSAONoise : register(t2); float3 GetUV(float3 position) { float4 vp = mul(float4(position, 1.0), ViewProject); vp.xy = float2(0.5, 0.5) + float2(0.5, -0.5) * vp.xy / vp.w; return float3(vp.xy, vp.z / vp.w); } float3 GetNormal(in Texture2D<uint> texNormal, in int3 coord) { return normalize(2.0 * UnpackNormalSphermap(texNormal.Load(coord)) - 1.0); } float3 GetPosition(in Texture2D<float> texDepth, in int3 coord) { float4 position = 1.0; float2 size; texDepth.GetDimensions(size.x, size.y); position.x = 2.0 * (coord.x / size.x) - 1.0; position.y = -(2.0 * (coord.y / size.y) - 1.0); position.z = texDepth.Load(coord); position = mul(position, ViewProjectInverse); position /= position.w; return position.xyz; } float3 GetPosition(in float2 coord, float depth) { float4 position = 1.0; position.x = 2.0 * coord.x - 1.0; position.y = -(2.0 * coord.y - 1.0); position.z = depth; position = mul(position, ViewProjectInverse); position /= position.w; return position.xyz; } float DepthInvSqrt(float nonLinearDepth) { return 1 / sqrt(1.0 - nonLinearDepth); } float GetDepth(in Texture2D<float> texDepth, float2 uv) { return texGBufferDepth.Sample(samplerPoint, uv); } float GetDepth(in Texture2D<float> texDepth, int3 screenPos) { return texGBufferDepth.Load(screenPos); } float CalculateOcclusion(in float3 position, in float3 direction, in float radius, in float pixelDepth) { float3 uv = GetUV(position + radius * direction); float d1 = DepthInvSqrt(GetDepth(texGBufferDepth, uv.xy)); float d2 = DepthInvSqrt(uv.z); return step(d1 - d2, 0) * min(1.0, radius / abs(d2 - pixelDepth)); } float GetRNDTexFactor(float2 texSize) { float width; float height; texGBufferDepth.GetDimensions(width, height); return float2(width, height) / texSize; } float main(FullScreenPSIn input) : SV_TARGET0 { int3 screenPos = int3(input.Position.xy, 0); float depth = DepthInvSqrt(GetDepth(texGBufferDepth, screenPos)); float3 normal = GetNormal(texGBufferNormal, screenPos); float3 position = GetPosition(texGBufferDepth, screenPos) + normal * SSAO_NORMAL_BIAS; float3 random = normalize(2.0 * texSSAONoise.Sample(samplerNoise, input.Texcoord * GetRNDTexFactor(SSAO_RND_TEX_SIZE)).rgb - 1.0); float SSAO = 0; [unroll] for (int index = 0; index < SSAO_KERNEL_SIZE; index++) { float3 dir = reflect(SamplesKernel[index].xyz, random); SSAO += CalculateOcclusion(position, dir * sign(dot(dir, normal)), SSAO_RADIUS, depth); } return 1.0 - SSAO / SSAO_KERNEL_SIZE; }

• Hello everyone
I am a programmer from Baku.
I need a 3D Modeller for my shooter project in unity.I have 2 years Unity exp.
Project will paid when we finish the work
If you interested write me on email:
mr.danilo911@gmail.com

• Hi guys, I'm trying to learn this stuff but running into some problems 😕
I've compiled my .hlsl into a header file which contains the global variable with the precompiled shader data:
//... // Approximately 83 instruction slots used #endif const BYTE g_vs[] = { 68, 88, 66, 67, 143, 82, 13, 236, 152, 133, 219, 113, 173, 135, 18, 87, 122, 208, 124, 76, 1, 0, 0, 0, 16, 76, 0, 0, 6, 0, //.... And now following the "Compiling at build time to header files" example at this msdn link , I've included the header files in my main.cpp and I'm trying to create the vertex shader like this:
hr = g_d3dDevice->CreateVertexShader(g_vs, sizeof(g_vs), nullptr, &g_d3dVertexShader); if (FAILED(hr)) { return -1; } and this is failing, entering the if and returing -1.
Can someone point out what I'm doing wrong? 😕

• 11
• 20
• 12
• 10
• 35
• ### Forum Statistics

• Total Topics
631399
• Total Posts
2999857
×