简体   繁体   中英

Reflect light in 3D space

I am trying to reflect light onto a triangle surface in 3D space. Everything worked fine until I moved the light source to the triangle's backside.

It appears that when the light face the triangle's backside the light get reflected as if the light source were on the other side of the triangle. The reflected light's theta (angle between incoming light and the reflected light) will also be half of that of the normal (green line) instead of double.

On the images provided, the yellow dot is the light source, white line is incoming light, green line is the triangle's normal and red line is the reflected light

    public Location Reflect(Line A, ref Line B)
    {
        double lA = A.length;
        double lB = B.length;

        Location unitA = (A.Head - A.Tail) / lA;
        Location unitB = (B.Head - B.Tail) / lB;
        Location result = (unitB - (unitA - unitB)) * lA;

        return result;
    }

Temporary solution:

            if (Line.theta(A, B) < 0)
            unitB *= -1;

Results:

Reflection when Normal and light source are on the same side 当法线和光源在同一侧时发生反射

Reflection when Normal and light source are on opposite sides 当法线和光源在相对侧时发生反射

I didn't use any additional 3D resources. Everything is coded in pure C#.

Any help to fix it will be appreciated. Thank you for your time.

This behavior is really correct, let me explain how reflection is calculated and what's happening and how to solve it.

Each poligon in a 3D environment has a vector called normal , the normal is the vector which defines it's front face direction.

The normal vector is calculated using the poligon vertices, and depending if you do this calculation clockwise or counter-clockwise the normal will face front or back.

Pseudo code from Wikipedia:

Begin Function CalculateSurfaceNormal (Input Triangle) Returns Vector

    Set Vector U to (Triangle.p2 minus Triangle.p1)
    Set Vector V to (Triangle.p3 minus Triangle.p1)

    Set Normal.x to (multiply U.y by V.z) minus (multiply U.z by V.y)
    Set Normal.y to (multiply U.z by V.x) minus (multiply U.x by V.z)
    Set Normal.z to (multiply U.x by V.y) minus (multiply U.y by V.x)

    Returning Normal

End Function

If the ray comes from the back and the normal is facing front or vice-versa then the reflection will be reversed as it's happening to you.

As I see you're representing the normal as a line, that concept is wrong, a normal does not have an start and an end like a line segment, it only stores an angle, so it's a unit vector (Ref. from wikipedia: https://en.wikipedia.org/wiki/Unit_vector ).

Anyway, to solve your problem you need to check if the angle between the normal and the incomming ray are wider than 180º and if that's the case then reverse the normal, this will simulate a two-sided polygon.

To do this first calculate the angular vector from the light source to the face (Normalize(LightPosition - FacePosition)) and then check the angle between that vector and the normal.

Here is a good explanation on how to calculate the angle between two vectors: http://www.wikihow.com/Find-the-Angle-Between-Two-Vectors

A typical function used on shaders to calculate a point light illumination is precissely what you are trying to calculate, it usually has this form:

 float factor = clamp(dot(lightNormal, faceNormal), 0.0, 1.0);

The dot product of two vectors will give you a value between -1 and 1, you can use this to check if the angle must be reversed:

bool reversed = Dot(LightNormal, FaceNormal) < 0;

You can find lots of implementations of vectors and it's calculations(normalization, dot product, cross product, length, etc) for c# on Internet, if you want something which will allow also advance in a future to OpenGL you can use per example OpenTK, it has all the vector's math stuff and is very easy to use, else you can also go to the OpenTK source code and take the functions you need (or of course you can search for the mathematical explanation and implement it by yourself, that will be the best option as you will understand how all works, but will be the hardest approach).

Cheers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM