这是我正在研究的光线跟踪器代码。当我测试它时,一切似乎都工作正常,直到我开始改变相机(观察点)的位置。以下是一些结果:
坎波斯(-60,100,-30),lightPos(-70,100,-30)
地板上的灯被切断了。
坎波斯(60,100,-30),lightPos(-70,100,-30)
这个问题显示了同样的问题。
坎波斯(60,30,-30),lightPos(-70,100,-30)
此屏幕截图中的灯光似乎有两个光源,但目前只有一个有效。
坎波斯(-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
#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
答案 0 :(得分:0)
这是一个糟糕的代码,所以我只能猜测问题是什么。由于问题出在图像的非阴影部分,因此问题在于计算diffuse
或specular
颜色(或两者)。你可以单独注释每一个,看看是什么给你预期的颜色,然后从那里进一步诊断问题。
问题可能出在您的normalize
方法中,该方法不会对真正的短向量进行标准化。这会导致specular
颜色关闭。