没有得到正确的阴影位置,基于 CPU 的光线追踪
Posted
技术标签:
【中文标题】没有得到正确的阴影位置,基于 CPU 的光线追踪【英文标题】:Not getting correct position of Shadows , CPU based Raytracing 【发布时间】:2019-10-04 01:23:56 【问题描述】:我正在尝试在基于 CPU 的光线跟踪中计算阴影,但我没有得到准确位置的阴影, 我正在尝试设计著名的康奈尔盒子,
图中的球体也被不正确地着色,
我已经粘贴了整个代码。 我在场景中使用了 2 个球体和 10 个三角形, 我猜我的阴影追踪算法或正常计算有问题
class Figure
public:
Vec3 position;
Vec3 cl;
Vec3 normal;
Figure(void);
Figure(Vec3 pos,Vec3 col,Vec3 Normal);
virtual bool intersection(float* t,Vec3 origin,Vec3 direction);
virtual Vec3 calculateNormal(Vec3 p0,float *intensity,Vec3* Diffusecolor,Vec3* Specular);
virtual bool intersectionShadow(float* t,Vec3 origin,Vec3 direction);
;
Figure::Figure()
position = Vec3(0,0,0);
cl = Vec3(0,0,0);
normal = Vec3(0,0,0);
Figure::Figure(Vec3 post, Vec3 coli,Vec3 Normal)
position = post;
cl = coli;
normal = Normal;
bool Figure::intersection(float *t, Vec3 origin,Vec3 direction)
return false;
Vec3 Figure::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular)
return normal;
bool Figure::intersectionShadow(float *t, Vec3 origin, Vec3 direction)
return false;
class Plane:public Figure
public:
Vec3 planeNormal;
Plane(void);
Plane(Vec3 pos,Vec3 norm,Vec3 c);
bool intersection(float *t, Vec3 origin, Vec3 direction);
Vec3 Plane::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular);
;
Plane::Plane(void)
planeNormal=Vec3(0,0,0);
Plane::Plane(Vec3 pos,Vec3 norm,Vec3 c)
position = pos;
planeNormal = norm;
cl = c;
bool Plane::intersection(float *t, Vec3 origin, Vec3 direction)
float denom = planeNormal.dot(direction);
if(abs(denom)<0.0001f)
return false;
else
Vec3 p_or = position-origin;
float res = p_or.dot(planeNormal)/denom;
*t = res;
Vec3 Plane::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular)
*intensity = 0;
*Diffusecolor = Vec3(0.7, 0.7, 0.7);
*Specular = cl;
return planeNormal;
class Sphere:public Figure
public:
float radius;
Sphere(void);
Sphere(Vec3 pos,float rad,Vec3 col);
bool intersection(float* t,Vec3 origin,Vec3 direction);
Vec3 calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular);
;
Sphere::Sphere()
position = Vec3(0,0,-2);
radius = 0.3f;
cl = Vec3(1.0,0,0);
Sphere::Sphere(Vec3 pos, float rad, Vec3 col)
position = pos;
radius = rad;
cl = col;
bool Sphere::intersection(float *t, Vec3 origin,Vec3 direction)
Vec3 oc = origin - position;
float a = direction.dot(direction);
float b = 2.0f * oc.dot(direction);
float c = oc.dot(oc) - radius*radius;
float discriminant = b*b - 4*a*c;
if (discriminant < 0)
return false;
else
float t0;
t0 = std::max((-b + sqrt(discriminant) ) / (2.0f*a),(-b - sqrt(discriminant) ) / (2.0f*a));
*t = t0;
return true;
Vec3 Sphere::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular)
*intensity = 50.0f;
*Diffusecolor = cl;
*Specular = Vec3(0.7f, 0.7f, 0.7);
return (p0-position);
class Triangle:public Figure
public:
Vec3 v0;
Vec3 v1;
Vec3 v2;
Vec3 norm;
Vec3 ed0,ed1;
float u,v,w;
Triangle(void);
Triangle(Vec3 a,Vec3 b,Vec3 c,Vec3 col);
bool intersection(float* t,Vec3 origin,Vec3 direction);
bool intersectionShadow(float* t,Vec3 origin,Vec3 direction);
Vec3 calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular);
;
Triangle::Triangle()
v0 = Vec3(0,0,0);
v1 = Vec3(0,0,0);
v2 = Vec3(0,0,0);
Triangle::Triangle(Vec3 a, Vec3 b, Vec3 c, Vec3 col)
v0 = a;
v1 = b;
v2 = c;
cl = col;
bool Triangle::intersection(float *t, Vec3 origin,Vec3 direction)
ed0 = v1-v0;
ed1 = v2-v0;
Vec3 r_o = origin-v0;
Vec3 r_ed = direction.cross(ed1);
u = r_o.dot(r_ed)/ed0.dot(r_ed);
Vec3 r0_ed0 = r_o.cross(ed0);
float rd_r0_ed0 = direction.dot(r0_ed0);
v = rd_r0_ed0/ed0.dot(r_ed);
float ed_r0_ed0 = ed1.dot(r0_ed0);
float t0 = ed_r0_ed0/ed0.dot(r_ed);
w = 1-u-v;
if((u<0) || (u>1))
return false;
else if((v<0) || (u+v>1))
return false;
else
*t = t0;
return true;
Vec3 Triangle::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular)
*intensity = 0;
*Diffusecolor = Vec3(0.7, 0.7, 0.7);
*Specular = cl;
//https://www.tjhsst.edu/~dhyatt/supercomp/n310.html
Vec3 d1 = Vec3(v1.x()-v0.x(),v1.y()-v0.y(),v1.z()-v0.z());
Vec3 d2 = Vec3(v2.x()-v1.x(),v2.y()-v1.y(),v2.z()-v1.z());
Vec3 n = (d1.cross(d2));
return n ;
bool Triangle::intersectionShadow(float* t,Vec3 origin,Vec3 direction)
return false;
using Colour = Vec3; // RGB Value
Colour red() return Colour(1.0f, 0.0f, 0.0f);
Colour white() return Colour(1.0f, 1.0f, 1.0f);
Colour black() return Colour(0.0f, 0.0f, 0.0f);
uchar BoundPixelValue(int shading)
if (shading < 0) return 0;
if (shading >= 255) return 255;
return shading;
Vec3 scalar_multiply(Vec3 b,float v)
return Vec3(b.x()*v,b.y()*v,b.z()*v);
int main(int, char**)
Vec3 v0 = Vec3(-1.0f,-1.0f,-1.0f);
Vec3 v1 = Vec3(-1.0f,-1.0f,-2.0f);
Vec3 v2 = Vec3(-1.0f,1.0f,-1.0f);
Vec3 v3 = Vec3(-1.0f,1.0f,-2.0f);
Vec3 v4 = Vec3(1.0f,-1.0f,-1.0f);
Vec3 v5 = Vec3(1.0f,-1.0f,-2.0f);
Vec3 v6 = Vec3(1.0f,1.0f,-2.0f);
Vec3 v7 = Vec3(1.0f,1.0f,-1.0f);
Vec3 point_0 = Vec3();
Figure* figurelist[12];
//sphere
figurelist[0]=new Sphere(Vec3(-0.2f,0.3f,-1.5f),0.3f,Vec3(1.000f, 0.196f, 0.000f));
figurelist[1]=new Sphere(Vec3(0.5f,-0.3f,-1.3f),0.4f,Vec3(0.054f, 0.172f, 0.847f));
//floor
figurelist[2]=new Triangle(v1,v0,v2,Vec3(0.752f, 0.713f, 0.823f));
figurelist[3]=new Triangle(v2,v3,v1,Vec3(0.752f, 0.713f, 0.823f));
//left
figurelist[4]=new Triangle(v5,v1,v0,Vec3(0.749f, 0.105f, 0.101f));
figurelist[5]=new Triangle(v0,v4,v5,Vec3(0.749f, 0.105f, 0.101f));
//back
figurelist[6]=new Triangle(v5,v1,v3,Vec3(0.925f, 0.639f, 0.454f));
figurelist[7]=new Triangle(v3,v6,v5,Vec3(0.925f, 0.639f, 0.454f));
//right
figurelist[8]=new Triangle(v7,v6,v3,Vec3(0.415f, 0.733f, 0.164f));
figurelist[9]=new Triangle(v3,v2,v7,Vec3(0.415f, 0.733f, 0.164f));
//top
figurelist[10]=new Triangle(v5,v6,v7,Vec3(0.925f, 0.639f, 0.454f));
figurelist[11]=new Triangle(v7,v4,v5,Vec3(0.925f, 0.639f, 0.454f));
int wResolution = 640;
int hResolution = 480;
// #rows = hResolution, #cols = wResolution
Image<Colour> image(hResolution, wResolution);
Vec3 llc= Vec3(-1.0,-1.0,-1.0);
Vec3 urc = Vec3(1.0,1.0,-1.0);
Vec3 CameraPos = Vec3(0,0,0);
Vec3 sphere_amient(0.960, 0.968, 0.811);
for (int row = 0; row < image.rows(); ++row)
for (int col = 0; col < image.cols(); ++col)
float u = float(row+0.5)/float(image.rows());
float v = float(col+0.5)/float(image.cols());
Vec3 PointPos = Vec3(llc(0) + u * (urc.x() - llc.x()), llc.y() + v * (urc.y() - llc.y()), -1);
Vec3 direction=(PointPos-CameraPos).normalized();
float minT = INFINITY;
int figureHit = -1;
float t0=0.0;
for (int k =0;k<sizeof (figurelist)/sizeof (figurelist[0]);k++)
bool hit = figurelist[k]->intersection(&t0,CameraPos,direction);
if(hit && t0<minT)
minT = t0;
figureHit = k;
if(figureHit != -1)
Vec3 p0 = CameraPos+minT*direction;
Vec3 lightSource=Vec3(2.0f,0.0f,-1.0f);
float lightIntensity=0.7f;
Vec3 diffuseColour(0.0f, 0.392f, 0.0f);
Vec3 specularColour(0.0,0.0,0.0);
float intensity = 0;
//ambient Colour for shadows
Vec3 AmbientColour = figurelist[figureHit]->cl.cross(Vec3(0.1f, 0.1f, 0.1f));
//Diffuse Lightning
Vec3 light_direction = (lightSource-p0).normalized();
Vec3 Normal = Vec3(figurelist[figureHit]->calculateNormal(p0,&intensity,&diffuseColour,&specularColour)).normalized();
float diffuse_term =std::max(0.0f,light_direction.dot(Normal));
Vec3 diffuse = (diffuseColour*lightIntensity*diffuse_term);
//Specular Highlights
Vec3 e = (p0-CameraPos).normalized();
Vec3 R = (e+light_direction).normalized();
float dot2 = std::max(0.0f,R.dot(Normal));
Vec3 specular = specularColour*lightIntensity*pow(dot2,intensity);
Vec3 shadow_direction = p0-light_direction;
float bias = 0.001f;
Vec3 p_shadow = p0+Normal;
//For hard shadows
int lightHit = -1;
for ( int i=0;i<sizeof (figurelist)/sizeof (figurelist[0]);i++)
bool lightRayHit = figurelist[i]->intersection(&t0,p_shadow,shadow_direction);
if(lightRayHit && t0<minT)
minT = t0;
lightHit = i;
if(lightHit != -1)
image(row,col) = AmbientColour;
else
image(row,col) = [enter image description here][1]specular+diffuse;
else
image(row,col)=white();
bmpwrite("../../out.bmp", image);
imshow(image);
return EXIT_SUCCESS;
附件是我得到的输出图像。这是应用阴影跟踪后的图像:
还有没有阴影的原图:
【问题讨论】:
【参考方案1】:应该是这个问题:
Vec3 shadow_direction = p0-light_direction;
p0
是一个位置,light_direction
是一个方向,因此,结果是一个position
。但是你把它作为一个方向。而是这样做:
Vec3 shadow_direction = -light_direction;
还有
float bias = 0.001f;
Vec3 p_shadow = p0+Normal;
应该是
Vec3 p_shadow = p0 + bias * Normal;
【讨论】:
我试过这个,但仍然没有得到阴影,可能是我的代码/算法中的其他问题以上是关于没有得到正确的阴影位置,基于 CPU 的光线追踪的主要内容,如果未能解决你的问题,请参考以下文章