Added texture support. Currently broken.
There is something very wrong somewhere. More testing is needed.main
parent
410e9c29b0
commit
763d57327f
|
@ -32,6 +32,8 @@ namespace Raytracing {
|
||||||
Vec4 normal{};
|
Vec4 normal{};
|
||||||
// the length of the vector from its origin in its direction.
|
// the length of the vector from its origin in its direction.
|
||||||
PRECISION_TYPE length{0};
|
PRECISION_TYPE length{0};
|
||||||
|
// Texture UV Coords.
|
||||||
|
PRECISION_TYPE u,v;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScatterResults {
|
struct ScatterResults {
|
||||||
|
@ -53,6 +55,7 @@ namespace Raytracing {
|
||||||
// returns true if the ray was scattered along with the scattered ray, otherwise will return false with empty ray.
|
// returns true if the ray was scattered along with the scattered ray, otherwise will return false with empty ray.
|
||||||
// the returned vec4 is the attenuation color
|
// the returned vec4 is the attenuation color
|
||||||
[[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const = 0;
|
[[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const = 0;
|
||||||
|
[[nodiscard]] virtual Vec4 getColor(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& point) const = 0;
|
||||||
|
|
||||||
[[nodiscard]] Vec4 getBaseColor() const { return baseColor; }
|
[[nodiscard]] Vec4 getBaseColor() const { return baseColor; }
|
||||||
virtual ~Material() = default;
|
virtual ~Material() = default;
|
||||||
|
|
|
@ -64,7 +64,10 @@ namespace Raytracing {
|
||||||
public:
|
public:
|
||||||
explicit DiffuseMaterial(const Vec4& scatterColor): Material(scatterColor) {}
|
explicit DiffuseMaterial(const Vec4& scatterColor): Material(scatterColor) {}
|
||||||
|
|
||||||
[[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const;
|
[[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const override;
|
||||||
|
[[nodiscard]] virtual Vec4 getColor(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& point) const override {
|
||||||
|
return this->baseColor;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MetalMaterial : public Material {
|
class MetalMaterial : public Material {
|
||||||
|
@ -76,7 +79,10 @@ namespace Raytracing {
|
||||||
public:
|
public:
|
||||||
explicit MetalMaterial(const Vec4& metalColor): Material(metalColor) {}
|
explicit MetalMaterial(const Vec4& metalColor): Material(metalColor) {}
|
||||||
|
|
||||||
[[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const;
|
[[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const override;
|
||||||
|
[[nodiscard]] virtual Vec4 getColor(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& point) const override {
|
||||||
|
return this->baseColor;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BrushedMetalMaterial : public MetalMaterial {
|
class BrushedMetalMaterial : public MetalMaterial {
|
||||||
|
@ -85,14 +91,23 @@ namespace Raytracing {
|
||||||
public:
|
public:
|
||||||
explicit BrushedMetalMaterial(const Vec4& metalColor, PRECISION_TYPE fuzzyness): MetalMaterial(metalColor), fuzzyness(fuzzyness) {}
|
explicit BrushedMetalMaterial(const Vec4& metalColor, PRECISION_TYPE fuzzyness): MetalMaterial(metalColor), fuzzyness(fuzzyness) {}
|
||||||
|
|
||||||
[[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const;
|
[[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const override;
|
||||||
|
[[nodiscard]] virtual Vec4 getColor(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& point) const override {
|
||||||
|
return this->baseColor;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TexturedMaterial : public Material {
|
class TexturedMaterial : public Material {
|
||||||
|
protected:
|
||||||
|
int width{}, height{}, channels{}, rowWidth{};
|
||||||
|
unsigned char* data;
|
||||||
public:
|
public:
|
||||||
explicit TexturedMaterial(const std::string& file): Material({}) {
|
explicit TexturedMaterial(const std::string& file);
|
||||||
|
|
||||||
}
|
[[nodiscard]] virtual ScatterResults scatter(const Ray& ray, const HitData& hitData) const override;
|
||||||
|
[[nodiscard]] virtual Vec4 getColor(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& point) const override;
|
||||||
|
|
||||||
|
~TexturedMaterial();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WorldConfig {
|
struct WorldConfig {
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
After Width: | Height: | Size: 195 KiB |
Binary file not shown.
After Width: | Height: | Size: 311 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
# Blender 3.3.1 MTL File: 'None'
|
||||||
|
# www.blender.org
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Blender 3.3.1
|
||||||
|
# www.blender.org
|
||||||
|
mtllib debug.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vn -1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 -0.0000 -1.0000
|
||||||
|
vn 1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 -0.0000 1.0000
|
||||||
|
vn -0.0000 -1.0000 -0.0000
|
||||||
|
vn -0.0000 1.0000 -0.0000
|
||||||
|
vt 0.000000 0.000000
|
||||||
|
vt 0.000000 1.000000
|
||||||
|
vt 0.000000 0.000000
|
||||||
|
vt 0.000000 0.000000
|
||||||
|
vt 0.000000 1.000000
|
||||||
|
vt 1.000000 0.000000
|
||||||
|
vt 1.000000 1.000000
|
||||||
|
vt 0.000000 1.000000
|
||||||
|
vt 0.000000 0.000000
|
||||||
|
vt 1.000000 0.000000
|
||||||
|
vt 0.000000 1.000000
|
||||||
|
vt 1.000000 1.000000
|
||||||
|
vt 1.000000 0.000000
|
||||||
|
vt 1.000000 0.000000
|
||||||
|
vt 1.000000 1.000000
|
||||||
|
vt 1.000000 1.000000
|
||||||
|
s 0
|
||||||
|
f 2/2/1 3/6/1 1/1/1
|
||||||
|
f 4/8/2 7/14/2 3/4/2
|
||||||
|
f 8/16/3 5/9/3 7/14/3
|
||||||
|
f 6/12/4 1/1/4 5/10/4
|
||||||
|
f 7/15/5 1/1/5 3/5/5
|
||||||
|
f 4/8/6 6/13/6 8/16/6
|
||||||
|
f 2/2/1 4/7/1 3/6/1
|
||||||
|
f 4/8/2 8/16/2 7/14/2
|
||||||
|
f 8/16/3 6/11/3 5/9/3
|
||||||
|
f 6/12/4 2/2/4 1/1/4
|
||||||
|
f 7/15/5 5/10/5 1/1/5
|
||||||
|
f 4/8/6 2/3/6 6/13/6
|
|
@ -14,7 +14,7 @@ void main() {
|
||||||
vec4 textureColor = texture(tex, outUv);
|
vec4 textureColor = texture(tex, outUv);
|
||||||
//FragColor = vec4(textureColor.rgb, 1.0f);
|
//FragColor = vec4(textureColor.rgb, 1.0f);
|
||||||
if (useWhite == 0)
|
if (useWhite == 0)
|
||||||
FragColor = vec4(vec3(1.0, 0.0f, 0.0f) * dot(lightDir, outNormal), 1.0f);
|
FragColor = vec4(vec3(1.0, 0.0f, 0.0f) * dot(lightDir, outNormal) * vec3(outUv, 1.0), 1.0f);
|
||||||
else
|
else
|
||||||
FragColor = vec4(color, 1.0f);
|
FragColor = vec4(color, 1.0f);
|
||||||
}
|
}
|
|
@ -126,6 +126,7 @@ int main(int argc, char** args) {
|
||||||
Raytracing::ModelData spider = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "spider.obj");
|
Raytracing::ModelData spider = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "spider.obj");
|
||||||
Raytracing::ModelData house = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "house.obj");
|
Raytracing::ModelData house = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "house.obj");
|
||||||
Raytracing::ModelData plane = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "plane.obj");
|
Raytracing::ModelData plane = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "plane.obj");
|
||||||
|
Raytracing::ModelData debugCube = Raytracing::OBJLoader::loadModel(parser.getOptionValue("--resources") + "debug.obj");
|
||||||
|
|
||||||
world.add("greenDiffuse", new Raytracing::DiffuseMaterial{Raytracing::Vec4{0, 1.0, 0, 1}});
|
world.add("greenDiffuse", new Raytracing::DiffuseMaterial{Raytracing::Vec4{0, 1.0, 0, 1}});
|
||||||
world.add("redDiffuse", new Raytracing::DiffuseMaterial{Raytracing::Vec4{1.0, 0, 0, 1}});
|
world.add("redDiffuse", new Raytracing::DiffuseMaterial{Raytracing::Vec4{1.0, 0, 0, 1}});
|
||||||
|
@ -134,6 +135,7 @@ int main(int argc, char** args) {
|
||||||
world.add("greenMetal", new Raytracing::MetalMaterial{Raytracing::Vec4{0.4, 1.0, 0.4, 1}});
|
world.add("greenMetal", new Raytracing::MetalMaterial{Raytracing::Vec4{0.4, 1.0, 0.4, 1}});
|
||||||
world.add("redMetal", new Raytracing::BrushedMetalMaterial{Raytracing::Vec4{1.0, 0.4, 0.4, 1}, 0.6f});
|
world.add("redMetal", new Raytracing::BrushedMetalMaterial{Raytracing::Vec4{1.0, 0.4, 0.4, 1}, 0.6f});
|
||||||
world.add("blueMetal", new Raytracing::MetalMaterial{Raytracing::Vec4{0.4, 0.4, 1.0, 1}});
|
world.add("blueMetal", new Raytracing::MetalMaterial{Raytracing::Vec4{0.4, 0.4, 1.0, 1}});
|
||||||
|
world.add("test", new Raytracing::TexturedMaterial{parser.getOptionValue("--resources") + "029a_-_Survival_of_the_Idiots_349.jpg"});
|
||||||
|
|
||||||
world.add(new Raytracing::SphereObject({0, -100.5, -1, 0}, 100, world.getMaterial("greenDiffuse")));
|
world.add(new Raytracing::SphereObject({0, -100.5, -1, 0}, 100, world.getMaterial("greenDiffuse")));
|
||||||
|
|
||||||
|
@ -142,6 +144,7 @@ int main(int argc, char** args) {
|
||||||
world.add(new Raytracing::ModelObject({5, 1, 0}, house, world.getMaterial("redDiffuse")));
|
world.add(new Raytracing::ModelObject({5, 1, 0}, house, world.getMaterial("redDiffuse")));
|
||||||
world.add(new Raytracing::ModelObject({0, 0, -5}, house, world.getMaterial("blueDiffuse")));
|
world.add(new Raytracing::ModelObject({0, 0, -5}, house, world.getMaterial("blueDiffuse")));
|
||||||
world.add(new Raytracing::ModelObject({0, 0, 5}, house, world.getMaterial("blueDiffuse")));
|
world.add(new Raytracing::ModelObject({0, 0, 5}, house, world.getMaterial("blueDiffuse")));
|
||||||
|
world.add(new Raytracing::ModelObject({0, 5, 0}, debugCube, world.getMaterial("test")));
|
||||||
|
|
||||||
if (parser.hasOption("--gui") || parser.hasOption("-g")) {
|
if (parser.hasOption("--gui") || parser.hasOption("-g")) {
|
||||||
#ifdef COMPILE_GUI
|
#ifdef COMPILE_GUI
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
#include "engine/world.h"
|
#include "engine/world.h"
|
||||||
#include "engine/raytracing.h"
|
#include "engine/raytracing.h"
|
||||||
|
#include "engine/image/stb_image.h"
|
||||||
|
|
||||||
namespace Raytracing {
|
namespace Raytracing {
|
||||||
|
|
||||||
|
@ -53,7 +54,10 @@ namespace Raytracing {
|
||||||
} else
|
} else
|
||||||
tlog << "ray outside sphere\n";
|
tlog << "ray outside sphere\n";
|
||||||
*/
|
*/
|
||||||
return {true, RayAtRoot, normal, root};
|
// calculate the uv coords and normalize to [0, 1]
|
||||||
|
PRECISION_TYPE u = (atan2(-RayAtRoot.z(), RayAtRoot.x()) + std::numbers::pi) / (2 * std::numbers::pi);
|
||||||
|
PRECISION_TYPE v = acos(RayAtRoot.y()) / std::numbers::pi;
|
||||||
|
return {true, RayAtRoot, normal, root, u, v};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<HitData, Object*> World::checkIfHit(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) const {
|
std::pair<HitData, Object*> World::checkIfHit(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) const {
|
||||||
|
@ -132,6 +136,55 @@ namespace Raytracing {
|
||||||
return {shouldReflect, Ray{hitData.hitPoint, newRay + Raycaster::randomUnitVector() * fuzzyness}, getBaseColor()};
|
return {shouldReflect, Ray{hitData.hitPoint, newRay + Raycaster::randomUnitVector() * fuzzyness}, getBaseColor()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScatterResults TexturedMaterial::scatter(const Ray& ray, const HitData& hitData) const {
|
||||||
|
Vec4 newRay = hitData.normal + Raytracing::Raycaster::randomUnitVector().normalize();
|
||||||
|
|
||||||
|
// rays that are close to zero are liable to floating point precision errors
|
||||||
|
if (newRay.x() < EPSILON && newRay.y() < EPSILON && newRay.z() < EPSILON && newRay.w() < EPSILON)
|
||||||
|
newRay = hitData.normal;
|
||||||
|
|
||||||
|
return {true, Ray{hitData.hitPoint, newRay}, getColor(hitData.u, hitData.v, hitData.hitPoint)};
|
||||||
|
}
|
||||||
|
Vec4 TexturedMaterial::getColor(PRECISION_TYPE u, PRECISION_TYPE v, const Vec4& point) const {
|
||||||
|
// if we are unable to load the image return the debug color.
|
||||||
|
// This causes major issues (force this to happen, you'll see), indicates issue + looks really cool.
|
||||||
|
if (!data)
|
||||||
|
Vec4{0, 1, 0.2} * Vec4{u, v, 1.0};
|
||||||
|
|
||||||
|
// if you render out the debug color above you'll notice that the UV coords are rotated.
|
||||||
|
// you can also see this from the debug view, which *as of now* is rendering based on UV coords * normals * red
|
||||||
|
// so let's transform it back and ensure that our UV coords are within image bounds.
|
||||||
|
u = clamp(u, 0, 1);
|
||||||
|
// fix that pesky issue
|
||||||
|
v = 1.0 - clamp(v, 0, 1);
|
||||||
|
|
||||||
|
auto imageX = (int)(width * u);
|
||||||
|
auto imageY = (int)(height * v);
|
||||||
|
|
||||||
|
if (imageX >= width) imageX = width-1;
|
||||||
|
if (imageY >= height) imageY = height-1;
|
||||||
|
|
||||||
|
// since stbi loads in RGB8 [0, 255] but the engine works on [0, 1] we need to scale the data down.
|
||||||
|
// this is best done with a single division followed by multiple multiplication.
|
||||||
|
// since this function needs to be cheap to run.
|
||||||
|
const PRECISION_TYPE colorFactor = 1.0 / 255.0;
|
||||||
|
const auto pixelData = data + (imageY * rowWidth + imageX * channels);
|
||||||
|
|
||||||
|
return {pixelData[0] * colorFactor, pixelData[1] * colorFactor, pixelData[2] * colorFactor};
|
||||||
|
}
|
||||||
|
TexturedMaterial::TexturedMaterial(const std::string& file) : Material({}) {
|
||||||
|
// we are going to have to ignore transparency for now. TODO:?
|
||||||
|
data = stbi_load(file.c_str(), &width, &height, &channels, 0);
|
||||||
|
if (!data)
|
||||||
|
flog << "Unable to load image file " << file << "!\n";
|
||||||
|
else
|
||||||
|
ilog << "Loaded image " << file << "!\n";
|
||||||
|
rowWidth = width * channels;
|
||||||
|
}
|
||||||
|
TexturedMaterial::~TexturedMaterial() {
|
||||||
|
delete(data);
|
||||||
|
}
|
||||||
|
|
||||||
static HitData checkIfTriangleGotHit(const Triangle& theTriangle, const Vec4& position, const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) {
|
static HitData checkIfTriangleGotHit(const Triangle& theTriangle, const Vec4& position, const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) {
|
||||||
// Möller–Trumbore intersection algorithm
|
// Möller–Trumbore intersection algorithm
|
||||||
// https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection
|
// https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection
|
||||||
|
@ -174,8 +227,26 @@ namespace Raytracing {
|
||||||
normal = Vec4{edge1.y() * edge2.z(), edge1.z() * edge2.x(), edge1.x() * edge2.y()} -
|
normal = Vec4{edge1.y() * edge2.z(), edge1.z() * edge2.x(), edge1.x() * edge2.y()} -
|
||||||
Vec4{edge1.z() * edge2.y(), edge1.x() * edge2.z(), edge1.y() * edge2.x()};
|
Vec4{edge1.z() * edge2.y(), edge1.x() * edge2.z(), edge1.y() * edge2.x()};
|
||||||
}
|
}
|
||||||
return {true, rayIntersectionPoint, normal, t};
|
|
||||||
|
// calculate triangle UV
|
||||||
|
// calculate the vector that runs between the vertex and the intersection point for all three vertices
|
||||||
|
auto vertex1ToIntersect = theTriangle.vertex1 - rayIntersectionPoint;
|
||||||
|
auto vertex2ToIntersect = theTriangle.vertex2 - rayIntersectionPoint;
|
||||||
|
auto vertex3ToIntersect = theTriangle.vertex3 - rayIntersectionPoint;
|
||||||
|
|
||||||
|
// the magnitude of the cross product of two vectors is double the area formed by the triangle of their intersection.
|
||||||
|
auto fullArea = 1 / Vec4::cross(theTriangle.vertex1 - theTriangle.vertex2, theTriangle.vertex1 - theTriangle.vertex3).magnitude();
|
||||||
|
// scale the area of sub triangles to be proportion to the area of the triangle
|
||||||
|
auto areaVert1 = Vec4::cross(vertex2ToIntersect, vertex3ToIntersect).magnitude() * fullArea;
|
||||||
|
auto areaVert2 = Vec4::cross(vertex3ToIntersect, vertex1ToIntersect).magnitude() * fullArea;
|
||||||
|
auto areaVert3 = Vec4::cross(vertex1ToIntersect, vertex2ToIntersect).magnitude() * fullArea;
|
||||||
|
|
||||||
|
// that area is how much each UV factors into the final UV coord
|
||||||
|
auto uv = theTriangle.uv1 * areaVert1 + theTriangle.uv2 * areaVert2 + theTriangle.uv3 * areaVert3;
|
||||||
|
|
||||||
|
return {true, rayIntersectionPoint, normal, t, uv.x(), uv.y()};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {false, Vec4(), Vec4(), 0};
|
return {false, Vec4(), Vec4(), 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Raytracing {
|
||||||
OpenCL openCl {0};
|
OpenCL openCl {0};
|
||||||
|
|
||||||
void OpenCL::init() {
|
void OpenCL::init() {
|
||||||
openCl = OpenCL{0};
|
|
||||||
}
|
}
|
||||||
OpenCL::OpenCL(int platformID, int deviceID): m_activePlatform(platformID) {
|
OpenCL::OpenCL(int platformID, int deviceID): m_activePlatform(platformID) {
|
||||||
m_CL_ERR = CL_SUCCESS;
|
m_CL_ERR = CL_SUCCESS;
|
||||||
|
|
Loading…
Reference in New Issue