Курсовая работана тему:«Отрисовка сцены «Отражающиеся дорожки» алгоритмом обратнойтрассировки лучей»
Екатеринбург 2011 г.
Алгоритмработы программы
1) Заранеев программе заданы объекты и источники света, тип поверхности объектов, размерыокна для отображения изображения, цвет фона, а также координаты точки обзора;
2) Затемдля каждого пикселя изображения рассчитываем цвет, для этого направляем лучи;
3) Еслизаданный луч не пересекает ни одного объекта сцены, то закрашиваем данныйпиксель в цвет фона.
4) Еслиже заданный луч пересекает какой-либо объект сцены, то обращаемся к методукласса Ray рассчитывающему цвет в точке пересечения. Он в свою очередьобращается к аналогичному методу класса Sphere, который находиткоординаты точки пересечения луча с объектом, увеличивает длину луча (вектора)до точки пересечения с объектом, находит вектор нормали к поверхности в точкепересечения.
5) Программапередает все найденные выше параметры в метод класса Surface, который рассчитываетцвет в данной точке. В зависимости от свойств материала пересеченного объектаданный метод находит затененность, отражение, преломление в данной точке. Приналичии двух последних генерируется новый луч, который трассируется (т.е.проходит заново пункты 3–5 данного алгоритма (рекурсия)). При трассировке этоголуча мы получаем цвет в данной точке, который модифицируется при помощикоэффициентов и возвращается в главную функцию для последующей отрисовки.
Блок-схемапрограммы
/>
программатрассировка тень освещение
Заключение
В результатеработы над программой были выполнены поставленные требования: реализованатрассировка лучей с просчетом теней, освещения, отражения, преломления лучей,что является несомненным достоинством программы. Также задан объект – сфера.Недостатком программы считаю то, что не рассмотрены такие источники света, каксвет окружающей среды и направленный свет.
Приложение1
/>
Полученноеизображение
Приложение2
Листинг Light.java
package objects;
/**
*
* @authorАлексей
*/
// Источниксвета
publicclass Light {
publicWorkVector lightvec; // позиция истоника света
publicfloat lightred, lightgreen, lightblue; // цвет источника света
publicLight (WorkVector v, float r, float g, float b) {
lightvec= v;
lightred= r;
lightgreen= g;
lightblue= b;
}
}
Приложение3
Листинг Ray.java
packageobjects;
importjava.awt. Color;
importjava.util. Vector;
/**
*
*@author Алексей
*/
//Луч
publicclass Ray {
floatmax_distance = Float.MAX_VALUE; // максимальная значение для currentDistance луча
WorkVectorinitRay; // начало луча
WorkVectorfinalRay; // направление луча
floatcurrentDistance; // Текущее расстояние до обьекта
Sphereobject; // Обьект, с которым произошло столкновение луча
publicRay (WorkVector eye, WorkVector dir) {
initRay= new WorkVector(eye);
finalRay= WorkVector.normalize(dir);
}
publicboolean trace (Vector objects) {
currentDistance= max_distance;
object= null;
for(int i = 0; i
Sphereobject = (Sphere) objects.elementAt(i);
object.intersection(this); //проверка пересечения с объектом
}
return(object!= null); // возвращение true если было пересечение
}
publicfinal Color Shade (Vector lights, Vector objects, Color bgnd) {
returnobject. Shade (this, lights, objects, bgnd);
}
}
Приложение4
Листинг Sphere.java
packageobjects;
importjava.awt. Color;
importjava.util. Vector;
/**
*
*@author Алексей
*/
//Сфера
publicclass Sphere {
Surfacesurface; // тип поверхности
WorkVectorcenter; // положение сферы
floatradius; // радиус сферы
publicSphere (Surface s, WorkVector c, float r) {
surface= s;
center= c;
radius= r;
}
publicboolean intersection (Ray ray) { // поиск пересечения со сферой
WorkVectordv = center.sub (ray.initRay);
floatv = ray.finalRay.dot(dv);
// Проверка того, можетли вообще произойти пересечение
if(v – radius > ray.currentDistance)
return false;
//нахождение суммы квадрата v и квадратов элементов вектора dv
float t =radius*radius + v*v – dv.x*dv.x – dv.y*dv.y – dv.z*dv.z;
if (t
return false;
//проверка знака пересечения и того что оно самое близкое
t= v – ((float) Math.sqrt(t));
if((t > ray.currentDistance) || (t
returnfalse;
ray.currentDistance= t; // расстояние до обьекта пересечения приравнивается к currentDistance
ray.object =this; // текущий обьект становится объектом пересечения с лучем
returntrue;
}
publicColor Shade (Ray ray, Vector lights, Vector objects, Color bgnd) {
// вызывается, если быланайдена точка пересечения обьекта и луча
// направлениелуча увеличивается на расстояние до точки пересечения
floatpx = ray.initRay.x + ray.currentDistance*ray.finalRay.x;
floatpy = ray.initRay.y + ray.currentDistance*ray.finalRay.y;
floatpz = ray.initRay.z + ray.currentDistance*ray.finalRay.z;
WorkVectorp = new WorkVector (px, py, pz); // нахождение точки пересечения луча и обьекта
WorkVectorv = new WorkVector (-ray.finalRay.x, – ray.finalRay.y, – ray.finalRay.z); //нахождение вектора – отрицательного направления луча
WorkVectorn = new WorkVector((px – center.x), (py – center.y), (pz – center.z)); // находится вектор, которому принадлежит нормаль в текущей точке поверхности
n.normalize(); //получаем нормаль
returnsurface. Shade (p, n, v, lights, objects, bgnd); // возвращяестя цвет в данной точке
}
}
Приложение5
Листинг Surface.java
packageobjects;
importjava.awt. Color;
importjava.util. Vector;
/**
*
*@author Алексей
*/
publicclass Surface {
publicfloat ir, ig, ib; // цвет обьекта
publicfloat kRasseivania, kOtragenia, ns; // константы для освещения обьекта
publicfloat kt, kr; // коэффициенты материала
privatefloat TINY = 0.001f;
privatefloat I255 = 0.00392156f;
privateWorkVector luch;
publicSurface (float rval, float gval, float bval, float d,
floats, float n, float r, float t) {
ir = rval; ig= gval; ib = bval; // задание цвета поверхности
kRasseivania= d; // рассеивающая составляющая поверхности
kOtragenia =s; // отражающая составляющая поверхности
ns= n;
kr= r*I255;
kt= t*I255;
}
publicColor Shade (WorkVector p, WorkVector n, WorkVector v, Vector lights, Vectorobjects, Color bgnd) // возвращает полученный цвет обьекта в точке
// точка пересечения (p)
// нормальв точке пересечения (n)
// векторнаправленный в точку из которой пришел лучь (v)
{
float r = 0; //обнуляем
float g = 0;
float b = 0;
for (int i =0; i
Lightlight = (Light) lights.elementAt(i); // взятие текущего истчоника освещения
luch = newWorkVector (light.lightvec.sub(p)); // задаем вектор luch как вектор отисточника освещения до точки обьекта
luch.normalize(); //нормализируем вектор luch чтобы получить вектор направления от источникаосвещения к точке обьекта
//ЗАТЕНЕННОСТЬ
WorkVectorpoffset = p.add (luch.mul(TINY)); // к основанию нового луча добавляетсяочень мальенький вектор luch чтобы при проверке не пересечь сам себя
Ray shadowRay= new Ray (poffset, luch); // создание луча проверки на затененность
if(shadowRay.trace(objects)) // в случае пеоесечения какого либо обьекта
continue; //переходим к следующему источнику освещения
float lambert= WorkVector.dot (n, luch); // нахождение коэффициента освещенности взависимости от нормали обьекта в данной точке и напраления источника света
if(lambert > 0) {
if(kRasseivania > 0) {
floatdiffuse = kRasseivania*lambert;
r+= diffuse*ir*light.lightred;
g+= diffuse*ig*light.lightgreen;
b+= diffuse*ib*light.lightblue;
}
if(kOtragenia > 0) {
lambert*= 2;
floatspec = v.dot (lambert*n.x – luch.x, lambert*n.y – luch.y, lambert*n.z – luch.z);
if(spec > 0) {
spec= kOtragenia*((float) Math.pow((double) spec, (double) ns));
r+= spec*light.lightred;
g+= spec*light.lightgreen;
b +=spec*light.lightblue;
}
}
}
}
//ОТРАЖЕНИЕ
if (kr >0) { // если коэффициент отражения больше нуля, то обьект может отражать
float t =v.dot(n); // получение результата скалярного произведения векторанаправленного к началу источника луча и нормали поверхности в данной точке
if(t > 0) {
t*= 2;
WorkVectorreflect = new WorkVector (n.mul(t).sub(v));
WorkVectorpoffset = new WorkVector (p.add (reflect.mul(TINY)));
RayreflectedRay = new Ray (poffset, reflect);
if(reflectedRay.trace(objects)) {
Colorrcolor = reflectedRay. Shade (lights, objects, bgnd);
r+= kr*rcolor.getRed();
g+= kr*rcolor.getGreen();
b+= kr*rcolor.getBlue();
}else {
r+= kr*bgnd.getRed();
g+= kr*bgnd.getGreen();
b+= kr*bgnd.getBlue();
}
}
}
//ПРИЛОМЛЕНИЕ
if(kt > 0) {
WorkVectortr;
WorkVectorincident = v.add(p);
floateta = (float) 0.7;
floatc1 = incident.mul(-1).dot(n);
floatc2;
c2= 1 – eta*eta*(1-c1*c1);
if(c2 > 0.0) {
c2= (float) (Math.sqrt(c2));
floatmaae = (eta*c1 – c2);
tr= incident.mul(eta).add (n.mul(maae));
tr.normalize();
WorkVectorpoffset = p.add (n.mul(-TINY));
RayreflectedRay = new Ray (poffset, tr);
if(reflectedRay.trace(objects)) {
Colorrcolor = reflectedRay. Shade (lights, objects, bgnd);
r+= kt*rcolor.getRed();
g+= kt*rcolor.getGreen();
b+= kt*rcolor.getBlue();
}else {
r+= kt*bgnd.getRed();
g+= kt*bgnd.getGreen();
b+= kt*bgnd.getBlue();
}
}
}
// чтобыизбежать выход за границы
r = (r > 1f)? 1f: r;
r= (r
g= (g > 1f)? 1f: g;
g= (g
b= (b > 1f)? 1f: b;
b= (b
returnnew Color (r, g, b); // возвращение цвета точки
}
}
Приложение6
ЛистингWorkVector.java
packageobjects;
/**
*
*@author Алексей
*/
publicclass WorkVector {
publicfloat x, y, z; // координаты вектора
publicWorkVector() {}
publicWorkVector (float X, float Y, float Z) {
x= X;
y= Y;
z= Z;
}
publicWorkVector (WorkVector v) {
x= v.x;
y= v.y;
z= v.z;
}
//методы
publicfloat dot (WorkVector v) { // скалярное произведение
return(x*v.x + y*v.y + z*v.z);
}
publicfloat dot (float Bx, float By, float Bz) {
return(x*Bx + y*By + z*Bz);
}
publicstatic float dot (WorkVector A, WorkVector B) {
return(A.x*B.x + A.y*B.y + A.z*B.z);
}
publicWorkVector add (WorkVector A) { // Вектор сложения
returnnew WorkVector (x+A.x, y+A.y, z+A.z);
}
publicWorkVector sub (WorkVector A) { // Вектор разности
returnnew WorkVector (x-A.x, y-A.y, z-A.z);
}
publicWorkVector mul (float A) { // Вектор, умноженный на число
returnnew WorkVector (x*A, y*A, z*A);
}
publicWorkVector set (WorkVector A) { // Задание координат
returnnew WorkVector (A.x, A.y, A.z);
}
publicWorkVector set (float Ax, float Ay, float Az) {
returnnew WorkVector (Ax, Ay, Az);
}
publicWorkVector cross (WorkVector B) {
returnnew WorkVector (y*B.z – z*B.y, z*B.x – x*B.z, x*B.y – y*B.x);
}
publicWorkVector cross (float Bx, float By, float Bz) {
returnnew WorkVector (y*Bz – z*By, z*Bx – x*Bz, x*By – y*Bx);
}
publicWorkVector cross (WorkVector A, WorkVector B) {
returnnew WorkVector (A.y*B.z – A.z*B.y, A.z*B.x – A.x*B.z, A.x*B.y – A.y*B.x);
}
public floatlength() { // Нахождение длины вектора
return(float) Math.sqrt (x*x + y*y + z*z);
}
publicfloat length (WorkVector A) {
return(float) Math.sqrt (A.x*A.x + A.y*A.y + A.z*A.z);
}
publicvoid normalize() { // нормализация вектора
floatt = x*x + y*y + z*z;
if(t!= 0 && t!= 1) t = (float) (1 / Math.sqrt(t));
x*= t;
y*= t;
z*= t;
}
publicstatic WorkVector normalize (WorkVector A) {
floatt = A.x*A.x + A.y*A.y + A.z*A.z;
if(t!= 0 && t!= 1) t = (float) (1 / Math.sqrt(t));
returnnew WorkVector (A.x*t, A.y*t, A.z*t);
}
}
Приложение7
Листинг Main.java
packageray_tracing;
importobjects.*;
importjava.awt. Color;
importjava.awt. Frame;
importjava.awt. Graphics;
importjava.awt. Image;
importjava.awt.event. WindowAdapter;
importjava.awt.event. WindowEvent;
importjava.util. Vector;
/**
*
*@author Алексей
*/
publicclass Main {
finalstatic int kol_vo = 600;
staticImage screen;
staticGraphics gc;
staticVector listOfObjects;
staticVector listOfLights;
staticSurface currentSurface;
staticWorkVector eye, lookat, up; // векторы необходимые для задания проекции
staticfloat angle = 40; // угол обзора
staticColor background = new Color (0,0,0); // цвет фона
staticint width=640, height=480;
staticFrame frame = new Frame («Raytracing»); // создание фрейма для отображения
publicstatic void main (String[] args) {
frame.setSize(width, height);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
screen= frame.createImage (width, height);
gc= screen.getGraphics();
gc.setColor(frame.getBackground());
gc.fillRect(0, 0, width, height);
frame.addWindowListener(new WindowAdapter() {
@Override
publicvoid windowClosing (WindowEvent e) {
System.exit(0);
}
});
//задание списков обьектов и источников освещения
listOfObjects= new Vector (kol_vo, kol_vo);
listOfLights= new Vector (kol_vo, kol_vo);
//добавление источника освещения
listOfLights.addElement(new Light (new WorkVector((float) 2, (float) 2, (float) 1), 1, 1, 1));
listOfLights.addElement(new Light (new WorkVector((float) – 3, (float) 5, (float) 3), 1, 1, 1));
// добавления сфер насцену
for (int i=0;i
for (int j=0;j
{
// Заданиематериала для обьектов
currentSurface= new Surface (i*j*0.02f, 0.7f, i*j*0.01f, 0.4f, 0.4f, 10.0f, 0f, 0f);
//Добавление обьекта
listOfObjects.addElement(new Sphere (currentSurface, new WorkVector((float) i*(float) 1.0–9, (float) –5*(float) Math.sqrt((float) i)+7, (float) – j*j*(float) 1.00+(float) 6),(float) 0.8));
}
currentSurface= new Surface (0.6f, 0.6f, 0.4f, 0.2f, 0.4f, 10.0f, 1.0f, 0.2f);
listOfObjects.addElement(new Sphere (currentSurface, new WorkVector((float) 20, (float) 0, (float) –40), (float) 15));
// Задание необходимыхпеременных для рендера
eye = newWorkVector (5, 0, 40); // координаты точки обзора
lookat = newWorkVector (0, 0, 0); // координаты точки направления взгляда
up = newWorkVector (0, 1, 0); // вектор указывающий верх
Graphicsg = frame.getGraphics();
WorkVectorEye, Du, Dv, Vp;
WorkVectorlook = new WorkVector (lookat.x – eye.x, lookat.y – eye.y, lookat.z – eye.z);
floatfl = (float) (width / (2*Math.tan((0.5*angle)*Math.PI/180)));
Eye = eye;
Du =WorkVector.normalize (look.cross(up)); // вектор являющийсявспомогательным вектором для рендера «по оси х»
Dv =WorkVector.normalize (look.cross(Du)); // вектор являющийсявспомогательным вектором для рендера «по оси y»
Vp =WorkVector.normalize(look); // вектор являющийся вспомогательным векторомдля рендера «по оси z»
Vp= (Vp.mul(fl)).sub((((Du.mul(width)).add (Dv.mul(height))).mul (0.5f)));
for(int j = 0; j
for(int i = 0; i
WorkVectordir = new WorkVector(((Du.mul(i)).add (Dv.mul(j)).add(Vp))); // задание точки начала луча
Ray ray = newRay (Eye, dir); // задание вектора направления луча
if(ray.trace(listOfObjects)) { // если было найдено пересечение с обектом
gc.setColor (ray.Shade (listOfLights, listOfObjects, background)); // то точка получаетрасчитываемый цвет
} else {
gc.setColor(background); //Если не было пересечения с обьектами то точка имеет цвет фона
}
gc.drawLine (i,j, i, j); // рисование точки на буферном изображении
}
}
g.drawImage (screen,0, 0, frame); // отрисовка всего изображения на экране
}
}