Курсовая работа: Отрисовка сцены "Отражающиеся дорожки" алгоритмом обратной трассировки лучей
Название: Отрисовка сцены "Отражающиеся дорожки" алгоритмом обратной трассировки лучей Раздел: Рефераты по информатике, программированию Тип: курсовая работа |
Курсовая работана тему:«Отрисовка сцены «Отражающиеся дорожки» алгоритмом обратной трассировки лучей»Екатеринбург 2011 г. Алгоритм работы программы 1) Заранее в программе заданы объекты и источники света, тип поверхности объектов, размеры окна для отображения изображения, цвет фона, а также координаты точки обзора; 2) Затем для каждого пикселя изображения рассчитываем цвет, для этого направляем лучи; 3) Если заданный луч не пересекает ни одного объекта сцены, то закрашиваем данный пиксель в цвет фона. 4) Если же заданный луч пересекает какой-либо объект сцены, то обращаемся к методу класса Ray рассчитывающему цвет в точке пересечения. Он в свою очередь обращается к аналогичному методу класса Sphere, который находит координаты точки пересечения луча с объектом, увеличивает длину луча (вектора) до точки пересечения с объектом, находит вектор нормали к поверхности в точке пересечения. 5) Программа передает все найденные выше параметры в метод класса Surface, который рассчитывает цвет в данной точке. В зависимости от свойств материала пересеченного объекта данный метод находит затененность, отражение, преломление в данной точке. При наличии двух последних генерируется новый луч, который трассируется (т.е. проходит заново пункты 3–5 данного алгоритма (рекурсия)). При трассировке этого луча мы получаем цвет в данной точке, который модифицируется при помощи коэффициентов и возвращается в главную функцию для последующей отрисовки. Блок-схема программы программа трассировка тень освещение Заключение В результате работы над программой были выполнены поставленные требования: реализована трассировка лучей с просчетом теней, освещения, отражения, преломления лучей, что является несомненным достоинством программы. Также задан объект – сфера. Недостатком программы считаю то, что не рассмотрены такие источники света, как свет окружающей среды и направленный свет. Приложение 1
Полученное изображение Приложение 2 Листинг Light.java packageobjects; /** * * @author Алексей */ // Источник света public class Light { public WorkVector lightvec; // позицияистоникасвета public float lightred, lightgreen, lightblue; // цветисточникасвета public Light (WorkVector v, float r, float g, float b) { lightvec = v; lightred = r; lightgreen = g; lightblue = b; } } Приложение 3 Листинг Ray.java package objects; import java.awt. Color; import java.util. Vector; /** * * @author Алексей */ // Луч public class Ray { float max_distance = Float.MAX_VALUE; // максимальнаязначениедля currentDistance луча WorkVector initRay; // началолуча WorkVector finalRay; // направлениелуча float currentDistance; // Текущее расстояние до обьекта Sphere object; // Обьект, с которым произошло столкновение луча public Ray (WorkVector eye, WorkVector dir) { initRay = new WorkVector(eye); finalRay = WorkVector.normalize(dir); } public boolean trace (Vector objects) { currentDistance = max_distance; object = null; for (int i = 0; i < objects.size(); i++) { Sphere object = (Sphere) objects.elementAt(i); object.intersection(this); // проверка пересечения с объектом } return (object!= null); // возвращение true если было пересечение } public final Color Shade (Vector lights, Vector objects, Color bgnd) { return object. Shade (this, lights, objects, bgnd); } } Приложение 4 Листинг Sphere.java package objects; import java.awt. Color; import java.util. Vector; /** * * @author Алексей */ // Сфера public class Sphere { Surface surface; // типповерхности WorkVector center; // положениесферы float radius; // радиуссферы public Sphere (Surface s, WorkVector c, float r) { surface = s; center = c; radius = r; } public boolean intersection (Ray ray) { // поискпересечениясосферой WorkVector dv = center.sub (ray.initRay); float v = 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 < 0) return false; // проверка знака пересечения и того что оно самое близкое t = v – ((float) Math.sqrt(t)); if ((t > ray.currentDistance) || (t < 0)) return false; ray.currentDistance = t; // расстояниедообьектапересеченияприравниваетсякcurrentDistance ray.object = this; // текущий обьект становится объектом пересечения с лучем return true; } public Color Shade (Ray ray, Vector lights, Vector objects, Color bgnd) { // направление луча увеличивается на расстояние до точки пересечения float px = ray.initRay.x + ray.currentDistance*ray.finalRay.x; float py = ray.initRay.y + ray.currentDistance*ray.finalRay.y; float pz = ray.initRay.z + ray.currentDistance*ray.finalRay.z; WorkVector p = new WorkVector (px, py, pz); // нахождениеточкипересечениялучаиобьекта WorkVector v = new WorkVector (-ray.finalRay.x, – ray.finalRay.y, – ray.finalRay.z); // нахождениевектора– отрицательногонаправлениялуча WorkVector n = new WorkVector((px – center.x), (py – center.y), (pz – center.z)); // находитсявектор, которомупринадлежитнормальвтекущейточкеповерхности n.normalize(); // получаемнормаль return surface. Shade (p, n, v, lights, objects, bgnd); // возвращяестяцветвданнойточке } } Приложение 5 Листинг Surface.java package objects; import java.awt. Color; import java.util. Vector; /** * * @author Алексей */ public class Surface { public float ir, ig, ib; // цветобьекта public float kRasseivania, kOtragenia, ns; // константыдляосвещенияобьекта public float kt, kr; // коэффициентыматериала private float TINY = 0.001f; private float I255 = 0.00392156f; private WorkVector luch; public Surface (float rval, float gval, float bval, float d, float s, float n, float r, float t) { ir = rval; ig = gval; ib = bval; // задание цвета поверхности kRasseivania = d; // рассеивающая составляющая поверхности kOtragenia = s; // отражающая составляющая поверхности ns = n; kr = r*I255; kt = t*I255; } public Color Shade (WorkVector p, WorkVector n, WorkVector v, Vector lights, Vector objects, Color bgnd) // возвращаетполученныйцветобьектавточке // нормаль в точке пересечения (n) // вектор направленный в точку из которой пришел лучь (v) { float r = 0; // обнуляем float g = 0; float b = 0; for (int i = 0; i < lights.size(); i++) { // цикл, в котором расчитывается освещенность Light light = (Light) lights.elementAt(i); // взятиетекущегоистчоникаосвещения luch = new WorkVector (light.lightvec.sub(p)); // задаем вектор luch как вектор от источника освещения до точки обьекта luch.normalize(); // нормализируем вектор luch чтобы получить вектор направления от источника освещения к точке обьекта // ЗАТЕНЕННОСТЬ WorkVector poffset = 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) { float diffuse = kRasseivania*lambert; r += diffuse*ir*light.lightred; g += diffuse*ig*light.lightgreen; b += diffuse*ib*light.lightblue; } if (kOtragenia > 0) { lambert *= 2; float spec = 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; WorkVector reflect = new WorkVector (n.mul(t).sub(v)); WorkVector poffset = new WorkVector (p.add (reflect.mul(TINY))); Ray reflectedRay = new Ray (poffset, reflect); if (reflectedRay.trace(objects)) { Color rcolor = 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) { WorkVector tr; WorkVector incident = v.add(p); float eta = (float) 0.7; float c1 = incident.mul(-1).dot(n); float c2; c2 = 1 – eta*eta*(1-c1*c1); if (c2 > 0.0) { c2 = (float) (Math.sqrt(c2)); float maae = (eta*c1 – c2); tr = incident.mul(eta).add (n.mul(maae)); tr.normalize(); WorkVector poffset = p.add (n.mul(-TINY)); Ray reflectedRay = new Ray (poffset, tr); if (reflectedRay.trace(objects)) { Color rcolor = 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 < 0f)? 0f: r; g = (g > 1f)? 1f: g; g = (g < 0f)? 0f: g; b = (b > 1f)? 1f: b; b = (b < 0f)? 0f: b; return new Color (r, g, b); // возвращениецветаточки } } Приложение 6 Листинг WorkVector.java package objects; /** * * @author Алексей */ public class WorkVector { public float x, y, z; // координатывектора public WorkVector() {} public WorkVector (float X, float Y, float Z) { x = X; y = Y; z = Z; } public WorkVector (WorkVector v) { x = v.x; y = v.y; z = v.z; } // методы public float dot (WorkVector v) { // скалярноепроизведение return (x*v.x + y*v.y + z*v.z); } public float dot (float Bx, float By, float Bz) { return (x*Bx + y*By + z*Bz); } public static float dot (WorkVector A, WorkVector B) { return (A.x*B.x + A.y*B.y + A.z*B.z); } public WorkVector add (WorkVector A) { // Векторсложения return new WorkVector (x+A.x, y+A.y, z+A.z); } public WorkVector sub (WorkVector A) { // Векторразности return new WorkVector (x-A.x, y-A.y, z-A.z); } public WorkVector mul (float A) { // Вектор, умноженныйначисло return new WorkVector (x*A, y*A, z*A); } public WorkVector set (WorkVector A) { // Заданиекоординат return new WorkVector (A.x, A.y, A.z); } public WorkVector set (float Ax, float Ay, float Az) { return new WorkVector (Ax, Ay, Az); } public WorkVector cross (WorkVector B) { return new WorkVector (y*B.z – z*B.y, z*B.x – x*B.z, x*B.y – y*B.x); } public WorkVector cross (float Bx, float By, float Bz) { return new WorkVector (y*Bz – z*By, z*Bx – x*Bz, x*By – y*Bx); } public WorkVector cross (WorkVector A, WorkVector B) { return new 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 float length() { // Нахождение длины вектора return (float) Math.sqrt (x*x + y*y + z*z); } public float length (WorkVector A) { return (float) Math.sqrt (A.x*A.x + A.y*A.y + A.z*A.z); } public void normalize() { // нормализациявектора float t = x*x + y*y + z*z; if (t!= 0 && t!= 1) t = (float) (1 / Math.sqrt(t)); x *= t; y *= t; z *= t; } public static WorkVector normalize (WorkVector A) { float t = A.x*A.x + A.y*A.y + A.z*A.z; if (t!= 0 && t!= 1) t = (float) (1 / Math.sqrt(t)); return new WorkVector (A.x*t, A.y*t, A.z*t); } } Приложение 7 Листинг Main.java package ray_tracing; import objects.*; import java.awt. Color; import java.awt. Frame; import java.awt. Graphics; import java.awt. Image; import java.awt.event. WindowAdapter; import java.awt.event. WindowEvent; import java.util. Vector; /** * * @author Алексей */ public class Main { final static int kol_vo = 600; static Image screen; static Graphics gc; static Vector listOfObjects; static Vector listOfLights; static Surface currentSurface; static WorkVector eye, lookat, up; // векторынеобходимыедлязаданияпроекции static float angle = 40; // уголобзора static Color background = new Color (0,0,0); // цветфона static int width=640, height=480; static Frame frame = new Frame («Raytracing»); // созданиефреймадляотображения public static 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 public void 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<40; i++) for (int j=0; j<10; 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 = new WorkVector (5, 0, 40); // координаты точки обзора lookat = new WorkVector (0, 0, 0); // координаты точки направления взгляда up = new WorkVector (0, 1, 0); // вектор указывающий верх Graphics g = frame.getGraphics(); WorkVector Eye, Du, Dv, Vp; WorkVector look = new WorkVector (lookat.x – eye.x, lookat.y – eye.y, lookat.z – eye.z); float fl = (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 < height; j++) { for (int i = 0; i < width; i++) { WorkVector dir = new WorkVector(((Du.mul(i)).add (Dv.mul(j)).add(Vp))); // заданиеточкиначалалуча Ray ray = new Ray (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); // отрисовка всего изображения на экране } } |