2016-05-28 11 views
-1

Dies ist ein Ray-Tracer-Code, an dem ich arbeite. Als ich es ausprobierte, schien alles in Ordnung zu sein, bis ich anfing, die Position der Kamera (Blickpunkt) zu ändern. Hier sind einige der Ergebnisse:Beleuchtung in meinem Ray Tracer funktioniert seltsam

enter image description here campos (-60, 100, -30), LightPos (-70, 100, -30)

Das Licht auf dem Boden ist irgendwie abgeschnitten.

enter image description here campos (60, 100, -30), LightPos (-70, 100, -30)

Dieser zeigt das gleiche Problem.

enter image description here campos (60, 30, -30), LightPos (-70, 100, -30)

Das Licht in diesem Screenshot scheint zwei Lichtquellen zu haben, obwohl es nur eine aktive zur Zeit ist.

enter image description here campos (-70, 100, -30), LightPos (-70, 100, -30)

Die Endposition ist die letzte Position I unten auf den Code gesetzt. Es ist genau am selben Ort wie die Lichtmagie.

Warum erzeugt das Licht so Schatten?

main.cpp

#include <iostream> 
#include <algorithm> 
#include <GL/glut.h> 
#include <GL/gl.h> 
#include <GL/glu.h> 
#include <math.h> 
#include <vector> 

#include "Vector.h" 
#include "Ray.h" 
#include "Camera.h" 
#include "Color.h" 
#include "Light.h" 
#include "Sphere.h" 
#include "Plane.h" 

#define PI 3.141592653589793 
#define INFINITY 1e6 
#define FOV 60 
#define KA 0.2 
#define KD 0.5 
#define KS 5 

VECTOR X = { 1,0,0 }; 
VECTOR Y = { 0,1,0 }; 
VECTOR Z = { 0,0,1 }; 
VECTOR O = { 0,0,0 }; 

Color white(1, 1, 1); 
Color black(0, 0, 0); 
Color greenC(0.5, 1, 0.5); 
Color gray(0.5, 0.5, 0.5); 
Color maroon(0.5, 0.25, 0.25); 

unsigned int width = 640; 
unsigned int height = 480; 

using namespace std; 

Color trace(Ray &ray, vector<Object*> objects, vector<Light*> lights) 
{ 
    float hit = INFINITY; 
    float closest = INFINITY; 
    Object* objectHit = NULL; 
    for (int i = 0; i < objects.size(); i++) 
    { 
     if (objects.at(i)->intersect(ray, hit)) 
     { 
      if (hit < closest) 
      { 
       closest = hit; 
       objectHit = objects.at(i); 
      } 
     } 
    } 

    if (objectHit) 
    { 
     VECTOR hitP = ray.getOrigin() + ray.getDirction() * closest; 
     VECTOR hitN = objectHit->getNormal(hitP); 

     Color finalColor = objectHit->getColor() * objectHit->getKa(); //ambient color 

     for (int i = 0; i < lights.size(); i++) 
     { 
      VECTOR lightDir = lights.at(i)->getPos() - hitP; 
      float lightDist = lightDir.Magnitude(); 
      lightDir.Normalize(); 

      bool shadow = false; 

      Ray shadowRay(hitP, lightDir); 

      float angle = max(hitN.DotProduct(lightDir), 0.0f); 

      for (int j = 0; j < objects.size() && shadow == false; j++) 
      { 
       float p; 
       if (objects.at(j)->intersect(shadowRay, p) && objectHit != objects.at(j)) 
       { 
        VECTOR objectDist = hitP + lightDir * p; 
        if (objectDist.Magnitude() <= lightDist) 
         shadow = true; 
       } 
      } 
      if (!shadow) 
      { 
       VECTOR h = ray.getDirction() + lightDir; 
       h.Normalize(); 
       Color diffuse = lights.at(i)->getCol() * objectHit->getKd() * angle; 
       Color specular = lights.at(i)->getCol() * angle * pow(max(hitN.DotProduct(h), 0.0f), objectHit->getKs()); 
       finalColor = finalColor + diffuse + specular; 
      } 
     } 

     return finalColor.clip(); 
    } 
    else return black; 
} 

void Render(void) 
{ 
    glClear(GL_COLOR_BUFFER_BIT); 

    vector<Object*> objects; 
    int radius = 20; 
    Sphere sphere(O, radius, greenC, KA, KD, KS); 
    Plane plane(Y, VECTOR(0, -radius, 0), maroon, 0.3, 0.5, 0.01); 
    objects.push_back(&sphere); 
    objects.push_back(&plane); 

    float xx, yy; 
    Color *image = new Color[width*height]; 
    Color *pixel = image; 

    VECTOR lightPos(-70, 100, -30); 
    Light light(lightPos, gray); 
    //Light l2(VECTOR(10, 10, -20), white); 
    vector<Light*> lights; 
    lights.push_back(&light); 
    //lights.push_back(&l2); 

    VECTOR camPos(-70, 100, -30); 
    VECTOR lookat(0, 0, 0); 
    VECTOR diff(camPos.getX() - lookat.getX(), camPos.getY() - lookat.getY(), camPos.getZ() - lookat.getZ()); 
    VECTOR camDir = diff; 
    camDir.Normalize(); 
    VECTOR camRight = Y.CrossProduct(camDir); 
    camRight.Normalize(); 
    VECTOR camUp = camRight.CrossProduct(camDir).Negative(); 
    Camera cam(camPos, camDir, camRight, camUp); 

    for (int x = 0; x < width; x++) 
    { 
     for (int y = 0; y < height; y++) 
     { 
      xx = -(double)(width/2) + x + 0.5; 
      yy = -(double)(height/2) + y + 0.5; 

      VECTOR ray_d = camRight*xx + camUp*yy + camDir; 
      VECTOR ray_origin = camPos; 
      VECTOR ray_dir = ray_d - ray_origin; 
      ray_dir.Normalize(); 
      Ray ray(ray_origin, ray_dir); 

      *(pixel++) = trace(ray, objects, lights); 

      float red = image[x*height + y].getRed(); 
      float green = image[x*height + y].getGreen(); 
      float blue = image[x*height + y].getBlue(); 

      glColor3f(red, green, blue); 
      glBegin(GL_POINTS); 
      glVertex2i(x, y); 
      glEnd(); 
     } 
    } 

    glutSwapBuffers(); 
} 

struct RGBtype 
{ 
    float r, g, b; 
}; 

int main(int argc, char ** argv) 
{ 
    glutInit(&argc, argv); 

    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 
    glutInitWindowSize(width, height); 
    glutCreateWindow("Ray tracer"); 
    glClearColor(0.0, 0.0, 0.0, 0.0); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    gluOrtho2D(0.0, width, 0.0, height); 
    glutDisplayFunc(Render); 

    glutMainLoop(); 

    return 0; 
} 

Vector.h

#ifndef _VECTOR_H_ 
#define _VECTOR_H_ 

#include <math.h> 

class VECTOR 
{ 
private: 
    float x, y, z; 

public: 
    VECTOR(); 
    ~VECTOR(); 
    VECTOR(float, float, float); 

    float getX() { return x; } 
    float getY() { return y; } 
    float getZ() { return z; } 

    float Magnitude(); 
    VECTOR CrossProduct(VECTOR); 
    float DotProduct(VECTOR); 
    VECTOR vecAdd(VECTOR); 
    VECTOR vecMul(float); 
    void Normalize(); 
    VECTOR Negative(); 

    VECTOR operator - (VECTOR); 
    VECTOR operator + (VECTOR); 
    VECTOR operator * (float); 
}; 

VECTOR VECTOR::operator-(VECTOR v) 
{ 
    VECTOR result = (*this); 
    result.x -= v.getX(); 
    result.y -= v.getY(); 
    result.z -= v.getZ(); 

    return result; 
} 

VECTOR VECTOR::operator+(VECTOR v) 
{ 
    VECTOR result = (*this); 
    result.x += v.getX(); 
    result.y += v.getY(); 
    result.z += v.getZ(); 

    return result; 
} 

VECTOR VECTOR::operator*(float f) 
{ 
    return VECTOR(x*f, y*f, z*f); 
} 

VECTOR::VECTOR() 
{ 
    x = y = z = 0; 
} 

VECTOR::~VECTOR(){} 

VECTOR::VECTOR(float xPos, float yPos, float zPos) 
{ 
    x = xPos; 
    y = yPos; 
    z = zPos; 
} 

float VECTOR::Magnitude() 
{ 
    return sqrt(x * x + y * y + z * z); 
} 

float VECTOR::DotProduct(VECTOR v) 
{ 
    return (x * v.getX() + y * v.getY() + z * v.getZ()); 
} 

VECTOR VECTOR::CrossProduct(VECTOR v) 
{ 
    VECTOR result; 
    result.x = y * v.getZ() - z * v.getY(); 
    result.y = z * v.getX() - x * v.getZ(); 
    result.z = x * v.getY() - y * v.getX(); 
    return result; 
} 

VECTOR VECTOR::vecAdd(VECTOR v) 
{ 
    return VECTOR(x + v.getX(), y + v.getY(), +z + v.getZ()); 
} 

VECTOR VECTOR::vecMul(float f) 
{ 
    return VECTOR(x*f, y*f, z*f); 
} 

void VECTOR::Normalize() 
{ 
    float w = Magnitude(); 
    if (w < 0.00001) return; 
    x /= w; 
    y /= w; 
    z /= w; 
} 

VECTOR VECTOR::Negative() 
{ 
    return VECTOR(-x,-y,-z); 
} 


#endif // !_VECTOR_H_#pragma once 

Ray.h

#ifndef _RAY_H_ 
#define _RAY_H_ 

#include "Vector.h" 

class Ray 
{ 
private: 
    VECTOR origin, direction; 

public: 
    Ray(); 
    ~Ray(); 
    Ray(VECTOR, VECTOR); 

    VECTOR getOrigin() { return origin; } 
    VECTOR getDirction() { return direction; } 

}; 

Ray::Ray() 
{ 
    origin = VECTOR { 0,0,0 }; 
    direction = VECTOR { 1,0,0 }; 
} 

Ray::~Ray() {} 

Ray::Ray(VECTOR o, VECTOR d) 
{ 
    origin = o; 
    direction = d; 
} 
#endif // !_Ray_H_#pragma once 

Camera.h

#ifndef _CAMERA_H_ 
#define _CAMERA_H_ 

#include "Vector.h" 

class Camera 
{ 
private: 
    VECTOR camPos, camDir, camRight, camUp; 

public: 
    Camera(); 
    ~Camera(); 
    Camera(VECTOR, VECTOR, VECTOR, VECTOR); 

    VECTOR getCamPos() { return camPos; } 
    VECTOR getCamDir() { return camDir; } 
    VECTOR getCamRight() { return camRight; } 
    VECTOR getcamUp() { return camUp; } 

}; 

Camera::Camera() 
{ 
    camPos = VECTOR{ 0,0,0 }; 
    camDir = VECTOR{ 0,0,1 }; 
    camRight = VECTOR{ 0,0,0 }; 
    camUp = VECTOR{ 0,0,0 }; 
} 

Camera::~Camera() {} 

Camera::Camera(VECTOR pos, VECTOR dir, VECTOR right, VECTOR down) 
{ 
    camPos = pos; 
    camDir = dir; 
    camRight = right; 
    camUp = down; 
} 
#endif // !_CAMERA_H_#pragma once 

Color.h

#ifndef _COLOR_H_ 
#define _COLOR_H_ 

#include "Vector.h" 

class Color 
{ 
private: 
    double red, green, blue; 

public: 
    Color(); 
    ~Color(); 
    Color(double, double, double); 

    double getRed() { return red; } 
    double getGreen() { return green; } 
    double getBlue() { return blue; } 

    void setRed(double r) { red = r; } 
    void setGreen(double g) { green = g; } 
    void setBlue(double b) { blue = b; } 

    double brightness() { return (red + green + blue)/3; } 
    Color average(Color c) { return Color((red + c.getRed())/2, (green + c.getGreen())/2, (blue + c.getBlue())/2); } 
    Color operator * (double); 
    Color operator + (Color); 
    Color operator * (Color); 

    Color clip() 
    { 
     float sum = red + green + blue; 
     float extra = sum - 3; 
     if (extra > 0) 
     { 
      red = red + extra * (red/sum); 
      green = red + extra * (green/sum); 
      blue = red + extra * (blue/sum); 
     } 
     if (red > 1) { red = 1; } 
     if (green > 1) { green = 1; } 
     if (blue > 1) { blue = 1; } 
     if (red < 0) { red = 0; } 
     if (green < 0) { green = 0; } 
     if (blue < 0) { blue = 0; } 

     return Color(red, green, blue); 
    } 
}; 

Color Color::operator * (double c) { return Color(red*c, green*c, blue*c); } 
Color Color::operator + (Color c) { return Color(red + c.getRed(), green + c.getGreen(), blue + c.getBlue()); } 
Color Color::operator * (Color c) { return Color(red*c.getRed(), green*c.getGreen(), blue*c.getBlue()); } 

Color::Color() 
{ 
    red = green = blue = 1; 
} 

Color::~Color() {} 

Color::Color(double r, double g, double b) 
{ 
    red = r; 
    green = g; 
    blue = b; 
} 
#endif // !_COLOR_H_#pragma once 

Light.h

#ifndef _LIGHT_H_ 
#define _LIGHT_H_ 

#include "Vector.h" 
#include "Color.h" 

class Light 
{ 
private: 
    VECTOR position; 
    Color color; 

public: 
    Light(); 
    ~Light(); 
    Light(VECTOR, Color); 

    virtual VECTOR getPos() { return position; } 
    virtual Color getCol() { return color; } 
}; 

Light::Light() 
{ 
    position = VECTOR(0, 0, 0); 
    color = Color(1,1,1); 
} 

Light::~Light() {} 

Light::Light(VECTOR v, Color c) 
{ 
    position = v; 
    color = c; 
} 
#endif // !_LIGHT_H_#pragma once 

Sphere.h

#ifndef _SPHERE_H_ 
#define _SPHERE_H_ 

#include <math.h> 

#include "Vector.h" 
#include "Color.h" 
#include "Object.h" 

class Sphere : public Object 
{ 
private: 
    VECTOR center; 
    float radius; 
    Color color; 
    float ka, kd, ks; 
public: 
    Sphere(); 
    ~Sphere(); 
    Sphere(VECTOR, float, Color, float, float, float); 

    float getKa() { return ka; } 
    float getKd() { return kd; } 
    float getKs() { return ks; } 
    VECTOR getCenter() { return center; } 
    float getRadius() { return radius; } 
    Color getColor() { return color; } 
    VECTOR getNormal(VECTOR &v) 
    { 
     VECTOR a = v - center; 
     a.Normalize(); 
     return a; 
    } 

    bool intersect(Ray &ray, float &t) 
    { 
     float t0, t1; 
     float radius2 = radius * radius;     //radius squared 
     VECTOR line = center - ray.getOrigin();    //vector from ray origin to sphere center 
     float ray_t = line.DotProduct(ray.getDirction()); //the current ray vector 
     if (ray_t < 0) 
      return false; 
     float d2 = line.DotProduct(line) - (ray_t * ray_t); //d2 + t2 = line2 by pythagorian theorm 
     if (d2 > radius2)         //if larger than the radius, then the ray doesn't intersect with sphere 
      return false; 
     float ray_i = sqrt(radius2 - d2);     //part of ray that is going through the sphere 
     t0 = ray_t - ray_i;         //first sphere vertex along the ray 
     t1 = ray_t + ray_i;         //second sphere vertex 

     if (t0 > t1) 
     { 
      float tmp = t0; 
      t0 = t1; 
      t1 = t0; 
     } 
     if (t0 < 0) 
     { 
      t0 = t1; 
      t = t0; 
      if (t0 < 0) return false; 
     } 

     t = t0; 

     return true; 
    } 
}; 

Sphere::Sphere() 
{ 
    center = VECTOR(0, 0, 0); 
    radius = 1; 
    color = Color(1, 1, 1); 
} 

Sphere::~Sphere() {} 

Sphere::Sphere(VECTOR v, float r, Color c, float a, float d, float s) 
{ 
    center = v; 
    radius = r; 
    color = c; 
    ka = a; 
    kd = d; 
    ks = s; 
} 
#endif // !_SPHERE_H_#pragma once 

Object.h

#ifndef _OBJECT_H_ 
#define _OBJECT_H_ 

#include "Ray.h" 
#include "Vector.h" 
#include "Color.h" 

class Object 
{ 
private: 
    VECTOR center; 
    Color color; 
    float ka, kd, ks; 
public: 
    Object(); 
    ~Object(); 

    virtual float getKa() = 0; 
    virtual float getKd() = 0; 
    virtual float getKs() = 0; 
    virtual VECTOR getCenter() = 0; 
    virtual Color getColor() = 0; 
    virtual VECTOR getNormal(VECTOR&) = 0; 
    virtual bool intersect(Ray&, float&) = 0; 
}; 

Object::Object(){} 
Object::~Object() {} 
#endif // !_OBJECT_H_#pragma once 

Plane.h

#ifndef _PLANE_H_ 
#define _PLANE_H_ 

#include <math.h> 
#include<vector> 

#include "Vector.h" 
#include "Color.h" 
#include "Object.h" 

using namespace std; 

class Plane : public Object 
{ 
private: 
    VECTOR normal; 
    float width, height; 
    vector<VECTOR> vertice; 
    VECTOR center; //to be used in equation (p - p0) * n = 0 where p is the point of intersection and p0 is the center 
    Color color; 
    float ka, kd, ks; 
public: 
    Plane(); 
    ~Plane(); 
    Plane(VECTOR, VECTOR, Color, float, float, float); 

    float getKa() { return ka; } 
    float getKd() { return kd; } 
    float getKs() { return ks; } 
    VECTOR getNormal(VECTOR &point) 
    { 
     VECTOR a = normal; 
     a.Normalize(); 
     return a; 
    } 
    VECTOR getCenter() { return center; } 
    Color getColor() { return color; } 

    bool intersect(Ray &ray, float &t) 
    { 
     VECTOR rayDir = ray.getDirction(); 

     float ray_f = rayDir.DotProduct(normal); 

     //ray doesn't intersect or is parallel to the plane - ray-plane intersection 
     if (fabs(ray_f) < 1e-6) 
      return false; 
     else 
     { 
      VECTOR tmp = (center - ray.getOrigin()); 
      float plane_f = normal.DotProduct(tmp); 
      //returns t in parametric equation of ray point = origin + t*direction 
      t = plane_f/ray_f; 
      return (t >= 0); 
     } 
    } 
}; 

Plane::Plane() 
{ 
    normal = VECTOR(0, 1, 0); 
    center = VECTOR(0, 0, 0); 
    color = Color(0.5, 0.5, 0.5); 
    width = 500; 
    height = 500; 
} 

Plane::~Plane() {} 

Plane::Plane(VECTOR v, VECTOR o, Color c, float a, float d, float s) 
{ 
    normal = v; 
    center = o; 
    color = c; 
    ka = a; 
    kd = d; 
    ks = s; 
} 

#endif // !_PLANE_H_#pragma once 
+1

Bitte poste ein [mcve]. Mit Schwerpunkt auf dem * minimal *. –

Antwort

0

Dies ist ein schrecklich viel Code, so kann ich nur raten, was das Problem ist. Da das Problem im nicht schattierten Teil des Bildes liegt, liegt das Problem in der Berechnung der Farben diffuse oder specular (oder beides). Sie können jeden einzeln auskommentieren, um zu sehen, was Ihnen die erwartete Färbung gibt, und dann das Problem von dort weiter diagnostizieren.

Das Problem kann in Ihrer normalize Methode sein, die nicht wirklich kurze Vektoren normalisiert. Dies würde dazu führen, dass die Farbe specular ausgeschaltet ist.

+0

Ja, es gab tatsächlich ein Problem bei der Spiegelfarbe! Ich habe die Strahlrichtung vom Schnittpunkt zum Negativ des Ansichtsfensters nicht festgelegt, wenn ich für den Wert 'h' berechne. Und sry für den langen Code. –

Verwandte Themen