2016-05-28 5 views
-1

Это код лучей, на котором я работаю. Когда я проверил это, все, казалось, работало нормально, пока я не начал менять положение камеры (точки обзора). Вот некоторые из результатов:Освещение в моем лучнике работает странно

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

свет на полу отрезана каким-то образом.

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

Это одно показывает ту же проблему.

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

Свет в этом скриншоте, кажется, имеет два источника света, хотя есть только один активный на данный момент.

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

Окончательное положение последней позиции я установил на коде ниже. Он находится в том же месте, что и свет.

Почему свет создает тени?

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

+1

Пожалуйста, отправьте сообщение [mcve]. С акцентом на * минимальный *. –

ответ

0

Это ужасно много кода, поэтому я могу только догадываться, в чем проблема. Так как проблема находится в не затененной части изображения, проблема заключается в вычислении цветов (или обоих): diffuse или specular. Вы можете прокомментировать каждый из них индивидуально, чтобы узнать, что дает вам ожидаемую окраску, а затем дальше диагностировать проблему.

Проблема может быть в вашем методе normalize, который не нормализует действительно короткие векторы. Это приведет к отключению цвета specular.

+0

Да, была проблема с зеркальным цветом! Я не задал направление луча от точки пересечения к негативному экрану при вычислении значения «h». И жаль для длинного кода. –