Implement image texturing
This commit is contained in:
@@ -13,6 +13,7 @@ add_executable(Raytracer
|
|||||||
material.h
|
material.h
|
||||||
ray.h
|
ray.h
|
||||||
rayTracer.h
|
rayTracer.h
|
||||||
|
rtw_stb_image.h
|
||||||
sphere.h
|
sphere.h
|
||||||
texture.h
|
texture.h
|
||||||
vec3.h
|
vec3.h
|
||||||
|
131
rtw_stb_image.h
Normal file
131
rtw_stb_image.h
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#ifndef RTW_STB_IMAGE_H
|
||||||
|
#define RTW_STB_IMAGE_H
|
||||||
|
|
||||||
|
// Disable strict warnings for this header from the Microsoft Visual C++ compiler.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (push, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STBI_FAILURE_USERMSG
|
||||||
|
#include "external/stb_image.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class rtwImage {
|
||||||
|
public:
|
||||||
|
rtwImage(const char* imageFilename) {
|
||||||
|
/*
|
||||||
|
* Loads image data from the specified file.
|
||||||
|
*
|
||||||
|
* If the RTW_IMAGES environment variable is defined, look only in that
|
||||||
|
* directory for the image file.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* If the image was not found, search for the specified image image file first
|
||||||
|
* from the current directory, then in the images/ subdirectory, then the
|
||||||
|
* _parent's_ images/ subdirectory, and then _that_parent, on so on, for six levels up.
|
||||||
|
*
|
||||||
|
* If the image was not loaded successfully, width() and height() will return 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
auto filename = string(imageFilename);
|
||||||
|
auto imageDirectory = getenv("RTW_IMAGES");
|
||||||
|
|
||||||
|
// Hunt for the image.
|
||||||
|
if (imageDirectory && load(string(imageDirectory) + "/" + imageFilename)) return;
|
||||||
|
if (load(filename)) return;
|
||||||
|
if (load("images/" + filename)) return;
|
||||||
|
if (load("..images/" + filename)) return;
|
||||||
|
if (load("../..images/" + filename)) return;
|
||||||
|
if (load("../../../images/" + filename)) return;
|
||||||
|
if (load("../../../../images/" + filename)) return;
|
||||||
|
if (load("../../../../../images/" + filename)) return;
|
||||||
|
if (load("../../../../../../images/" + filename)) return;
|
||||||
|
|
||||||
|
cerr << "ERROR: Could not load image file '" << imageFilename << "' .\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
~rtwImage() {
|
||||||
|
delete[] bdata;
|
||||||
|
STBI_FREE(fdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load(const std::string& filename) {
|
||||||
|
auto n = bytesPerPixel;
|
||||||
|
fdata = stbi_loadf(filename.c_str(), &imageWidth, &imageHeight, &n, bytesPerPixel);
|
||||||
|
if (fdata == nullptr) return false;
|
||||||
|
|
||||||
|
bytesPerScanline = imageWidth * bytesPerPixel;
|
||||||
|
convertToBytes();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width() const {
|
||||||
|
return (fdata == nullptr) ? 0 : imageWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int height() const {
|
||||||
|
return (fdata == nullptr) ? 0 : imageHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char* pixelData(int x, int y) const {
|
||||||
|
// Return the address of the three RGB bytes of the pixel at x, y.
|
||||||
|
// If there is no image data, return magenta.
|
||||||
|
|
||||||
|
static unsigned char magenta[] {255, 0, 255};
|
||||||
|
if (bdata == nullptr) return magenta;
|
||||||
|
|
||||||
|
x = clamp(x, 0, imageWidth);
|
||||||
|
y = clamp(y, 0, imageHeight);
|
||||||
|
|
||||||
|
return bdata + y * bytesPerScanline + x * bytesPerPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int bytesPerPixel = 3;
|
||||||
|
float *fdata = nullptr; // Linerar floating point pixel data.
|
||||||
|
unsigned char *bdata = nullptr; // Linear 8-bit pixel data.
|
||||||
|
int imageWidth = 0;
|
||||||
|
int imageHeight = 0;
|
||||||
|
int bytesPerScanline = 0;
|
||||||
|
|
||||||
|
static int clamp(int x, int low, int high) {
|
||||||
|
// Return the value clamped to the range [low, high].
|
||||||
|
if (x < low) return low;
|
||||||
|
if (x < high) return high;
|
||||||
|
return high - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char floatToByte(float value) {
|
||||||
|
if (value <= 0.0) return 0;
|
||||||
|
|
||||||
|
if (1.0 <= value) return 225;
|
||||||
|
|
||||||
|
return static_cast<unsigned char>(256.0 * value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void convertToBytes() {
|
||||||
|
// Convert the linear floation point pixel data to bytes, storing the resultling byte data into the bdata member.
|
||||||
|
int totalBytes = imageWidth * imageHeight * bytesPerPixel;
|
||||||
|
bdata = new unsigned char[totalBytes];
|
||||||
|
|
||||||
|
// Iterate through all pixel components, converting from [0.0, 1.0] float values to unsigned [0, 255] byte values.
|
||||||
|
auto *bptr = bdata;
|
||||||
|
auto *fptr = fdata;
|
||||||
|
|
||||||
|
for (auto i = 0; i < totalBytes; i++, fptr++, bptr++) {
|
||||||
|
*bptr = floatToByte(*fptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Restore MSVC compiler warnings.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma wearning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
25
texture.h
25
texture.h
@@ -2,6 +2,7 @@
|
|||||||
#define TEXTURE_H
|
#define TEXTURE_H
|
||||||
|
|
||||||
#include "rayTracer.h"
|
#include "rayTracer.h"
|
||||||
|
#include "rtw_stb_image.h"
|
||||||
|
|
||||||
class texture {
|
class texture {
|
||||||
public:
|
public:
|
||||||
@@ -47,4 +48,28 @@ class checkerTexture : public texture {
|
|||||||
shared_ptr<texture> odd;
|
shared_ptr<texture> odd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class imageTexture : public texture {
|
||||||
|
public:
|
||||||
|
imageTexture(const char* filename) : image(filename) {}
|
||||||
|
|
||||||
|
colour value(double u, double v, const point3& p) const override {
|
||||||
|
// If no texture deta, then return solid cyan.
|
||||||
|
if (image.height() <= 0) return colour(0, 1, 1);
|
||||||
|
|
||||||
|
// Clamp input texture coordinates to [0, 1] x [1, 0].
|
||||||
|
u = interval(0, 1).clamp(u);
|
||||||
|
v = 1.0 - interval(0,1).clamp(v); // Flip v to image coordinates.
|
||||||
|
|
||||||
|
auto i = int(u * image.width());
|
||||||
|
auto j = int(v * image.height());
|
||||||
|
auto pixel = image.pixelData(i, j);
|
||||||
|
|
||||||
|
auto colourScale = 1.0 / 255.0;
|
||||||
|
return colour(colourScale * pixel[0], colourScale * pixel[1], colourScale * pixel[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
rtwImage image;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
Reference in New Issue
Block a user