# Calculation of refraction vector seems to be incorrect...

This topic is 4918 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi, I try to calculate the refraction in a simple ray-tracer. But actually, the implementation seems to be incorrect. Here is what I've done so far (in C' and DirectX):
public static Vector3 RefractVector(Vector3 vector, Vector3 normal, float muSurfaceFront, float muSurfaceBack)
{
float nDotV = Vector3.Dot(normal, vector);

float mu;
if(nDotV > 0.0f)
{
mu = muSurfaceFront / muSurfaceBack;  // from front to back
}
else
{
mu = muSurfaceBack / muSurfaceFront;  // from back to front
}

float cosThetaT = 1 - (mu*mu * (1 - nDotV*nDotV));

// total internal reflection
if(cosThetaT < 0.0f)
{
return Vector3.Empty;
}

Vector3 refractionVector = ((mu * nDotV - (float)Math.Sqrt(cosThetaT)) * normal) - (mu * vector);

if(nDotV < 0.0f)
{
return -refractionVector;
}
else
{
return refractionVector;
}
}
IMPORTANT: The vector is assumed to start AT the surface and points towards the light or whatever!! I tested the code with simple vectors and the normal (0,1,0): ( 0, 1, 0) => ( 0,-1, 0) // correct? ( 0,-1, 0) => ( 0, 1, 0) // correct? ( 1, 1, 0) => (-1,-1, 0) // correct? ( 1,-1, 0) => ( 1, 1, 0) // INCORRECT? supposed (-1, 1, 0) (-1, 1, 0) => ( 1,-1, 0) // correct? (-1,-1, 0) => (-1, 1, 0) // INCORRECT? supposed ( 1, 1, 0) ... Can anyone tell me, how this damn refraction is calculated? That would be really great and let me live a few minutes longer....

##### Share on other sites
your algo looks correct on first glance, but i dont have my working code handy to compare it to.

in any case there is something wrong with all of your outcomes it seems. first of all the results are too 'clean', values like 0 and 1 are not to be expected.

secondly all dotproducts between your in and output are =< 0, and a < 0 outcome should be impossible, and 0 bordering on impossible.

so on thing is for sure: there is a mayor hole in there somewhere.

try googleing for extra sources, maybe your current example is flawed. otherwise derive/doublecheck it yourself using these observations:

the refracted vector is a weighted sum of the normal and the incoming vector. the two weights should be such as to statisfy two conditions: snells law and outgoing.length == 1, which is a solvable system of equations.

##### Share on other sites
Uh, I'm sorry. I forgot to mention that the refraction indices used for testing were both 1. So the refracted vector should be the inverse source vector. Inverse since both pointing away from the surface...

##### Share on other sites
i remembered something: that piece of code is derived assuming the ingoing vector is of unit length, which isnt the case in your failed examples. thats probably it, or atleast one problem.

##### Share on other sites
Oops, good point! I've totally overlooked that. But the normalized vectors don't change anything. Same results (except 0.707... instead of 1). And as you can see, 2 of my examples are correct even though they have x and y +/- 1.

##### Share on other sites
Weird. I tried hundreds of sample codes -- all with different but wrong results. What the hell is wrong with my code?!?!?! Or with me??

##### Share on other sites
i dont get it either. the expression for the weight multiplied with the normal simplifies to 0, the one for the input vector to -1, just the way you want them to.

although i dont completely understand how you overloading works, but that could be me: why do you write weight * vector, instead of vector * weight? you cant overload a float to be multiplyable by a vector, can you?

##### Share on other sites
I think you have a few signs wrong here:

Vector3 refractionVector = ((mu * nDotV - (float)Math.Sqrt(cosThetaT)) * normal) - (mu * vector);

should be

Vector3 refractionVector = -((mu * nDotV + (float)Math.Sqrt(cosThetaT)) * normal) + (mu * vector);

##### Share on other sites
Quote:
 Original post by Eelcoalthough i dont completely understand how you overloading works, but that could be me: why do you write weight * vector, instead of vector * weight? you cant overload a float to be multiplyable by a vector, can you?

Yes; you just make it a non-member function with two arguments. Actually, that's the recommended method of overloading a binary operator, because it encourages using only the public interfaces of the operand types, and as a bonus you get implicit conversions to work on both operands. Some operators have to be declared as member functions, though; foremost operator = (but operator += and its kind don't need to!)

vector operator * (float f, const vector &v){  return /* ... */}

##### Share on other sites
@Eelco

Quote:
 Vector3 refractionVector = -((mu * nDotV + (float)Math.Sqrt(cosThetaT)) * normal) + (mu * vector);

Well, that doesn't help either. The results are as follows (I extended my test-driver a bit ;-)):

incident:     0 / 1 / 0expected:     0 / -1 / 0refracted:    0 / -1 / 0 => Correct?: Trueincident:     0 / -1 / 0expected:     0 / 1 / 0refracted:    0 / 1 / 0 => Correct?: Trueincident:     0,7071068 / 0,7071068 / 0expected:     -0,7071068 / -0,7071068 / 0refracted:    0,7071068 / -0,7071068 / 0 => Correct?: Falseincident:     0,7071068 / -0,7071068 / 0expected:     -0,7071068 / 0,7071068 / 0refracted:    -0,7071068 / 0,7071068 / 0 => Correct?: Trueincident:     -0,7071068 / 0,7071068 / 0expected:     0,7071068 / -0,7071068 / 0refracted:    -0,7071068 / -0,7071068 / 0 => Correct?: Falseincident:     -0,7071068 / -0,7071068 / 0expected:     0,7071068 / 0,7071068 / 0refracted:    0,7071068 / 0,7071068 / 0 => Correct?: True

Ok, I think, before I'll freak out, here is my code again. This time, the whole thing. I'm wondering if the method works well and I only feed it with wrong vectors. Or my expected results are incorrect...

    private static void TestRefraction()    {        IList vectors  = new ArrayList();        IList expected = new ArrayList();        vectors.Add(Vector3.Normalize(new Vector3( 0,  1, 0)));  expected.Add(Vector3.Normalize(new Vector3( 0, -1, 0)));        vectors.Add(Vector3.Normalize(new Vector3( 0, -1, 0)));  expected.Add(Vector3.Normalize(new Vector3( 0,  1, 0)));        vectors.Add(Vector3.Normalize(new Vector3( 1,  1, 0)));  expected.Add(Vector3.Normalize(new Vector3(-1, -1, 0)));        vectors.Add(Vector3.Normalize(new Vector3( 1, -1, 0)));  expected.Add(Vector3.Normalize(new Vector3(-1,  1, 0)));        vectors.Add(Vector3.Normalize(new Vector3(-1,  1, 0)));  expected.Add(Vector3.Normalize(new Vector3( 1, -1, 0)));        vectors.Add(Vector3.Normalize(new Vector3(-1, -1, 0)));  expected.Add(Vector3.Normalize(new Vector3( 1,  1, 0)));        Vector3 normal = new Vector3(0, 1, 0);        for(int i = 0; i < vectors.Count; i++)        {            Vector3 incident  = (Vector3)vectors;            Vector3 exp       = (Vector3)expected;            Vector3 refracted = MathUtils.RefractVector(incident, normal, 1,1);            System.Diagnostics.Debug.WriteLine("");            System.Diagnostics.Debug.WriteLine("incident:     " + MathUtils.ToString(incident));            System.Diagnostics.Debug.WriteLine("expected:     " + MathUtils.ToString(exp));            System.Diagnostics.Debug.WriteLine("refracted:    " + MathUtils.ToString(refracted));            System.Diagnostics.Debug.WriteLine(" => Correct?: " + (refracted == exp));        }    }    public static Vector3 RefractVector(Vector3 vector, Vector3 mirrorNormal, float muSurfaceFront, float muSurfaceBack)    {        float nDotV = Vector3.Dot(mirrorNormal, vector);        float mu;        if(nDotV > 0.0f)        {            mu = muSurfaceFront / muSurfaceBack;    // from front to back        }        else        {            mu = muSurfaceBack / muSurfaceFront;    // from back to front        }        float cosThetaT = 1 - (mu*mu * (1 - nDotV*nDotV));        // total internal reflection        if(cosThetaT < 0.0f)        {            return Vector3.Empty;        }        Vector3 refractionVector = ((mu * nDotV - (float)Math.Sqrt(cosThetaT)) * mirrorNormal) - (mu * vector);        if(nDotV < 0.0f)        {            return -refractionVector;        }        else        {            return refractionVector;        }    }

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 15
• 11
• 9
• 9
• 41
• ### Forum Statistics

• Total Topics
634130
• Total Posts
3015706
×