Приложение 1 – результат работы программы





Приложение 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);

}

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-08-20 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: