diff --git a/Object.h b/Object.h index f3cd7c8..c89dd63 100644 --- a/Object.h +++ b/Object.h @@ -1,7 +1,26 @@ #pragma once #include "Vector3.h" class Material; -class Object { +class LinkedList { +public: + LinkedList* mNext; + LinkedList() { + mNext = nullptr; + } + template + T* Next() { + return (T*)mNext; + } + void Append(LinkedList* node) { + if (mNext == nullptr) { + mNext = node; + } + else { + mNext->Append(node); + } + } +}; +class Object : public LinkedList{ public: Geometry *mGeometry; Material *mMaterial; diff --git a/Scene.cpp b/Scene.cpp index f749aba..ea2169a 100644 --- a/Scene.cpp +++ b/Scene.cpp @@ -10,16 +10,17 @@ static int sTotalPixelCount = 0; static int sViewportWidth = 0, sViewportHeight = 0; static Camera* sCamera = nullptr; -Sphere sphere(Vector3(0.0f, 0.0f, -5.0f), 0.5f); +Sphere sphere(Vector3(0.0f, 0.5f, 0.0f), 0.5f); static Object* sRootObject = nullptr; static Material* lambert = nullptr; static int sSampleCount = 64; +static int sMaxBounceTime = 30; void AddObject(Object* object) { if (sRootObject == nullptr) { sRootObject = object; } else { - //TODO + sRootObject->Append(object); } } void Init(int width, int height) @@ -28,7 +29,9 @@ void Init(int width, int height) sViewportWidth = width; sViewportHeight = height; sCamera = new Camera(45.0f, float(width) / float(height)); - sCamera->LookAt(Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 0.0f, -1.0f), Vector3(0.0f, 1.0f, 0.0f)); + sCamera->LookAt(Vector3(3.0f, 1.0f, 3.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 1.0f, 0.0f)); + Material* earth_material = new LamberMaterial(Vector3(0.5f, 0.3f, 0.1f)); + AddObject(new Object(new Sphere(Vector3(0.0f, -1000.0f, 0.0), 1000.0f), earth_material)); lambert = new LamberMaterial(Vector3(0.1f, 0.4f, 0.7f)); AddObject(new Object(&sphere, lambert)); } @@ -50,16 +53,28 @@ Vector3 GetEnviromentColor(const Ray& input_ray) { return factor * top_color + (1.0f - factor) * bottom_color; } -Vector3 GetColor(const Ray& input_ray) { +Vector3 RenderOneSample(const Ray& input_ray, int bounce_time) { HitPoint hit_point; - if (sRootObject->HitTest(input_ray, 0.01f, 100.0f, hit_point)) { - Ray scatter_ray; - if (hit_point.mMaterial->Scatter(input_ray, hit_point, scatter_ray)) { - return GetColor(scatter_ray); + float max_distance = 1000.0f; + Object* current_object = sRootObject; + Object* hitted_object = nullptr; + + while (current_object != nullptr) { + if (current_object->HitTest(input_ray, 0.01f, max_distance, hit_point)) { + max_distance = hit_point.mDistance; + hitted_object = current_object; } + current_object = current_object->Next(); } - - return GetEnviromentColor(input_ray); + if (hitted_object != nullptr) { + if(bounce_time < sMaxBounceTime){ + Ray scatter_ray; + if (hit_point.mMaterial->Scatter(input_ray, hit_point, scatter_ray)) { + return RenderOneSample(scatter_ray, bounce_time + 1); + } + } + } + return GetEnviromentColor(input_ray) * input_ray.mLightAttenuation; } void RenderOnePixel(int pixel_index) { @@ -73,7 +88,7 @@ void RenderOnePixel(int pixel_index) { float u = (float(x) + offset_u) / sViewportWidth; float v = (float(y) + offset_v) / sViewportHeight; Ray ray = sCamera->GetRay(u, v); - Vector3 current_color = GetColor(ray); + Vector3 current_color = RenderOneSample(ray,0); color = color + current_color; } color /= sSampleCount; diff --git a/Sphere.cpp b/Sphere.cpp index 5507489..bb01341 100644 --- a/Sphere.cpp +++ b/Sphere.cpp @@ -23,17 +23,19 @@ bool Sphere::HitTest(const Ray& input_ray, float min_distance, float max_distanc bool isHited = false; float distance = -1.0f; if (determinant > 0.0f) { - distance = (-b - sqrtf(determinant))/ 2.0f; + distance = (-b - sqrtf(determinant))/ 2.0f *a; if (distance > min_distance && distance < max_distance) { isHited = true; } - distance = (-b + sqrtf(determinant)) / 2.0f; - if (distance > min_distance && distance < max_distance) { - isHited = true; + else { + distance = (-b + sqrtf(determinant)) / 2.0f*a; + if (distance > min_distance && distance < max_distance) { + isHited = true; + } } } else if (determinant == 0.0f) { - distance = -b / 2.0f; + distance = -b / (2.0f * a); if (distance > min_distance && distance < max_distance) { isHited = true; }