C++ OpenGL: шейдинг трассировки лучей некорректно
Я студент CS, и для нашего финала нам сказали построить отражения на нескольких сферах с помощью трассировки лучей. Это почти буквально то, что мы получили для указаний, кроме изображения того, как оно должно выглядеть, когда закончите. Поэтому мне нужны сферы, с отражениями (использующими трассировку лучей), нанесенными на них с надлежащей штриховкой от света.
Ну, у меня все это работает, за исключением нескольких сфер и того факта, что это не похоже на картину, которую он дал нам для рубрики.
Я не очень уверен, что делать с несколькими сферами, но я бы сказал, что мне нужно хранить их в двумерном массиве и изменять несколько разделов кода.
Я подумал, что нужно изменить сферу_intersect и find_reflect, чтобы указать, какая сфера анализируется. Затем измените find_reflect, чтобы при вычислении нового вектора u его начальная точка (P0) также обновлялась. Затем, если луч попадает на сферу, ему нужно будет посчитать, сколько раз луч был отражен. В какой-то момент прекратить (возможно, через 10 раз), а затем я просто нарисую пиксель. Для дополнительного прикосновения я хотел бы добавить сплошные цвета к сферам, которые, как мне кажется, требовали бы нахождения нормали к сфере.
В любом случае я собираюсь прикрепить его фотографию, мою фотографию и исходный код. Надеюсь, кто-нибудь может помочь мне в этом.
Заранее спасибо!
Профессорские сферы
Мои сферы
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
#include <string>
#define screen_width 750
#define screen_height 750
#define true 1
#define false 0
#define perpendicular 0
int gridXsize = 20;
int gridZsize = 20;
float plane[] = {0.0, 1.0, 0.0, -50.0,};
float sphere[] = {250.0, 270.0, -100.0, 100.0};
float eye[] = {0.0, 400.0, 550.0};
float light[] = {250.0, 550.0, -200.0};
float dot(float *u, float *v)
{
return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
}
void norm(float *u)
{
float norm = sqrt(abs(dot(u,u)));
for (int i =0; i <3; i++)
{
u[i] = u[i]/norm;
}
}
float plane_intersect(float *u, float *pO)
{
float normt[3] = {plane[0], plane[1], plane[2]};
float s;
if (dot(u,normt) == 0)
{
s = -10;
}
else
{
s = (plane[3]-(dot(pO,normt)))/(dot(u,normt));
}
return s;
}
float sphere_intersect(float *u, float *pO)
{
float deltaP[3] = {sphere[0]-pO[0],sphere[1]-pO[1],sphere[2]-pO[2]};
float deltLen = sqrt(abs(dot(deltaP,deltaP)));
float t=0;
float answer;
float det;
if ((det =(abs(dot(u,deltaP)*dot(u,deltaP))- (deltLen*deltLen)+sphere[3]*sphere[3])) < 0)
{
answer = -10;
}
else
{
t =-1*dot(u,deltaP)- sqrt(det) ;
if (t>0)
{
answer = t;
}
else
{
answer = -10;
}
}
return answer;
}
void find_reflect(float *u, float s, float *pO)
{
float n[3] = {pO[0]+s *u[0]-sphere[0],pO[1]+s *u[1]-sphere[1],pO[2]+s *u[2]- sphere[2]};
float l[3] = {s *u[0],s *u[1],s *u[2]};
u[0] =(2*dot(l,n)*n[0])-l[0];
u[1] = (2*dot(l,n)*n[1])-l[1];
u[2] = (2*dot(l,n)*n[2])-l[2];
}
float find_shade(float *u,float s, float *pO)
{
float answer;
float lightVec[3] = {light[0]-(pO[0]+s *u[0]), light[1]-(pO[1]+s *u[1]), light[2]-(pO[2]+s *u[2])};
float n[3] = {pO[0]+s *u[0]-sphere[0],pO[1]+s *u[1]-sphere[1],pO[2]+s *u[2]-sphere[2]};
answer = -1*dot(lightVec,n)/(sqrt(abs(dot(lightVec,lightVec)))*sqrt(abs(dot(n,n))));
return answer;
}
void init()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,screen_width,0,screen_height);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
for (int i=0; i < screen_width; i++)
{
for (int j=0; j < screen_height; j++)
{
float ray[3] = {1*(eye[0]-i),-1*(eye[1]-j),1*eye[2]};
float point[3] = {i,j,0};
norm(ray);
int plotted = false;
while (!plotted)
{
float s_plane = plane_intersect(ray, point);
float s_sphere = sphere_intersect(ray, point);
if (s_plane <= 0 && s_sphere <=0)
{
glColor3f(0,0,0);
glBegin(GL_POINTS);
glVertex3f(i,j,0);
glEnd();
plotted = true;
}
else if (s_sphere >= 0 && (s_plane <=0 || s_sphere <= s_plane))
{
find_reflect(ray, s_sphere, point);
}
else if (s_plane >=0 && (s_sphere <=0 ||s_plane <= s_sphere))
{
float shade = find_shade(ray, s_plane, point);
float xx = s_plane*ray[0] + eye[0];
float z = s_plane*ray[2] + eye[2];
if (abs((int)xx/gridXsize)%2 == abs((int)z/gridZsize)%2)
{
glColor3f(shade,0,0);
}
else
{
glColor3f(shade,shade,shade);
}
glBegin(GL_POINTS);
glVertex3f(i,j,0);
glEnd();
plotted = true;
}
}
}
}
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutCreateWindow("Ray Trace with Sphere.");
glutInitWindowSize(screen_width,screen_height);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutDisplayFunc(display);
init();
glutMainLoop();
return 0;
}
1 ответ
Профессор не сказал вам слишком много, потому что такая тема тысячи раз освещается в Интернете, просто посмотрите "Whited Raytracing";) Это домашнее задание, и 5 миллионов поисков в поиске решат проблему... Некоторые подсказки помочь, не выполняя для вас домашнее задание
Делайте это шаг за шагом, не пытайтесь воспроизвести изображение за один шаг
- Получите одну сферу, работающую, если попал в плоскость зеленого пикселя, сфера красного пикселя, ничего, черный. Этого достаточно, чтобы правильно вычислить пересечения. Из вашей картинки видно, что у вас нет правильных пересечений, для начала
- То же, что и предыдущий, с несколькими сферами. То же, что и одна сфера: проверить пересечение для всех объектов, сохранить ближайший перекресток с точки зрения.
- То же, что и в предыдущем примере, но также рассчитывается количество света, получаемого для каждого найденного пересечения, чтобы иметь оттенок красного для сфер и оттенок зеленого для плоскости. (подсказка: точечный продукт ^^)
- Текстура для самолета
- Отражение для сфер. Подсказка: зеркало не отражает 100% света, только его часть.