www.pudn.com > Ray_Tracing_Materials.rar > RayTracingMaterials.cpp, change:2005-03-02,size:9811b
/*
Ray Tracing Materials Demo.
Created by the Programming Ace.
www.UltimateGameProgramming.com
The purpose of this demo is to build off of the previous ray tracing demos
and add materials to our objects. In the past we have used a hard coded
values for all surfaces of 0.7 but now we will add a way to set the diffuse
material for each shape in the scene.
*/
// Demo: Ray Tracing Materials.
// All the necessary includes...
#include<iostream>
#include"Shape.h"
#include"RayTracer.h"
#include"Light.h"
#include"TgaImage.h"
using namespace std;
// Width/Height resolution and total number of objects.
#define WIDTH_RES 640
#define HEIGHT_RES 480
#define TOTAL_SHAPES 16
#define TOTAL_LIGHTS 1
// Function prototype...
bool InitializeRT();
void ClearBuffer(unsigned char *buffer, int size, int r, int g, int b);
void Shutdown();
// Primary render array and the look up array of directions.
unsigned char *primaryBuffer = 0;
CVector4 *directionList = 0;
// List of objects, light source, and tga object to save the rendered scene.
Shape shapes[TOTAL_SHAPES];
CLight lights[TOTAL_LIGHTS];
Ray primaryRay;
int main()
{
cout << "Ultimate Game Programming Ray Tracer..." << endl;
cout << "Created by Allen Sherrod..." << endl << endl;
// Initialize all arrays and data nescessary. If it fails then we can't
// perform our ray tracing.
if(!InitializeRT())
{
cout << "Initialization failed! Exiting." << endl;
return 0;
}
cout << "Clearing primary buffer..." << endl;
// Clear the rendered scene to a default color (I choose black).
ClearBuffer(primaryBuffer, WIDTH_RES * HEIGHT_RES * 3, 0, 0, 0);
cout << "Primary buffer cleared and ready to be drawn to..." << endl << endl;
cout << "Starting trace." << endl;
// Trace through the scene and create the rendered scene.
int bufferIndex = 0;
for(int y = 0; y < HEIGHT_RES; y++)
{
if(y == 0) cout << " 0% complete..." << endl;
if(y == (int)(HEIGHT_RES * 0.4)) cout << " 25% complete..." << endl;
if(y == (int)(HEIGHT_RES * 0.5)) cout << " 50% complete..." << endl;
if(y == (int)(HEIGHT_RES * 0.75)) cout << " 75% complete..." << endl;
if(y == (int)(HEIGHT_RES - 1)) cout << "100% complete..." << endl;
for(int x = 0; x < WIDTH_RES; x++, bufferIndex+=3)
{
float r = 0, g = 0, b = 0;
// Grab the direction for this current pixel.
primaryRay.direction = directionList[x + y * WIDTH_RES];
TraceScene(shapes, TOTAL_SHAPES, lights, TOTAL_LIGHTS,
primaryRay, r, g, b);
// Convert and clamp to 0 to 255 from 0 to 1.
r *= 255; g *= 255; b *= 255;
if(r > 255) r = 255;
if(g > 255) g = 255;
if(b > 255) b = 255;
// Save the color in our back buffer array.
primaryBuffer[bufferIndex + 0] = (int)r;
primaryBuffer[bufferIndex + 1] = (int)g;
primaryBuffer[bufferIndex + 2] = (int)b;
}
}
cout << endl;
cout << "Trace over." << endl << endl;
cout << "Preparing to save scene as RayTracedScene.tga..." << endl;
// Take our ray traced scene and save it as a .tga image file.
WriteTGA("RayTracedScene.tga", WIDTH_RES, HEIGHT_RES, primaryBuffer);
cout << "Traced scene saved...shut down starting..." << endl << endl;
// Release all resources and data we used.
Shutdown();
cout << "Exiting..." << endl;
return 1;
}
bool InitializeRT()
{
// Release all previous data.
Shutdown();
// Allocate rendering buffer.
primaryBuffer = new unsigned char[WIDTH_RES * HEIGHT_RES * 3];
// Error checking...
if(primaryBuffer == NULL)
return false;
// Allocate the ray directions.
directionList = GenerateRayDirections(WIDTH_RES, HEIGHT_RES, 255);
// Error checking...
if(directionList == NULL)
return false;
// Set the primary ray.
primaryRay.origin.x = 0;
primaryRay.origin.y = 0;
primaryRay.origin.z = -500;
// Setup the lights.
lights[0] = CLight(POINT_LIGHT, CVector4(0, 300, 0), 1, 1, 1, 500);
// Initialize the shapes we are using.
shapes[0].type = SPHERE;
shapes[0].sphere = new Sphere(-400, -200, 0, 100, 1, 1, 1, 0.7f, 1.0f, 0.0f);
shapes[1].type = SPHERE;
shapes[1].sphere = new Sphere(-400, -200, 200, 100, 1, 1, 1, 0.7f, 1.0f, 0.0f);
shapes[2].type = SPHERE;
shapes[2].sphere = new Sphere(400, -200, 200, 100, 1, 1, 1, 0.7f, 1.0f, 0.0f);
shapes[3].type = SPHERE;
shapes[3].sphere = new Sphere(400, -200, 0, 100, 1, 1, 1, 0.7f, 1.0f, 0.0f);
// Ground.
shapes[4].type = TRIANGLE;
shapes[4].triangle = new Triangle(CVector4(-600, -300, -800),
CVector4(-600, -300, 800),
CVector4(600, -300, 800), 1, 1, 1,
0.7f, 0, 0);
shapes[5].type = TRIANGLE;
shapes[5].triangle = new Triangle(CVector4(600, -300, 800),
CVector4(600, -300, -800),
CVector4(-600, -300, -800), 1, 1, 1,
0.7f, 0, 0);
// Left.
shapes[6].type = TRIANGLE;
shapes[6].triangle = new Triangle(CVector4(-600, -300, 800),
CVector4(-600, -300, -800),
CVector4(-600, 550, -800), 1, 0, 1,
0.7f, 0, 0);
shapes[7].type = TRIANGLE;
shapes[7].triangle = new Triangle(CVector4(-600, 550, -800),
CVector4(-600, 550, 800),
CVector4(-600, -300, 800), 1, 0, 1,
0.7f, 0, 0);
// Right.
shapes[8].type = TRIANGLE;
shapes[8].triangle = new Triangle(CVector4(600, -300, -800),
CVector4(600, -300, 800),
CVector4(600, 550, 800), 0, 1, 1,
0.7f, 0, 0);
shapes[9].type = TRIANGLE;
shapes[9].triangle = new Triangle(CVector4(600, 550, 800),
CVector4(600, 550, -800),
CVector4(600, -300, -800), 0, 1, 1,
0.7f, 0, 0);
// Roof.
shapes[10].type = TRIANGLE;
shapes[10].triangle = new Triangle(CVector4(-600, 550, 800),
CVector4(-600, 550, -800),
CVector4(600, 550, -800), 1, 1, 1,
0.7f, 0, 0);
shapes[11].type = TRIANGLE;
shapes[11].triangle = new Triangle(CVector4(600, 550, -800),
CVector4(600, 550, 800),
CVector4(-600, 550, 800), 1, 1, 1,
0.7f, 0, 0);
// Front.
shapes[12].type = TRIANGLE;
shapes[12].triangle = new Triangle(CVector4(-600, -300, -800),
CVector4(600, -300, -800),
CVector4(600, 550, -800), 1, 1, 1,
0.7f, 0, 0);
shapes[13].type = TRIANGLE;
shapes[13].triangle = new Triangle(CVector4(600, 550, -800),
CVector4(-600, 550, -800),
CVector4(-600, -300, -800), 1, 1, 1,
0.7f, 0, 0);
// Back.
shapes[14].type = TRIANGLE;
shapes[14].triangle = new Triangle(CVector4(600, -300, 800),
CVector4(-600, -300, 800),
CVector4(-600, 550, 800), 0, 0, 1,
0.7f, 0, 0);
shapes[15].type = TRIANGLE;
shapes[15].triangle = new Triangle(CVector4(-600, 550, 800),
CVector4(600, 550, 800),
CVector4(600, -300, 800), 0, 0, 1,
0.7f, 0, 0);
return true;
}
void ClearBuffer(unsigned char *buffer, int size, int r, int g, int b)
{
// Loop through the entire array and set the buffer to the specified color.
for(int p = 0; p < size; p += 3)
{
buffer[p + 0] = r; buffer[p + 1] = g; buffer[p + 2] = b;
}
}
void Shutdown()
{
// Release all resources we used.
if(directionList != NULL) delete[] directionList;
if(primaryBuffer != NULL) delete[] primaryBuffer;
for(int i = 0; i < TOTAL_SHAPES; i++)
{
if(shapes[i].type == SPHERE && shapes[i].sphere != NULL)
delete shapes[i].sphere;
else if(shapes[i].type == TRIANGLE && shapes[i].triangle != NULL)
delete shapes[i].triangle;
else if(shapes[i].type == PLANE && shapes[i].plane != NULL)
delete shapes[i].plane;
}
}
// Recap:
// Our shapes have gotten to the point where it is easier and better to just
// create a base class with all the common data then derive each shape from
// that. But since I don't want to make any major changes to the code you
// are use to seeing and since this is just for educational purposes, the way
// we do things are fine. Even though its not the best way.
// Copyright February 2005
// All Rights Reserved!
// Allen Sherrod
// ProgrammingAce@UltimateGameProgramming.com
// www.UltimateGameProgramming.com