Simple Normals Rendering

This commit is contained in:
IlyaShurupov 2023-10-16 13:38:56 +03:00 committed by Ilya Shurupov
parent b2fa4c4266
commit eb133745f9
9 changed files with 2296 additions and 156 deletions

View file

@ -2,19 +2,17 @@
using namespace tp;
Camera::Camera() {
lookAtPoint({ 0, 0, 0 }, { 2, 0, 0 }, { 0, 0, 1 });
}
Camera::Camera() { lookAtPoint({0, 0, 0}, {2, 0, 0}, {0, 0, 1}); }
Vec3F Camera::getTarget() const { return mTarget; }
const Vec3F& Camera::getTarget() const { return mTarget; }
void Camera::offset_target(halnf val) { mTarget += (mPos - mTarget).normalize() * val; }
Vec3F Camera::getForward() const { return (mTarget - mPos).normalize(); }
Vec3F Camera::getUp() const { return mUp; }
const Vec3F& Camera::getUp() const { return mUp; }
Vec3F& Camera::getPos() { return mPos; }
const Vec3F& Camera::getPos() const { return mPos; }
halnf Camera::getFar() const { return mFar; }
@ -26,107 +24,109 @@ void Camera::setRatio(halnf in) { mRatio = in; }
void Camera::setFOV(halnf in) { mFOV = in; }
void Camera::setFar(halnf in) { mFar = in; }
halnf Camera::getFOV() const { return mFOV; }
Mat4F Camera::calculateTransformationMatrix() {
return calculateProjectionMatrix() * calculateViewMatrix();
}
Mat4F Camera::calculateTransformationMatrix() { return calculateProjectionMatrix() * calculateViewMatrix(); }
Mat4F Camera::calculateViewMatrix() {
const Vec3F& F = (mPos - mTarget).unitV();
const Vec3F& S = mUp * F;
const Vec3F& U = F * S;
const Vec3F& P = mPos;
const Vec3F& F = (mPos - mTarget).unitV();
const Vec3F& S = mUp * F;
const Vec3F& U = F * S;
const Vec3F& P = mPos;
Mat4F out;
out[0] = Vec4F(S.x, S.y, S.z, -P.dot(S));
out[1] = Vec4F(U.x, U.y, U.z, -P.dot(U));
out[2] = Vec4F(F.x, F.y, F.z, -P.dot(F));
out[3] = Vec4F(0, 0, 0, 1);
return out;
Mat4F out;
out[0] = Vec4F(S.x, S.y, S.z, -P.dot(S));
out[1] = Vec4F(U.x, U.y, U.z, -P.dot(U));
out[2] = Vec4F(F.x, F.y, F.z, -P.dot(F));
out[3] = Vec4F(0, 0, 0, 1);
return out;
}
Mat4F Camera::calculateProjectionMatrix() const {
auto r = (halnf) sqrt(mRatio);
halnf c = 1 / r;
auto s = halnf(1.f / tan(mFOV / 2.f));
auto r = (halnf) sqrt(mRatio);
halnf c = 1 / r;
auto s = halnf(1.f / tan(mFOV / 2.f));
Mat4F out;
out[0] = Vec4F(s * r, 0, 0, 0);
out[1] = Vec4F(0, s * c, 0, 0);
out[2] = Vec4F(0, 0, -2.f / (mFar - mNear), -(mFar + mNear) / (mFar - mNear));
out[3] = Vec4F(0, 0, -1, 0);
return out;
Mat4F out;
out[0] = Vec4F(s * r, 0, 0, 0);
out[1] = Vec4F(0, s * c, 0, 0);
out[2] = Vec4F(0, 0, -2.f / (mFar - mNear), -(mFar + mNear) / (mFar - mNear));
out[3] = Vec4F(0, 0, -1, 0);
return out;
}
Vec3F Camera::project(Vec2F normalized) {
auto camMat = calculateTransformationMatrix();
auto inv = camMat.inv();
auto camMat = calculateTransformationMatrix();
auto inv = camMat.inv();
halnf z = halnf((((mTarget - mPos).length() - mNear) / (mFar - mNear) - 1.f / 2) * 2.f);
halnf w = halnf((mTarget - mPos).length());
Vec4<halnf> world_pos4(normalized.x * w, normalized.y * w, z, w);
halnf z = halnf((((mTarget - mPos).length() - mNear) / (mFar - mNear) - 1.f / 2) * 2.f);
halnf w = halnf((mTarget - mPos).length());
Vec4<halnf> world_pos4(normalized.x * w, normalized.y * w, z, w);
return Vec3F(inv * world_pos4);
return Vec3F(inv * world_pos4);
}
Vec2F Camera::project(const Vec3F& world) {
Vec4F world_pos4(world.x, world.y, world.z, 1);
Vec4F transformed = calculateViewMatrix() * world_pos4;
transformed = calculateProjectionMatrix() * transformed;
return { transformed[0] / transformed[3], transformed[1] / transformed[3] };
Vec4F world_pos4(world.x, world.y, world.z, 1);
Vec4F transformed = calculateViewMatrix() * world_pos4;
transformed = calculateProjectionMatrix() * transformed;
return {transformed[0] / transformed[3], transformed[1] / transformed[3]};
}
Vec2F Camera::project(const tp::Vec3F& world, const tp::Mat4F& viewMat, const tp::Mat4F& projMat) {
Vec4F world_pos4(world.x, world.y, world.z, 1);
Vec4F transformed = viewMat * world_pos4;
transformed = projMat * transformed;
return { transformed[0] / transformed[3], transformed[1] / transformed[3] };
Vec4F world_pos4(world.x, world.y, world.z, 1);
Vec4F transformed = viewMat * world_pos4;
transformed = projMat * transformed;
return {transformed[0] / transformed[3], transformed[1] / transformed[3]};
}
void Camera::lookAtPoint(const Vec3F& aTarget, const Vec3F& aPos, Vec3F aUp) {
if (aTarget == aPos) return;
mPos = aPos;
mTarget = aTarget;
Vec3F f = (mPos - mTarget).normalize();
mUp = f * (aUp.normalize() * f);
if (aTarget == aPos) {
return;
}
mPos = aPos;
mTarget = aTarget;
Vec3F f = (mPos - mTarget).normalize();
mUp = f * (aUp.normalize() * f);
}
void Camera::zoom(halnf ratio) {
ratio = abs(ratio);
if (ratio < 0.1f) {
return;
}
if (abs((mPos - mTarget).length2()) < 0.05f && ratio < 1.f) {
return;
}
mPos = mTarget + (mPos - mTarget) * ratio;
lookAtPoint(mTarget, mPos, mUp);
ratio = abs(ratio);
if (ratio < 0.1f) {
return;
}
if (abs((mPos - mTarget).length2()) < 0.05f && ratio < 1.f) {
return;
}
mPos = mTarget + (mPos - mTarget) * ratio;
lookAtPoint(mTarget, mPos, mUp);
}
void Camera::move(Vec2F aPos, Vec2F aPrevPos) {
Vec3F p1 = project(aPrevPos);
Vec3F p2 = project(aPos);
Vec3F move = p1 - p2;
mPos += move;
mTarget += move;
lookAtPoint(mTarget, mPos, mUp);
Vec3F p1 = project(aPrevPos);
Vec3F p2 = project(aPos);
Vec3F move = p1 - p2;
mPos += move;
mTarget += move;
lookAtPoint(mTarget, mPos, mUp);
}
void Camera::rotate(halnf angleX, halnf angleY) {
Vec3F wup(0, 0, 1);
mPos -= mTarget;
Vec3F wup(0, 0, 1);
mPos -= mTarget;
mat3f rotZ = mat3f::rotatorDir(wup, angleX);
mPos = rotZ * mPos;
mUp = rotZ * mUp;
mat3f rotZ = mat3f::rotatorDir(wup, angleX);
mPos = rotZ * mPos;
mUp = rotZ * mUp;
Vec3F f = mPos.unitV();
Vec3F s = mUp * f;
Vec3F f = mPos.unitV();
Vec3F s = mUp * f;
mPos = mat3f::rotatorDir(s, -angleY) * mPos;
mPos = mat3f::rotatorDir(s, -angleY) * mPos;
mPos += mTarget;
mPos += mTarget;
lookAtPoint(mTarget, mPos, mUp);
}
lookAtPoint(mTarget, mPos, mUp);
}

View file

@ -95,3 +95,6 @@ void Topology::updateTransformed() {
mTrigCaches[idx].updateCache(mPointsTransformed);
}
}
const Buffer<TrigCache>& Topology::getTrigs() const { return mTrigCaches; }

View file

@ -4,43 +4,43 @@
#include "Ray.hpp"
namespace tp {
class Camera {
Vec3F mPos, mTarget, mUp;
halnf mFOV = (halnf) (PI) / 4;
halnf mNear = 0.001f;
halnf mFar = 100.f;
halnf mRatio = 1.f;
class Camera {
Vec3F mPos, mTarget, mUp;
halnf mFOV = (halnf) (PI) / 4;
halnf mNear = 0.001f;
halnf mFar = 100.f;
halnf mRatio = 1.f;
public:
Camera();
~Camera() = default;
public:
Camera();
~Camera() = default;
void setRatio(halnf ratio);
void setFOV(halnf fov);
void setRatio(halnf ratio);
void setFOV(halnf fov);
void setFar(halnf far);
[[nodiscard]] Vec3F& getPos();
[[nodiscard]] Vec3F getTarget() const;
[[nodiscard]] Vec3F getForward() const;
[[nodiscard]] Vec3F getUp() const;
[[nodiscard]] halnf getRatio() const;
[[nodiscard]] halnf getFOV() const;
[[nodiscard]] halnf getFar() const;
[[nodiscard]] halnf getNear() const;
[[nodiscard]] const Vec3F& getPos() const;
[[nodiscard]] const Vec3F& getTarget() const;
[[nodiscard]] Vec3F getForward() const;
[[nodiscard]] const Vec3F& getUp() const;
[[nodiscard]] halnf getRatio() const;
[[nodiscard]] halnf getFOV() const;
[[nodiscard]] halnf getFar() const;
[[nodiscard]] halnf getNear() const;
public:
void lookAtPoint(const Vec3F& aTarget, const Vec3F& aPos, Vec3F aUp);
void rotate(halnf anglex, halnf angleY);
void move(Vec2F aPos, Vec2F aPrevPos);
void zoom(halnf ratio);
void offset_target(halnf val);
public:
void lookAtPoint(const Vec3F& aTarget, const Vec3F& aPos, Vec3F aUp);
void rotate(halnf anglex, halnf angleY);
void move(Vec2F aPos, Vec2F aPrevPos);
void zoom(halnf ratio);
void offset_target(halnf val);
public:
[[nodiscard]] Mat4F calculateTransformationMatrix();
[[nodiscard]] Mat<halnf, 4, 4> calculateProjectionMatrix() const;
[[nodiscard]] Mat<halnf, 4, 4> calculateViewMatrix();
[[nodiscard]] Vec3F project(Vec2F normalized);
[[nodiscard]] Vec2F project(const Vec3F& world);
[[nodiscard]] static Vec2F project(const tp::Vec3F& world, const tp::Mat4F& viewMat, const tp::Mat4F& projMat);
};
}
public:
[[nodiscard]] Mat4F calculateTransformationMatrix();
[[nodiscard]] Mat<halnf, 4, 4> calculateProjectionMatrix() const;
[[nodiscard]] Mat<halnf, 4, 4> calculateViewMatrix();
[[nodiscard]] Vec3F project(Vec2F normalized);
[[nodiscard]] Vec2F project(const Vec3F& world);
[[nodiscard]] static Vec2F project(const tp::Vec3F& world, const tp::Mat4F& viewMat, const tp::Mat4F& projMat);
};
}

View file

@ -44,5 +44,6 @@ namespace tp {
void addTrig(const Vec3F& v1, const Vec3F& v2, const Vec3F& v3);
void transformPoint(Vec3F& vert);
void updateTransformed();
[[nodiscard]] const Buffer<TrigCache>& getTrigs() const;
};
}
}

View file

@ -4,6 +4,7 @@
#include "Buffer.hpp"
#include "RayTracer.hpp"
#include "Strings.hpp"
#include "Timing.hpp"
#include "Vec.hpp"
#include "OBJ_Loader.h"
@ -71,13 +72,24 @@ void renderCommand(const String& scenePath, RayTracer::RenderBuffer::Index2D siz
loadScene(scene, scenePath);
scene.mCamera.lookAtPoint({0, 0, 0}, {-3, -3, 3}, {1, 1, 1});
scene.mCamera.setFOV(3.14 / 4);
scene.mCamera.setRatio((halnf) size.y / (halnf) size.x);
scene.mCamera.setFar(100);
RayTracer::RenderBuffer output;
output.reserve(size);
RayTracer rayt;
auto start = get_time();
rayt.render(scene, output);
auto end = get_time();
printf("\n Render finished with average render time per sample - %i (ms)\n", end - start);
writeImage(output);
}
@ -86,7 +98,7 @@ int main() {
tp::ModuleManifest module("Rayt", nullptr, nullptr, deps);
if (module.initialize()) {
renderCommand("scene.obj", {1000, 1000});
renderCommand("scene.obj", {600, 600});
module.deinitialize();
}

View file

@ -1,12 +1,10 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl Material
Ns 323.999994
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
newmtl None
Ns 500
Ka 0.8 0.8 0.8
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,14 @@
#include "MathCommon.hpp"
#include "NewPlacement.hpp"
#include "CommandLine.hpp"
#include "Module.hpp"
#include "Ray.hpp"
#include "RayTracer.hpp"
#include "TypeInfo.hpp"
#include <cstdio>
using namespace tp;
@ -11,10 +16,79 @@ ModuleManifest* sDependencies[] = {&gModuleMath, &gModuleCommandLine, &gModuleCo
ModuleManifest tp::gModuleRayTracer = ModuleManifest("RayTracer", nullptr, nullptr, sDependencies);
void RayTracer::render(const Scene& scene, RayTracer::RenderBuffer& buff) {
for (RayTracer::RenderBuffer::Index i = 0; i < buff.size().x; i++) {
for (RayTracer::RenderBuffer::Index j = 0; j < buff.size().y; j++) {
buff.set({i, j}, RGBA(1.f, 1.f, 1.f, 1.f));
void RayTracer::castRay(const Ray& ray, RayCastData& out, alnf far) {
out.hit = false;
far *= far;
for (auto obj : mScene->mObjects) {
for (auto trig : obj->getTrigs()) {
if (trig->castRay(ray)) {
// printf("Hit\n");
auto dist = (trig->getHitPos() - ray.pos).length2();
if (far > dist) {
out.trig = &trig.data();
out.hitPos = trig->getHitPos();
out.obj = &obj.data();
out.hit = true;
far = dist;
}
}
}
}
}
void RayTracer::render(const Scene& scene, RayTracer::RenderBuffer& buff) {
mScene = &scene;
mBuff = &buff;
auto pos = mScene->mCamera.getPos();
auto fov = mScene->mCamera.getFOV();
auto height = sqrt(mScene->mCamera.getRatio());
auto width = 1.f / height;
auto forward = mScene->mCamera.getForward();
auto up = mScene->mCamera.getUp();
auto right = forward.cross(up);
auto planeCenter = pos + (forward * halnf(width / (2.f * tan(fov / 2.f))));
auto planeCenterOffset = (up * (halnf) height / 2.f) - (right * (halnf) width / 2.f);
auto planeLeftTop = planeCenter + planeCenterOffset;
RayCastData castData;
Ray ray = {
{0, 0, 0},
pos
};
Vec3F iterPoint = {0, 0, 0};
Vec3F deltaX = right * halnf(width / (alnf) buff.size().x);
Vec3F deltaY = up * halnf(-height / (alnf) buff.size().y);
for (RayTracer::RenderBuffer::Index i = 0; i < buff.size().x; i++) {
for (RayTracer::RenderBuffer::Index j = 0; j < buff.size().y; j++) {
iterPoint = planeLeftTop + ((deltaX * (halnf) i) + (deltaY * (halnf) j));
ray.dir = (iterPoint - pos).unitV();
castRay(ray, castData, mScene->mCamera.getFar());
if (castData.hit) {
auto normal = castData.trig->getNormal();
normal.normalize();
RGBA col = {normal.x * 0.5f + 0.5f, normal.y * 0.5f + 0.5f, normal.z * 0.5f + 0.5f, 1.f};
auto depth = 1 - clamp((halnf) (castData.hitPos - ray.pos).length(), 0.f, mScene->mCamera.getFar()) / mScene->mCamera.getFar();
// buff.set({i, j}, {depth, depth, depth, 1.f});
buff.set({i, j}, col);
} else {
buff.set({i, j}, RGBA(0.f, 0.f, 0.f, 0.f));
}
}
}
}

View file

@ -6,17 +6,21 @@
#include "Color.hpp"
#include "Module.hpp"
#include "Topology.hpp"
#include "Vec.hpp"
namespace tp {
extern ModuleManifest gModuleRayTracer;
class Scene {
public:
typedef Topology Object;
public:
Scene() = default;
public:
Buffer<Topology> mObjects;
Buffer<Object> mObjects;
Camera mCamera;
};
@ -24,8 +28,28 @@ namespace tp {
public:
typedef Buffer2D<RGBA> RenderBuffer;
struct RenderSettings {
alni samplesiPerPixel = 1;
alni rayBounces = 1;
};
public:
RayTracer() = default;
void render(const Scene& scene, RenderBuffer& buff);
private:
struct RayCastData {
const Scene::Object* obj = nullptr;
TrigCache* trig = nullptr;
Vec3F hitPos = {0, 0, 0};
bool hit = false;
};
void castRay(const Ray& ray, RayCastData& out, alnf far);
private:
RenderSettings mSettings;
const Scene* mScene = nullptr;
RenderBuffer* mBuff = nullptr;
};
}