Приложение 2 – листинг
// -----------------------------------------------------------
// common.h
// -----------------------------------------------------------
#include "math.h"
#include "stdlib.h"
typedef unsigned int Pixel;
inline float Rand(float a_Range) { return ((float)rand() / RAND_MAX) * a_Range; }
namespace Raytracer {
#define DOT(A,B) (A.x*B.x+A.y*B.y+A.z*B.z)
#define NORMALIZE(A) {float l=1/sqrtf(A.x*A.x+A.y*A.y+A.z*A.z);A.x*=l;A.y*=l;A.z*=l;}
#define LENGTH(A) (sqrtf(A.x*A.x+A.y*A.y+A.z*A.z))
#define SQRLENGTH(A) (A.x*A.x+A.y*A.y+A.z*A.z)
#define SQRDISTANCE(A,B) ((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z))
#define EPSILON 0.001f
#define TRACEDEPTH 6
#define PI 3.141592653589793238462f
class vector3
{
public:
vector3(): x(0.0f), y(0.0f), z(0.0f) {};
vector3(float a_X, float a_Y, float a_Z): x(a_X), y(a_Y), z(a_Z) {};
void Set(float a_X, float a_Y, float a_Z) { x = a_X; y = a_Y; z = a_Z; }
vector3 Normalize() { float l = 1.0f / Length(); x *= l; y *= l; z *= l; return *this; }
float Length() { return (float)sqrt(x * x + y * y + z * z); }
float SqrLength() { return x * x + y * y + z * z; }
float Dot(vector3 a_V) { return x * a_V.x + y * a_V.y + z * a_V.z; }
vector3 Cross(vector3 b) { return vector3(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x); }
void operator += (vector3& a_V) { x += a_V.x; y += a_V.y; z += a_V.z; }
void operator += (vector3* a_V) { x += a_V->x; y += a_V->y; z += a_V->z; }
void operator -= (vector3& a_V) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
void operator -= (vector3* a_V) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
void operator *= (float f) { x *= f; y *= f; z *= f; }
void operator *= (vector3& a_V) { x *= a_V.x; y *= a_V.y; z *= a_V.z; }
void operator *= (vector3* a_V) { x *= a_V->x; y *= a_V->y; z *= a_V->z; }
vector3 operator- () const { return vector3(-x, -y, -z); }
friend vector3 operator + (const vector3& v1, const vector3& v2) { return vector3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); }
friend vector3 operator - (const vector3& v1, const vector3& v2) { return vector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); }
friend vector3 operator + (const vector3& v1, vector3* v2) { return vector3(v1.x + v2->x, v1.y + v2->y, v1.z + v2->z); }
friend vector3 operator - (const vector3& v1, vector3* v2) { return vector3(v1.x - v2->x, v1.y - v2->y, v1.z - v2->z); }
friend vector3 operator * (const vector3& v, float f) { return vector3(v.x * f, v.y * f, v.z * f); }
friend vector3 operator * (const vector3& v1, vector3& v2) { return vector3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z); }
friend vector3 operator * (float f, const vector3& v) { return vector3(v.x * f, v.y * f, v.z * f); }
union
{
struct { float x, y, z; };
|
struct { float r, g, b; };
struct { float cell[3]; };
};
};
class plane
{
public:
plane(): N(0, 0, 0), D(0) {};
plane(vector3 a_Normal, float a_D): N(a_Normal), D(a_D) {};
union
{
struct
{
vector3 N;
float D;
};
float cell[4];
};
};
typedef vector3 Color;
}; // namespace Raytracer
// -----------------------------------------------------------
// surface.h
// -----------------------------------------------------------
#include "common.h"
namespace Raytracer {
class Surface
{
public:
Surface(int a_Width, int a_Height);
~Surface();
Pixel* GetBuffer() { return m_Buffer; }
int GetWidth() { return m_Width; }
int GetHeight() { return m_Height; }
void Print(int x1, int y1);
void Clear(Pixel a_Color);
private:
Pixel* m_Buffer;
int m_Width, m_Height;
};
}; // namespace Raytracer
// -----------------------------------------------------------
// surface.cpp
// -----------------------------------------------------------
#include "common.h"
#include "surface.h"
namespace Raytracer {
Surface::Surface(int a_Width, int a_Height):
m_Width(a_Width),
m_Height(a_Height)
{
m_Buffer = new Pixel[a_Width * a_Height];
}
Surface::~Surface()
{
delete [] m_Buffer;
}
void Surface::Clear(Pixel a_Color)
{
int s = m_Width * m_Height;
for (int i = 0; i < s; i++) m_Buffer[i] = a_Color;
}
void Surface::Print(int x1, int y1)
{
Pixel* t = m_Buffer + x1 + y1 * m_Width;
}
}; // namespace Raytracer
// -----------------------------------------------------------
// scene.h
// -----------------------------------------------------------
#include "raytracer.h"
namespace Raytracer {
// Возвращаемые значения метода Intersection (пересечение)
#define HIT 1 // Луч попал в примитив
#define MISS 0 // Промазал
#define INPRIM -1 // Зашел с тыла
#define MAXLIGHTS 10
// -----------------------------------------------------------
// Material class definition
// -----------------------------------------------------------
class Material
{
public:
Material();
void SetColor(Color& a_Color) { m_Color = a_Color; }
Color GetColor() { return m_Color; }
void SetDiffuse(float a_Diff) { m_Diff = a_Diff; }
void SetSpecular(float a_Spec) { m_Spec = a_Spec; }
void SetTransparency(float a_Refl) { m_Refl = a_Refl; }
float GetSpecular() { return m_Spec; }
float GetDiffuse() { return m_Diff; }
float GetTransparency() { return m_Refl; }
|
void SetDiffuseRefl(float a_DRefl) { m_DRefl = a_DRefl; }
float GetDiffuseRefl() { return m_DRefl; }
private:
Color m_Color;
float m_Refl, m_Refr;
float m_Diff, m_Spec;
float m_DRefl;
};
// -----------------------------------------------------------
// Primitive class definition
// -----------------------------------------------------------
class Primitive
{
public:
enum
{
SPHERE = 1,
PLANE,
RING
};
Primitive(): m_Name(0), m_Light(false), m_RayID(-1) {};
Material* GetMaterial() { return m_Material; }
void SetMaterial(Material* a_Mat) { m_Material = a_Mat; }
virtual int GetType() = 0;
virtual int Intersect(Ray& a_Ray, float& a_Dist) = 0;
virtual vector3 GetNormal(vector3& a_Pos) = 0;
virtual Color GetColor(vector3&) { return m_Material->GetColor(); }
virtual void Light(bool a_Light) { m_Light = a_Light; }
bool IsLight() { return m_Light; }
int GetLastRayID() { return m_RayID; }
void SetName(char* a_Name);
char* GetName() { return m_Name; }
protected:
Material* m_Material;
char* m_Name;
bool m_Light;
int m_RayID;
};
// -----------------------------------------------------------
// Sphere primitive class definition
// -----------------------------------------------------------
class Sphere: public Primitive
{
public:
int GetType() { return SPHERE; }
Sphere(vector3& a_Centre, float a_Radius);
~Sphere();
vector3& GetCentre() { return m_Centre; }
float GetSqRadius() { return m_SqRadius; }
int Intersect(Ray& a_Ray, float& a_Dist);
vector3 GetNormal(vector3& a_Pos) { return (a_Pos - m_Centre) * m_RRadius; }
Color GetColor(vector3& a_Pos);
private:
vector3 m_Centre;
float m_SqRadius, m_Radius, m_RRadius;
vector3 m_Ve, m_Vn, m_Vc;
};
// -----------------------------------------------------------
// PlanePrim primitive class definition
// -----------------------------------------------------------
class PlanePrim: public Primitive
{
public:
int GetType() { return PLANE; }
PlanePrim(vector3& a_Normal, float a_D);
~PlanePrim();
vector3& GetNormal() { return m_Plane.N; }
int Intersect(Ray& a_Ray, float& a_Dist);
vector3 GetNormal(vector3& a_Pos);
Color GetColor(vector3& a_Pos);
private:
plane m_Plane;
};
// -----------------------------------------------------------
// Ring primitive class definition
// -----------------------------------------------------------
class Ring: public Primitive
{
public:
int GetType() { return RING; }
Ring(vector3& a_Normal, vector3 &point, float R, float r);
~Ring();
vector3& GetNormal() { return m_Plane.N; }
int Intersect(Ray& a_Ray, float& a_Dist);
|
vector3 GetNormal(vector3& a_Pos);
Color GetColor(vector3& a_Pos);
private:
plane m_Plane;
vector3 point;
float R;
float r;
};
// -----------------------------------------------------------
// Scene class definition
// -----------------------------------------------------------
class Scene
{
public:
Scene(): m_Primitives(0), m_Primitive(0) {};
~Scene();
void InitScene();
int GetNrPrimitives() { return m_Primitives; }
Primitive* GetPrimitive(int a_Idx) { return m_Primitive[a_Idx]; }
private:
int m_Primitives;
Primitive** m_Primitive;
};
}; // namespace Raytracer
// -----------------------------------------------------------
// scene.cpp
// -----------------------------------------------------------
#include "common.h"
#include "string.h"
#include "scene.h"
#include "raytracer.h"
#include "stdio.h"
namespace Raytracer {
// -----------------------------------------------------------
// Primitive реализация
// -----------------------------------------------------------
void Primitive::SetName(char* a_Name)
{
delete m_Name;
m_Name = new char[strlen(a_Name) + 1];
strcpy(m_Name, a_Name);
}
// -----------------------------------------------------------
// Material реализация
// -----------------------------------------------------------
Material::Material():
m_Color(Color(0.2f, 0.2f, 0.2f)),
m_Refl(0), m_Diff(0.2f), m_Spec(0.8f),
m_DRefl(0)
{
}
// -----------------------------------------------------------
// Sphere примитив
// -----------------------------------------------------------
Sphere::Sphere(vector3& a_Centre, float a_Radius):
m_Centre(a_Centre), m_SqRadius(a_Radius * a_Radius),
m_Radius(a_Radius), m_RRadius(1.0f / a_Radius)
{
m_Material = new Material();
m_Vn = vector3(0, 1, 0);
m_Ve = vector3(1, 0, 0);
m_Vc = m_Vn.Cross(m_Ve);
}
Sphere::~Sphere()
{
delete m_Material;
}
int Sphere::Intersect(Ray& a_Ray, float& a_Dist)
{
vector3 v = a_Ray.GetOrigin() - m_Centre;
float b = -DOT(v, a_Ray.GetDirection());
float det = (b * b) - DOT(v, v) + m_SqRadius;
int retval = MISS;
if (det > 0)
{
det = sqrtf(det);
float i1 = b - det;
float i2 = b + det;
if (i2 > 0)
{
if (i1 < 0)
{
if (i2 < a_Dist)
{
a_Dist = i2;
retval = INPRIM;
}
}
else
{
if (i1 < a_Dist)
{
a_Dist = i1;
retval = HIT;
}
}
}
}
return retval;
}
Color Sphere::GetColor(vector3& a_Pos)
{
return m_Material->GetColor();
}
// -----------------------------------------------------------
// Plane примитив (плоскость)
// -----------------------------------------------------------
PlanePrim::PlanePrim(vector3& a_Normal, float a_D):
m_Plane(plane(a_Normal, a_D))
{
m_Material = new Material();
}
PlanePrim::~PlanePrim()
{
delete m_Material;
}
int PlanePrim::Intersect(Ray& a_Ray, float& a_Dist)
{
float d = DOT(m_Plane.N, a_Ray.GetDirection());
if (d < 0)
{
float dist = -(DOT(m_Plane.N, a_Ray.GetOrigin()) + m_Plane.D) / d;
if (dist < a_Dist)
{
a_Dist = dist;
return HIT;
}
}
return MISS;
}
Color PlanePrim::GetColor(vector3& a_Pos)
{
return m_Material->GetColor();
}
vector3 PlanePrim::GetNormal(vector3& a_Pos)
{
return m_Plane.N;
}
// -----------------------------------------------------------
// Ring примитив (кольцо)
// -----------------------------------------------------------
Ring::Ring(vector3& a_Normal, vector3 &point, float R, float r): point(point), R(R), r(r),
m_Plane(plane(a_Normal, -(a_Normal.x*point.x+a_Normal.y*point.y+a_Normal.z*point.z)))
{
m_Material = new Material();
}
Ring::~Ring()
{
delete m_Material;
}
int Ring::Intersect(Ray& a_Ray, float& a_Dist)
{
float d = DOT(m_Plane.N, a_Ray.GetDirection());
if (d < 0)
{
float dist = -(DOT(m_Plane.N, a_Ray.GetOrigin()) + m_Plane.D) / d;
if (dist < a_Dist)
{
vector3 p=a_Ray.GetOrigin()+a_Ray.GetDirection()*dist;
float Rdist = (point-p).Length();
if (Rdist>R||Rdist<r) return MISS;
a_Dist = dist;
return HIT;
}
}
return MISS;
}
Color Ring::GetColor(vector3& a_Pos)
{
return m_Material->GetColor();
}
vector3 Ring::GetNormal(vector3& a_Pos)
{
return m_Plane.N;
}
// -----------------------------------------------------------
// Scene реализация
// -----------------------------------------------------------
Scene::~Scene()
{
delete m_Primitive;
}
void Scene::InitScene()
{
m_Primitive = new Primitive*[15];
// источники света
m_Primitive[0] = new Sphere(vector3(-5, 4, -4), 1.5f);
m_Primitive[0]->Light(true);
m_Primitive[0]->GetMaterial()->SetColor(Color(1.0f, 1.0f, 1.0f));
m_Primitive[1] = new Sphere(vector3(20, 1, 1), 1.5f);
m_Primitive[1]->Light(true);
m_Primitive[1]->GetMaterial()->SetColor(Color(1.0f, 1.0f, 1.0f));
// задник
m_Primitive[2] = new PlanePrim(vector3(0, 0, -1), 50.0f);
m_Primitive[2]->SetName("backplane");
m_Primitive[2]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[2]->GetMaterial()->SetSpecular(0);
m_Primitive[2]->GetMaterial()->SetColor(Color(0.3f, 0.3f, 0.8f));
// протоны
m_Primitive[3] = new Sphere(vector3(0.8f, 0.5f, 6.7f), 0.555);
m_Primitive[3]->SetName("proton1");
m_Primitive[3]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[3]->GetMaterial()->SetSpecular(0.6f);
m_Primitive[3]->GetMaterial()->SetColor(Color(1.0f, 0.0f, 0.0f));
m_Primitive[4] = new Sphere(vector3(-0.8f, 0.5f, 6.7f), 0.555);
m_Primitive[4]->SetName("proton2");
m_Primitive[4]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[4]->GetMaterial()->SetSpecular(0.6f);
m_Primitive[4]->GetMaterial()->SetColor(Color(1.0f, 0.0f, 0.0f));
m_Primitive[5] = new Sphere(vector3(0, -0.7f, 6.7f), 0.555);
m_Primitive[5]->SetName("proton3");
m_Primitive[5]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[5]->GetMaterial()->SetSpecular(0.6f);
m_Primitive[5]->GetMaterial()->SetColor(Color(1.0f, 0.0f, 0.0f));
// нейтроны
m_Primitive[6] = new Sphere(vector3(0, 0, 7), 0.655);
m_Primitive[6]->SetName("neutron1");
m_Primitive[6]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[6]->GetMaterial()->SetSpecular(1.0f);
m_Primitive[6]->GetMaterial()->SetColor(Color(0.0f, 0.0f, 0.9f));
m_Primitive[7] = new Sphere(vector3(0, 1, 7.2f), 0.655);
m_Primitive[7]->SetName("neutron2");
m_Primitive[7]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[7]->GetMaterial()->SetSpecular(1.0f);
m_Primitive[7]->GetMaterial()->SetColor(Color(0.0f, 0.0f, 0.9f));
m_Primitive[8] = new Sphere(vector3(0.8f, -0.45f, 7.2f), 0.655);
m_Primitive[8]->SetName("neutron3");
m_Primitive[8]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[8]->GetMaterial()->SetSpecular(1.0f);
m_Primitive[8]->GetMaterial()->SetColor(Color(0.0f, 0.0f, 0.9f));
m_Primitive[9] = new Sphere(vector3(-0.8f, -0.45f, 7.2f), 0.655);
m_Primitive[9]->SetName("neutron4");
m_Primitive[9]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[9]->GetMaterial()->SetSpecular(1.0f);
m_Primitive[9]->GetMaterial()->SetColor(Color(0.0f, 0.0f, 0.9f));
// орбиты электронов
m_Primitive[10] = new Ring(-vector3(-1,1,1).Normalize(), vector3(0, 0, 7), 4.2, 4.155);
m_Primitive[10]->SetName("orbit1");
m_Primitive[10]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[10]->GetMaterial()->SetColor(Color(0.8f, 0.8f, 0.8f));
m_Primitive[11] = new Ring(-vector3(1,1,1).Normalize(), vector3(0, 0, 7), 5.32, 5.26);
m_Primitive[11]->SetName("orbit2");
m_Primitive[11]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[11]->GetMaterial()->SetColor(Color(0.8f, 0.8f, 0.8f));
// электроны
m_Primitive[12] = new Sphere(vector3(2.0f, 3.4f, 5.7f), 0.3);
m_Primitive[12]->SetName("electron1");
m_Primitive[12]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[12]->GetMaterial()->SetSpecular(1.0f);
m_Primitive[12]->GetMaterial()->SetColor(Color(0.6f, 0.6f, 0.6f));
m_Primitive[13] = new Sphere(vector3(-2.5f, -3.3f, 8.0f), 0.3);
m_Primitive[13]->SetName("electron2");
m_Primitive[13]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[13]->GetMaterial()->SetSpecular(1.0f);
m_Primitive[13]->GetMaterial()->SetColor(Color(0.6f, 0.6f, 0.6f));
m_Primitive[14] = new Sphere(vector3(-3.5f, 4.0f, 6.6f), 0.3);
m_Primitive[14]->SetName("electron3");
m_Primitive[14]->GetMaterial()->SetDiffuse(1.0f);
m_Primitive[14]->GetMaterial()->SetSpecular(1.0f);
m_Primitive[14]->GetMaterial()->SetColor(Color(0.6f, 0.6f, 0.6f));
int prim = 15;
m_Primitives = prim;
}
}; // namespace Raytracer
// -----------------------------------------------------------
// raytracer.h
// -----------------------------------------------------------
#include "common.h"
namespace Raytracer {
// -----------------------------------------------------------
// Ray class
// -----------------------------------------------------------
class Ray
{
public:
Ray(): m_Origin(vector3(0, 0, 0)), m_Direction(vector3(0, 0, 0)) {};
Ray(vector3& a_Origin, vector3& a_Dir);
void SetOrigin(vector3& a_Origin) { m_Origin = a_Origin; }
void SetDirection(vector3& a_Direction) { m_Direction = a_Direction; }
vector3& GetOrigin() { return m_Origin; }
vector3& GetDirection() { return m_Direction; }
private:
vector3 m_Origin;
vector3 m_Direction;
};
// -----------------------------------------------------------
// Engine class definition
// Raytracer core
// -----------------------------------------------------------
class Scene;
class Primitive;
class Engine
{
public:
Engine();
~Engine();
void SetTarget(Pixel* a_Dest, int a_Width, int a_Height);
Scene* GetScene() { return m_Scene; }
Primitive* Raytrace(Ray& a_Ray, Color& a_Acc, int a_Depth,float& a_Dist);
void InitRender();
bool Render();
protected:
float m_WX1, m_WY1, m_WX2, m_WY2, m_DX, m_DY, m_SX, m_SY;
Scene* m_Scene;
Pixel* m_Dest;
int m_Width, m_Height, m_CurrLine, m_PPos;
Primitive** m_LastRow;
};
}; // namespace Raytracer
// -----------------------------------------------------------
// raytracer.cpp
// -----------------------------------------------------------
#include "raytracer.h"
#include "scene.h"
#include "common.h"
#include "windows.h"
#include "winbase.h"
namespace Raytracer {
Ray::Ray(vector3& a_Origin, vector3& a_Dir):
m_Origin(a_Origin),
m_Direction(a_Dir) {}
Engine::Engine()
{
m_Scene = new Scene();
}
Engine::~Engine()
{
delete m_Scene;
}
// -----------------------------------------------------------
// Engine::SetTarget
// Настраиваем
// -----------------------------------------------------------
void Engine::SetTarget(Pixel* a_Dest, int a_Width, int a_Height)
{
// Устанавливаем для буфера пикселей экрана указатель и размеры
m_Dest = a_Dest;
m_Width = a_Width;
m_Height = a_Height;
}
// -----------------------------------------------------------
// Engine::Raytrace
// "Наивная" трассировка лучей: Пересечение луча с каждым примитивом
// в сцене, для определения ближайшего пересечения
// -----------------------------------------------------------
//луч,цвет окрашивания точки примитива,глубина трассировки,расстояние до пересечения с объектом
Primitive* Engine::Raytrace(Ray& a_Ray, Color& a_Acc, int a_Depth, float& a_Dist)
{
if (a_Depth > TRACEDEPTH) return 0;
// Трассируем начальный луч
a_Dist = 1000000.0f;
vector3 pi; //точка пересечения луча с примитивом
Primitive* prim = 0;
// Находим ближайшее пересечение с примитивом
for (int s = 0; s < m_Scene->GetNrPrimitives(); s++)
{
Primitive* pr = m_Scene->GetPrimitive(s);
int res;
if (res = pr->Intersect(a_Ray, a_Dist)) prim = pr;
}
// Нет попаданий, прекратить трассировку луча
if (!prim) return 0;
// Пересечение с источником света?
if (prim->IsLight())
{
// Устанавливаем цвет света
a_Acc = prim->GetMaterial()->GetColor();
}
else
{
// Определяем цвет точки пересечения
pi = a_Ray.GetOrigin() + a_Ray.GetDirection() * a_Dist;
Color color = prim->GetColor(pi);
// Трассируем лучи к источникам света
for (int l = 0; l < m_Scene->GetNrPrimitives(); l++)
{
Primitive* p = m_Scene->GetPrimitive(l);
if (p->IsLight())
{
Primitive* light = p;
float shade = 1.0f;
//Если источник - сфера
if (light->GetType() == Primitive::SPHERE)
{
vector3 L = ((Sphere*)light)->GetCentre() - pi;
float tdist = LENGTH(L);
L *= (1.0f / tdist); //Нормализуем
Ray r = Ray(pi + L * EPSILON, L); //сдвигаем, чтобы избежать пересечения с самим собой
for (int s = 0; s < m_Scene->GetNrPrimitives(); s++)
{
Primitive* pr = m_Scene->GetPrimitive(s);
int res=(pr->Intersect(r, tdist));
if ((pr!= light) && res)
{
shade = 0;
break;
}
}
}
if (shade > 0)
{
// оценка диффузного отражения
vector3 L = ((Sphere*)light)->GetCentre() - pi;
NORMALIZE(L);
vector3 N = prim->GetNormal(pi);
if (prim->GetMaterial()->GetDiffuse() > 0)
{
float dot = DOT(L, N); //покоординатное произведение векторов
if (dot > 0)
{
float diff = dot * prim->GetMaterial()->GetDiffuse() * shade;
// Добавляем цвет рассеянного света в цвет луча
a_Acc += diff * color * light->GetMaterial()->GetColor();
}
}
// Если примитив обладает отражающими свойствами
if (prim->GetMaterial()->GetSpecular() > 0)
{
// при точечном источнике света
vector3 V = a_Ray.GetDirection();
vector3 R = L - 2.0f * DOT(L, N) * N;
float dot = DOT(V, R);
if (dot > 0)
{
float spec = powf(dot, 20) * prim->GetMaterial()->GetSpecular() * shade;
// Добавляем цвет отражения в цвет луча
a_Acc += spec * light->GetMaterial()->GetColor();
}
}
}
}
}
}
// возвращаем примитив с которым пересекся луч
return prim;
}
// -----------------------------------------------------------
// Engine::InitRender
// Инициализация отрисовки обнулением линий,
// предподготовка некоторых значений
// -----------------------------------------------------------
void Engine::InitRender()
{
// Устанавливаем первую линию для отрисовки
m_CurrLine = 0;
// Устанавливаем указатель на буфер пикселей на начальную позицию
m_PPos = m_CurrLine * m_Width;
// Координаты плоскости экрана в коррдинатах мира
m_WX1 = -4, m_WX2 = 4, m_WY1 = m_SY = 3, m_WY2 = -3;
// Считаем дельты для сдвига
m_DX = (m_WX2 - m_WX1) / m_Width;
m_DY = (m_WY2 - m_WY1) / m_Height;
m_SY += m_CurrLine * m_DY;
// Выделаяем просторанство для хранения указателей на примитивы для предыдущей линии
m_LastRow = new Primitive*[m_Width];
memset(m_LastRow, 0, m_Width * 4);
}
// -----------------------------------------------------------
// Engine::Render
// Запускает лучи в сцену по одному в линии слева направо
// -----------------------------------------------------------
bool Engine::Render() //отрисовка
{
#define DEPTH 0 //Сдвиг в глубину
// Точка из которой трассируем
vector3 o(0, 0, -5 -DEPTH);
// Сбрасываем указатель на последний найденный примитив
Primitive* lastprim = 0;
// Для каждой линии
for (int y = m_CurrLine; y < m_Height; y++)
{
m_SX = m_WX1; //устанавливаем начальную позицию по Х для каждой линии
// Рисуем пиксели в линии
for (int x = 0; x < m_Width; x++)
{
// Создаем начальные лучи
Color acc(0, 0, 0); // задаём будущий фоновый цвет
// направляем из точки О вектор на плоскость экрана
vector3 dir = vector3(m_SX, m_SY, 0 -DEPTH) - o;
NORMALIZE(dir);
// Задаем луч
Ray r(o, dir);
float dist;
// Трассируем луч
Primitive* prim = Raytrace(r, acc, 1, dist);
int red, green, blue;
//Задаем цвета пиксела
red = (int)(acc.r * 256);
green = (int)(acc.g * 256);
blue = (int)(acc.b * 256);
//Проверяем правильность цвета
if (red > 255) red = 255;
if (green > 255) green = 255;
if (blue > 255) blue = 255;
//Создаем цвет в формате RGB для каждого пикселя экрана
m_Dest[m_PPos++] = (red << 16) + (green << 8) + blue;
//перешли к следующему участку модели экрана (в реальных координатах по Х)
m_SX += m_DX;
}
//перешли аналогично к следующему участку по У (более ранний цикл был построчный)
m_SY += m_DY;
{
m_CurrLine = y + 1; //Переходим на следующую строку
//Возращаем управление
return false;
}
}
// Все Ok
return true;
}
}; // namespace Raytracer
// -----------------------------------------------------------
// raytracer.h
// -----------------------------------------------------------
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include "common.h"
#include "raytracer.h"
#include "scene.h"
#include "surface.h"
#define SCRWIDTH 800
#define SCRHEIGHT 600
static WNDCLASS wc;
static HWND wnd;
static char bitmapbuffer[sizeof(BITMAPINFO) + 16];
static BITMAPINFO* bh;
HDC window_hdc;
Raytracer::Surface* surface = 0;
Pixel* buffer = 0;
Raytracer::Engine* tracer = 0;
void DrawWindow();
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int result = 0, keycode = 0;
switch (message)
{
case WM_PAINT:
if (!buffer) break;
StretchDIBits(window_hdc, 0, 0, SCRWIDTH, SCRHEIGHT, 0, 0, SCRWIDTH, SCRHEIGHT, buffer, bh, DIB_RGB_COLORS, SRCCOPY);
ValidateRect(wnd, NULL);
break;
case WM_KEYDOWN:
if ((wParam & 0xFF)!= 27) break;
case WM_CLOSE:
ReleaseDC(wnd, window_hdc);
DestroyWindow(wnd);
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, 0, 0);
ExitProcess(0);
break;
default:
result = DefWindowProc(hWnd,message,wParam,lParam);
}
return result;
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
RECT rect;
int cc;
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = wc.cbWndExtra = 0;
wc.hInstance = 0;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(0,IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "raytracer";
if (!RegisterClass(&wc)) return FALSE;
rect.left = rect.top = 0;
rect.right = SCRWIDTH, rect.bottom = SCRHEIGHT;
AdjustWindowRect(&rect, WS_POPUP|WS_SYSMENU|WS_CAPTION, 0);
rect.right -= rect.left, rect.bottom -= rect.top;
wnd = CreateWindowEx(0, "raytracer", "raytracer", WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME,
CW_USEDEFAULT, CW_USEDEFAULT, rect.right, rect.bottom, 0, 0, 0, 0);
ShowWindow(wnd,SW_NORMAL);
for (cc = 0; cc < sizeof(BITMAPINFOHEADER) + 16; cc++) bitmapbuffer[cc] = 0;
bh = (BITMAPINFO *)&bitmapbuffer;
bh->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bh->bmiHeader.biPlanes = 1;
bh->bmiHeader.biBitCount = 32;
bh->bmiHeader.biCompression = BI_BITFIELDS;
bh->bmiHeader.biWidth = SCRWIDTH, bh->bmiHeader.biHeight = -SCRHEIGHT;
((unsigned long*)bh->bmiColors)[0] = 255 << 16;
((unsigned long*)bh->bmiColors)[1] = 255 << 8;
((unsigned long*)bh->bmiColors)[2] = 255;
window_hdc = GetDC(wnd);
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, 0);
// подготовка экрана
surface = new Raytracer::Surface(SCRWIDTH, SCRHEIGHT);
buffer = surface->GetBuffer();
surface->Clear(0);
// подготовка к отрисовке
tracer = new Raytracer::Engine();
tracer->GetScene()->InitScene();
tracer->SetTarget(surface->GetBuffer(), SCRWIDTH, SCRHEIGHT);
int tpos = 60;
// истинное начало
while (1)
{
tracer->InitRender();
while (!tracer->Render()) DrawWindow();
surface->Print(tpos, 2);
tpos += 100;
}
return 1;
}
void DrawWindow()
{
MSG message;
HACCEL haccel = 0;
InvalidateRect(wnd,NULL,TRUE);
SendMessage(wnd, WM_PAINT, 0, 0);
while (PeekMessage(&message, wnd, 0, 0, PM_REMOVE))
{
if (TranslateAccelerator(wnd, haccel, &message) == 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
}
Sleep(0);
}