diff --git a/Math/private/Topology.cpp b/Math/private/Topology.cpp index 10d49af..d47b0da 100644 --- a/Math/private/Topology.cpp +++ b/Math/private/Topology.cpp @@ -12,89 +12,89 @@ TrigCache::TrigCache() : mP1(0), mP2(0), mP3(0) {} TrigCache::TrigCache(ualni v1, ualni v2, ualni v3) : mP1(v1), mP2(v2), mP3(v3) {} TrigCache::TrigCache(const TrigCache& in) { - mP1 = in.mP1; - mP2 = in.mP2; - mP3 = in.mP3; + mP1 = in.mP1; + mP2 = in.mP2; + mP3 = in.mP3; - mEdgeP1P2 = in.mEdgeP1P2; - mEdgeP1P3 = in.mEdgeP1P3; + mEdgeP1P2 = in.mEdgeP1P2; + mEdgeP1P3 = in.mEdgeP1P3; - mOrigin = in.mOrigin; - mNormal = in.mNormal; + mOrigin = in.mOrigin; + mNormal = in.mNormal; } void TrigCache::updateCache(const Buffer& points) { - mOrigin = points[mP1]; - mEdgeP1P2 = points[mP2] - points[mP1]; - mEdgeP1P3 = points[mP3] - points[mP1]; - mNormal = (points[mP2] - points[mP1]).cross(points[mP3] - points[mP1]).unitV(); + mOrigin = points[mP1]; + mEdgeP1P2 = points[mP2] - points[mP1]; + mEdgeP1P3 = points[mP3] - points[mP1]; + mNormal = (points[mP2] - points[mP1]).cross(points[mP3] - points[mP1]).unitV(); } bool TrigCache::castRay(const Ray& ray) const { - static Vec3F h, s, q; - static halnf a, f, u, v; - static halnf t; + static Vec3F h, s, q; + static halnf a, f, u, v; + static halnf t; - h = ray.dir.cross(mEdgeP1P3); - a = mEdgeP1P2.dot(h); + h = ray.dir.cross(mEdgeP1P3); + a = mEdgeP1P2.dot(h); - if (a > -EPSILON && a < EPSILON) { - return false; - } + if (a > -EPSILON && a < EPSILON) { + return false; + } - f = 1.f / a; - s = ray.pos - mOrigin; - u = f * s.dot(h); + f = 1.f / a; + s = ray.pos - mOrigin; + u = f * s.dot(h); - if (u < 0.0 || u > 1.0) { - return false; - } + if (u < 0.0 || u > 1.0) { + return false; + } - q = s.cross(mEdgeP1P2); - v = f * ray.dir.dot(q); + q = s.cross(mEdgeP1P2); + v = f * ray.dir.dot(q); - if (v < 0.f || u + v > 1.f) { - return false; - } + if (v < 0.f || u + v > 1.f) { + return false; + } - t = f * mEdgeP1P3.dot(q); - if (t > EPSILON) { - gHitPos = ray.pos + ray.dir * t; - return true; - } else { - return false; - } + t = f * mEdgeP1P3.dot(q); + if (t > EPSILON) { + gHitPos = ray.pos + ray.dir * t; + return true; + } else { + return false; + } } const Vec3F& TrigCache::getHitPos() { return gHitPos; } const Vec3F& TrigCache::getNormal() const { return mNormal; } -void Topology::addTrig(const Vec3F& v1, const Vec3F& v2, const Vec3F& v3) { - auto trigIdx = mPoints.size(); +void TopologyCache::updateCache() { + TransformedNormals.clear(); + TransformedPoints.clear(); + TrigCaches.clear(); - mPoints.append(v1); - mPoints.append(v2); - mPoints.append(v3); + if (!Source) { + return; + } - TrigCache newTrig(trigIdx, trigIdx + 1, trigIdx + 2); - mTrigCaches.append(newTrig); + TransformedPoints.reserve(Source->Points.size()); + for (auto idx : Range(TransformedPoints.size())) { + TransformedPoints[idx] = Source->Basis.transform(Source->Points[idx]); + TransformedPoints[idx] += Source->Origin; + } + + TransformedNormals.reserve(Source->Normals.size()); + for (auto idx : Range(TransformedNormals.size())) { + TransformedNormals[idx] = Source->Basis.transform(Source->Normals[idx]); + } + + TrigCaches.reserve(Source->Indexes.size()); + for (auto idx : Range(TrigCaches.size())) { + TrigCaches[idx].mP1 = Source->Indexes[idx].x; + TrigCaches[idx].mP2 = Source->Indexes[idx].y; + TrigCaches[idx].mP3 = Source->Indexes[idx].z; + TrigCaches[idx].updateCache(TransformedPoints); + } } - -void Topology::transformPoint(Vec3F& vert) { - mBasis.transform(vert); - vert += mOrigin; -} - -void Topology::updateTransformed() { - mPointsTransformed = mPoints; - for (auto idx : Range(mPointsTransformed.size())) { - transformPoint(mPointsTransformed[idx]); - } - for (auto idx : Range(mTrigCaches.size())) { - mTrigCaches[idx].updateCache(mPointsTransformed); - } -} - -const Buffer& Topology::getTrigs() const { return mTrigCaches; } - diff --git a/Math/public/Mat.hpp b/Math/public/Mat.hpp index e5ce928..59ce954 100644 --- a/Math/public/Mat.hpp +++ b/Math/public/Mat.hpp @@ -4,765 +4,721 @@ namespace tp { - template - class Mat { - typedef Vec MVec; - - private: - MVec mCol[tNColoumns]; - - public: - Mat() = default; - - explicit Mat(const Type& val) { - operator=(val); - } - - Mat(const Mat& in) { - operator=(in); - } - - MVec& operator[](alni i) { - DEBUG_ASSERT(i < tNColoumns && i >= 0) - return mCol[i]; - } - - const MVec& operator[](alni i) const { - DEBUG_ASSERT(i < tNColoumns && i >= 0) - return mCol[i]; - } - - Mat& operator=(const Mat& in) { - if (&in == this) return *this; - memCopy(this, &in, sizeof(Mat)); - return *this; - } - - Mat& operator=(const Type& val) { - clear(val); - return *this; - } - - void clear(const Type& val) { - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - (*this)[i][j] = val; - } - } - } - - void setDiagonal(const Type& val) { - halni len = min(tNColoumns, tNRows); - for (halni i = 0; i < len; i++) { - (*this)[i][i] = val; - } - } - - Mat& fillRandom() { - DEBUG_ASSERT(0) - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - (*this)[i][j] = (Type) 0; - } - } - return *this; - } - - Mat operator-() { - Mat out; - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - out[i][j] = -(*this)[i][j]; - } - } - return out; - } - - Mat& operator+=(const Mat& in) { - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - (*this)[i][j] += in[i][j]; - } - } - return *this; - } - - Mat& operator-=(const Mat& in) { - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - (*this)[i][j] -= in[i][j]; - } - } - return *this; - } - - Mat& operator+=(const Type& val) { - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - (*this)[i][j] += val; - } - } - return *this; - } - - Mat& operator-=(const Type& val) { - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - (*this)[i][j] -= val; - } - } - return *this; - } - - Mat& operator/=(const Type& val) { - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - (*this)[i][j] /= val; - } - } - return *this; - } - - Mat& operator*=(const Type& val) { - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - (*this)[i][j] *= val; - } - } - return *this; - } - - Mat operator+(const Mat& in) { - Mat out; - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - out[i][j] = (*this)[i][j] + in[i]; - } - } - return out; - } - - Mat operator-(const Mat& in) { - Mat out; - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - out[i][j] = (*this)[i][j] - in[i]; - } - } - return out; - } - - Mat operator+(const Type& val) { - Mat out; - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - out[i][j] = (*this)[i][j] + val; - } - } - return out; - } - - Mat operator-(const Type& val) { - Mat out; - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - out[i][j] = (*this)[i][j] - val; - } - } - return out; - } - - Mat operator*(const Type& val) { - Mat out; - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - out[i][j] = (*this)[i][j] * val; - } - } - return out; - } - - Mat operator/(const Type& val) { - Mat out; - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = 0; j < tNRows; j++) { - out[i][j] = (*this)[i][j] / val; - } - } - return out; - } - - // Matrix Properties - MVec transform(const MVec& in) const { - static_assert(tNRows == tNColoumns); - MVec out; - for (halni i = 0; i < tNRows; i++) { - Type tmp = 0; - for (halni j = 0; j < tNColoumns; j++) { - tmp += (*this)[i][j] * in[j]; - } - out[i] = tmp; - } - return out; - } - - Mat transform(const Mat& in) const { - Mat out; - out.clear(0); - for (halni i = 0; i < tNRows; i++) { - for (halni j = 0; j < tNRows; j++) { - for (halni u = 0; u < tNRows; u++) { - out[i][j] += (*this)[i][u] * in[u][j]; - } - } - } - return out; - } - - Mat& transpose() { - static_assert( tNRows == tNColoumns); - for (halni i = 0; i < tNColoumns; i++) { - for (halni j = i + 1; j < tNColoumns; j++) { - swap((*this)[i][j], (*this)[j][i]); - } - } - return *this; - } - - Mat operator*(const Mat& in) const { - return transform(in); - } - - MVec operator*(const MVec& in) const { - return transform(in); - } - - Mat minor(halni p, halni q) { - Mat out; - halni i = 0, j = 0; - for (halni row = 0; row < tNRows; row++) { - for (halni col = 0; col < tNRows; col++) { - if (row != p && col != q) { - out[i][j++] = (*this)[row][col]; - if (j == tNRows - 1) { - j = 0; - i++; - } - } - } - } - return out; - } - - Type det() { - static_assert( tNRows == tNColoumns); - - Type out = 0; - - if (tNRows == 1) { - return (*this)[0][0]; - } - if (tNRows == 2) { - return ((*this)[0][0] * (*this)[1][1]) - ((*this)[1][0] * (*this)[0][1]); - } - - halni sign = 1; - for (int i = 0; i < tNRows; i++) { - out += sign * (*this)[0][i] * minor(0, i).det(); - sign = -sign; - } - return out; - } - - Mat cofactors() { - static_assert( tNRows == tNColoumns); - Mat out; - for (int i = 0; i < tNRows; i++) { - for (int j = 0; j < tNRows; j++) { - Type sign = (Type) ((i + j + 2) & 1 ? -1 : 1); - out[i][j] = minor(j, i).det() * sign; - } - } - return out; - } - - Mat inv() { - Type detV = det(); - DEBUG_ASSERT(detV) - return cofactors() /= detV; - } - }; - - template - using Mat2 = Mat; - using Mat2F = Mat2; - - template - class Mat { - typedef Vec MVec; - - MVec i; - MVec j; - - public: - - Mat() = default; - - explicit Mat(const Type& val) { - operator=(val); - } - - Mat(const MVec& pi, const MVec& pj) { - i.x = pi.x; - i.y = pi.y; - j.x = pj.x; - j.y = pj.y; - } - - Mat(Type ix, Type iy, Type jx, Type jy) { - i.x = ix; - i.y = iy; - j.x = jx; - j.y = jy; - } - - Mat(const Mat& in) { - operator=(in); - } - - MVec& operator[](alni idx) { - DEBUG_ASSERT(idx < 2 && idx >= 0) - return (&i)[idx]; - } - - const MVec& operator[](alni idx) const { - DEBUG_ASSERT(idx < 2 && idx >= 0) - return (&i)[idx]; - } - - Mat& operator=(const Mat& in) { - memCopy(this, &in, sizeof(Mat2)); - return *this; - } - - Mat& operator=(const Type& val) { - clear(val); - return *this; - } - - void clear(const Type& val) { - i.x = val; - i.y = val; - j.x = val; - j.y = val; - } - - void setDiagonal(const Type& val) { - i.x = val; - j.y = val; - } - - Mat& fillRandom() { - DEBUG_ASSERT(0) - i.x = (Type) 0; - i.y = (Type) 0; - j.x = (Type) 0; - j.y = (Type) 0; - return *this; - } - - Mat operator-() { - return Mat(-i.x, -i.y, -j.x, -j.y); - } - - Mat& operator+=(const Mat& in) { - i.x += in.i.x; - i.y += in.i.y; - j.x += in.j.x; - j.y += in.j.y; - return *this; - } - - Mat& operator-=(const Mat& in) { - i.x -= in.i.x; - i.y -= in.i.y; - j.x -= in.j.x; - j.y -= in.j.y; - return *this; - } - - Mat& operator+=(Type val) { - i.x += val; - i.y += val; - j.x += val; - j.y += val; - return *this; - } - - Mat& operator-=(Type val) { - i.x -= val; - i.y -= val; - j.x -= val; - j.y -= val; - return *this; - } - - Mat& operator/=(Type val) { - i.x /= val; - i.y /= val; - j.x /= val; - j.y /= val; - return *this; - } - - Mat& operator*=(Type val) { - i.x *= val; - i.y *= val; - j.x *= val; - j.y *= val; - return *this; - } - - Mat operator+(const Mat& in) { - Mat out; - out.i.x = i.x + in.i.x; - out.i.y = i.y + in.i.y; - out.j.x = j.x + in.j.x; - out.j.y = j.y + in.j.y; - return out; - } - - Mat operator-(const Mat& in) { - Mat out; - out.i.x = i.x - in.i.x; - out.i.y = i.y - in.i.y; - out.j.x = j.x - in.j.x; - out.j.y = j.y - in.j.y; - return out; - } - - Mat operator+(const Type& val) { - Mat out; - out.i.x = i.x + val; - out.i.y = i.y + val; - out.j.x = j.x + val; - out.j.y = j.y + val; - return out; - } - - Mat operator-(const Type& val) { - Mat out; - out.i.x = i.x - val; - out.i.y = i.y - val; - out.j.x = j.x - val; - out.j.y = j.y - val; - return out; - } - - Mat operator*(const Type& val) { - Mat out; - out.i.x = i.x * val; - out.i.y = i.y * val; - out.j.x = j.x * val; - out.j.y = j.y * val; - return out; - } - - Mat operator/(const Type& val) { - Mat out; - out.i.x = i.x / val; - out.i.y = i.y / val; - out.j.x = j.x / val; - out.j.y = j.y / val; - return out; - } - - // Matrix Properties - MVec transform(const MVec& in) const { - return MVec(i.x * in.x + i.y * in.y, j.x * in.y + j.y * in.x); - } - - Mat transform(const Mat& in) const { - Mat out; - out.i.x = i.x * in.i.x + j.x * in.i.y; - out.i.y = i.y * in.i.x + j.y * in.i.y; - out.j.x = i.x * in.j.x + j.x * in.j.y; - out.j.y = i.y * in.j.x + j.y * in.j.y; - return out; - } - - Mat operator*(const Mat& in) { - return transform(in); - } - - Mat& transpose() { - swap(j.x, i.y); - return *this; - } - - Type det() { - return i.x * j.y - i.y * j.x; - } - - Mat cofactors() { - return Mat(j.y, -i.y, -j.x, i.x); - } - - Mat inv() { - Type detV = det(); - DEBUG_ASSERT(detV != 0) - return (cofactors() /= detV); - } - }; - - template - using mat3 = Mat; - using mat3f = mat3; - - template - class Mat { - typedef Vec3 vec; - - public: - vec I; - vec J; - vec K; - - public: - Mat() = default; - - explicit Mat(Type val) { - I.assign(val, 0.f, 0.f); - J.assign(0.f, val, 0.f); - K.assign(0.f, 0.f, val); - } - - Mat(const vec& i, const vec& j, const vec& k) { - I = i; - J = j; - K = k; - } - - Mat(const Mat& in) { - this->I = in.I; - this->J = in.J; - this->K = in.K; - } - - void assign(const vec& i, const vec& j, const vec& k) { - I = i; - J = j; - K = k; - } - - Mat& fillRandom() { - I.randf(); - J.randf(); - K.randf(); - return *this; - } - - vec& operator[](alni i) { - DEBUG_ASSERT(i < 3 && i >= 0) - return (&I)[i]; - } - - const vec& operator[](alni i) const { - DEBUG_ASSERT(i < 3 && i >= 0) - return (&I)[i]; - } - - // create on stack - Mat operator+(const Mat& in) { return Mat(I + in.I, J + in.J, K + in.K); } - Mat operator-(const Mat& in) { return Mat(I - in.I, J - in.J, K - in.K); } - Mat operator+(Type val) { return Mat(I + val, J + val, K + val); } - Mat operator-(Type val) { return Mat(I - val, J - val, K - val); } - Mat operator*(Type val) { return Mat(I * val, J * val, K * val); } - Mat operator/(Type val) { return Mat(I / val, J / val, K / val); } - - // write - Mat& operator=(const Mat& in) { - I = in.I; - J = in.J; - K = in.K; - return *this; - } - - Mat& operator+=(const Mat& in) { - I += in.I; - J += in.J; - K += in.K; - return *this; - } - - Mat& operator-=(const Mat& in) { - I -= in.I; - J -= in.J; - K -= in.K; - return *this; - } - - Mat& operator+=(Type val) { - I += val; - J += val; - K += val; - return *this; - } - - Mat& operator-=(Type val) { - I -= val; - J -= val; - K -= val; - return *this; - } - - Mat& operator*=(Type val) { - I *= val; - J *= val; - K *= val; - return *this; - } - - Mat& operator/=(Type val) { - I /= val; - J /= val; - K /= val; - return *this; - } - - // Matrix transformation - vec transform(const vec& in) { - return vec( - I.x * in.x + I.y * in.y + I.z * in.z, - J.x * in.x + J.y * in.y + J.z * in.z, - K.x * in.x + K.y * in.y + K.z * in.z - ); - } - - Mat transform(const Mat& in) { - return Mat( - {(in.I.x * I.x + in.I.y * J.x + in.I.z * K.x), (in.I.x * I.y + in.I.y * J.y + in.I.z * K.y), (in.I.x * I.z + in.I.y * J.z + in.I.z * K.z)}, - {(in.J.x * I.x + in.J.y * J.x + in.J.z * K.x), (in.J.x * I.y + in.J.y * J.y + in.J.z * K.y), (in.J.x * I.z + in.J.y * J.z + in.J.z * K.z)}, - {(in.K.x * I.x + in.K.y * J.x + in.K.z * K.x), (in.K.x * I.y + in.K.y * J.y + in.K.z * K.y), (in.K.x * I.z + in.K.y * J.z + in.K.z * K.z)} - ); - } - - vec operator*(const vec& in) { - return transform(in); - } - - Mat operator*(const Mat& in) { - return transform(in); - } - - Mat minor(halni, halni) { - Mat out; - return out; - } - - Mat& transpose() { - swap(I.y, J.x); - swap(I.z, K.x); - swap(J.z, K.y); - return *this; - } - - Type det() { - return ( - +I.x * (J.y * K.z - J.z * K.y) - - I.y * (J.x * K.z - J.z * K.x) - + I.z * (J.x * K.y - J.y * K.x) - ); - } - - Mat cofactors() { - return Mat( - vec(+(J.y * K.z - J.z * K.y), -(I.y * K.z - I.z * K.y), +(I.y * J.z - I.z * J.y)), - vec(-(J.x * K.z - J.z * K.x), +(I.x * K.z - I.z * K.x), -(I.x * J.z - I.z * J.x)), - vec(+(J.x * K.y - J.y * K.x), -(I.x * K.y - I.y * K.x), +(I.x * J.y - I.y * J.x)) - ); - } - - Mat inv() { - return cofactors() /= det(); - } - - Mat rotatorX(alnf angle) { - alnf cosA = (alnf) cos(angle); - alnf sinA = (alnf) sin(angle); - return { - {1, 0, 0}, - {0, cosA, -sinA}, - {0, sinA, cosA} - }; - } - - Mat rotatorY(alnf angle) { - alnf cosA = (alnf) cos(angle); - alnf sinA = (alnf) sin(angle); - return { - {cosA, 0, sinA}, - {0, 1, 0}, - {-sinA, 0, cosA} - }; - } - - Mat rotatorZ(alnf angle) { - alnf cosA = (alnf) cos(angle); - alnf sinA = (alnf) sin(angle); - return { - {cosA, -sinA, 0}, - {sinA, cosA, 0}, - {0, 0, 1} - }; - } - - static Mat rotatorDir(vec dir, alnf angle) { - dir.normalize(); - - Mat out; - alnf cosA = (alnf) cos(angle); - alnf sinA = (alnf) sin(angle); - alnf tmp = 1 - cosA; - - out.I.x = (Type) (cosA + dir.x * dir.x * tmp); - out.I.y = (Type) (dir.x * dir.y * tmp - dir.z * sinA); - out.I.z = (Type) (dir.x * dir.z * tmp + dir.y * sinA); - - out.J.x = (Type) (dir.y * dir.x * tmp + dir.z * sinA); - out.J.y = (Type) (cosA + dir.y * dir.y * tmp); - out.J.z = (Type) (dir.y * dir.z * tmp - dir.x * sinA); - - out.K.x = (Type) (dir.z * dir.x * tmp - dir.y * sinA); - out.K.y = (Type) (dir.z * dir.y * tmp + dir.x * sinA); - out.K.z = (Type) (cosA + dir.z * dir.z * tmp); - - return out; - } - }; - - template - using Mat4 = Mat; - - using Mat4F = Mat4; - using Mat4I = Mat4; - - template - class Mat< Type, 0, 0 > { - typedef Vec MVec; - MVec dummy; - - public: - MVec& operator[](alni) { - return dummy; - } - - const MVec& operator[](alni) const { - return dummy; - } - - Type det() { - return Type(); - } - }; -} \ No newline at end of file + template + class Mat { + typedef Vec MVec; + + private: + MVec mCol[tNColoumns]; + + public: + Mat() = default; + + explicit Mat(const Type& val) { operator=(val); } + + Mat(const Mat& in) { operator=(in); } + + MVec& operator[](alni i) { + DEBUG_ASSERT(i < tNColoumns && i >= 0) + return mCol[i]; + } + + const MVec& operator[](alni i) const { + DEBUG_ASSERT(i < tNColoumns && i >= 0) + return mCol[i]; + } + + Mat& operator=(const Mat& in) { + if (&in == this) { + return *this; + } + memCopy(this, &in, sizeof(Mat)); + return *this; + } + + Mat& operator=(const Type& val) { + clear(val); + return *this; + } + + void clear(const Type& val) { + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + (*this)[i][j] = val; + } + } + } + + void setDiagonal(const Type& val) { + halni len = min(tNColoumns, tNRows); + for (halni i = 0; i < len; i++) { + (*this)[i][i] = val; + } + } + + Mat& fillRandom() { + DEBUG_ASSERT(0) + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + (*this)[i][j] = (Type) 0; + } + } + return *this; + } + + Mat operator-() { + Mat out; + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + out[i][j] = -(*this)[i][j]; + } + } + return out; + } + + Mat& operator+=(const Mat& in) { + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + (*this)[i][j] += in[i][j]; + } + } + return *this; + } + + Mat& operator-=(const Mat& in) { + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + (*this)[i][j] -= in[i][j]; + } + } + return *this; + } + + Mat& operator+=(const Type& val) { + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + (*this)[i][j] += val; + } + } + return *this; + } + + Mat& operator-=(const Type& val) { + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + (*this)[i][j] -= val; + } + } + return *this; + } + + Mat& operator/=(const Type& val) { + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + (*this)[i][j] /= val; + } + } + return *this; + } + + Mat& operator*=(const Type& val) { + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + (*this)[i][j] *= val; + } + } + return *this; + } + + Mat operator+(const Mat& in) { + Mat out; + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + out[i][j] = (*this)[i][j] + in[i]; + } + } + return out; + } + + Mat operator-(const Mat& in) { + Mat out; + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + out[i][j] = (*this)[i][j] - in[i]; + } + } + return out; + } + + Mat operator+(const Type& val) { + Mat out; + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + out[i][j] = (*this)[i][j] + val; + } + } + return out; + } + + Mat operator-(const Type& val) { + Mat out; + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + out[i][j] = (*this)[i][j] - val; + } + } + return out; + } + + Mat operator*(const Type& val) { + Mat out; + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + out[i][j] = (*this)[i][j] * val; + } + } + return out; + } + + Mat operator/(const Type& val) { + Mat out; + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = 0; j < tNRows; j++) { + out[i][j] = (*this)[i][j] / val; + } + } + return out; + } + + // Matrix Properties + MVec transform(const MVec& in) const { + static_assert(tNRows == tNColoumns); + MVec out; + for (halni i = 0; i < tNRows; i++) { + Type tmp = 0; + for (halni j = 0; j < tNColoumns; j++) { + tmp += (*this)[i][j] * in[j]; + } + out[i] = tmp; + } + return out; + } + + Mat transform(const Mat& in) const { + Mat out; + out.clear(0); + for (halni i = 0; i < tNRows; i++) { + for (halni j = 0; j < tNRows; j++) { + for (halni u = 0; u < tNRows; u++) { + out[i][j] += (*this)[i][u] * in[u][j]; + } + } + } + return out; + } + + Mat& transpose() { + static_assert(tNRows == tNColoumns); + for (halni i = 0; i < tNColoumns; i++) { + for (halni j = i + 1; j < tNColoumns; j++) { + swap((*this)[i][j], (*this)[j][i]); + } + } + return *this; + } + + Mat operator*(const Mat& in) const { return transform(in); } + + MVec operator*(const MVec& in) const { return transform(in); } + + Mat minor(halni p, halni q) { + Mat out; + halni i = 0, j = 0; + for (halni row = 0; row < tNRows; row++) { + for (halni col = 0; col < tNRows; col++) { + if (row != p && col != q) { + out[i][j++] = (*this)[row][col]; + if (j == tNRows - 1) { + j = 0; + i++; + } + } + } + } + return out; + } + + Type det() { + static_assert(tNRows == tNColoumns); + + Type out = 0; + + if (tNRows == 1) { + return (*this)[0][0]; + } + if (tNRows == 2) { + return ((*this)[0][0] * (*this)[1][1]) - ((*this)[1][0] * (*this)[0][1]); + } + + halni sign = 1; + for (int i = 0; i < tNRows; i++) { + out += sign * (*this)[0][i] * minor(0, i).det(); + sign = -sign; + } + return out; + } + + Mat cofactors() { + static_assert(tNRows == tNColoumns); + Mat out; + for (int i = 0; i < tNRows; i++) { + for (int j = 0; j < tNRows; j++) { + Type sign = (Type) ((i + j + 2) & 1 ? -1 : 1); + out[i][j] = minor(j, i).det() * sign; + } + } + return out; + } + + Mat inv() { + Type detV = det(); + DEBUG_ASSERT(detV) + return cofactors() /= detV; + } + }; + + template + using Mat2 = Mat; + using Mat2F = Mat2; + + template + class Mat { + typedef Vec MVec; + + MVec i; + MVec j; + + public: + Mat() = default; + + explicit Mat(const Type& val) { operator=(val); } + + Mat(const MVec& pi, const MVec& pj) { + i.x = pi.x; + i.y = pi.y; + j.x = pj.x; + j.y = pj.y; + } + + Mat(Type ix, Type iy, Type jx, Type jy) { + i.x = ix; + i.y = iy; + j.x = jx; + j.y = jy; + } + + Mat(const Mat& in) { operator=(in); } + + MVec& operator[](alni idx) { + DEBUG_ASSERT(idx < 2 && idx >= 0) + return (&i)[idx]; + } + + const MVec& operator[](alni idx) const { + DEBUG_ASSERT(idx < 2 && idx >= 0) + return (&i)[idx]; + } + + Mat& operator=(const Mat& in) { + memCopy(this, &in, sizeof(Mat2)); + return *this; + } + + Mat& operator=(const Type& val) { + clear(val); + return *this; + } + + void clear(const Type& val) { + i.x = val; + i.y = val; + j.x = val; + j.y = val; + } + + void setDiagonal(const Type& val) { + i.x = val; + j.y = val; + } + + Mat& fillRandom() { + DEBUG_ASSERT(0) + i.x = (Type) 0; + i.y = (Type) 0; + j.x = (Type) 0; + j.y = (Type) 0; + return *this; + } + + Mat operator-() { return Mat(-i.x, -i.y, -j.x, -j.y); } + + Mat& operator+=(const Mat& in) { + i.x += in.i.x; + i.y += in.i.y; + j.x += in.j.x; + j.y += in.j.y; + return *this; + } + + Mat& operator-=(const Mat& in) { + i.x -= in.i.x; + i.y -= in.i.y; + j.x -= in.j.x; + j.y -= in.j.y; + return *this; + } + + Mat& operator+=(Type val) { + i.x += val; + i.y += val; + j.x += val; + j.y += val; + return *this; + } + + Mat& operator-=(Type val) { + i.x -= val; + i.y -= val; + j.x -= val; + j.y -= val; + return *this; + } + + Mat& operator/=(Type val) { + i.x /= val; + i.y /= val; + j.x /= val; + j.y /= val; + return *this; + } + + Mat& operator*=(Type val) { + i.x *= val; + i.y *= val; + j.x *= val; + j.y *= val; + return *this; + } + + Mat operator+(const Mat& in) { + Mat out; + out.i.x = i.x + in.i.x; + out.i.y = i.y + in.i.y; + out.j.x = j.x + in.j.x; + out.j.y = j.y + in.j.y; + return out; + } + + Mat operator-(const Mat& in) { + Mat out; + out.i.x = i.x - in.i.x; + out.i.y = i.y - in.i.y; + out.j.x = j.x - in.j.x; + out.j.y = j.y - in.j.y; + return out; + } + + Mat operator+(const Type& val) { + Mat out; + out.i.x = i.x + val; + out.i.y = i.y + val; + out.j.x = j.x + val; + out.j.y = j.y + val; + return out; + } + + Mat operator-(const Type& val) { + Mat out; + out.i.x = i.x - val; + out.i.y = i.y - val; + out.j.x = j.x - val; + out.j.y = j.y - val; + return out; + } + + Mat operator*(const Type& val) { + Mat out; + out.i.x = i.x * val; + out.i.y = i.y * val; + out.j.x = j.x * val; + out.j.y = j.y * val; + return out; + } + + Mat operator/(const Type& val) { + Mat out; + out.i.x = i.x / val; + out.i.y = i.y / val; + out.j.x = j.x / val; + out.j.y = j.y / val; + return out; + } + + // Matrix Properties + MVec transform(const MVec& in) const { return MVec(i.x * in.x + i.y * in.y, j.x * in.y + j.y * in.x); } + + Mat transform(const Mat& in) const { + Mat out; + out.i.x = i.x * in.i.x + j.x * in.i.y; + out.i.y = i.y * in.i.x + j.y * in.i.y; + out.j.x = i.x * in.j.x + j.x * in.j.y; + out.j.y = i.y * in.j.x + j.y * in.j.y; + return out; + } + + Mat operator*(const Mat& in) { return transform(in); } + + Mat& transpose() { + swap(j.x, i.y); + return *this; + } + + Type det() { return i.x * j.y - i.y * j.x; } + + Mat cofactors() { return Mat(j.y, -i.y, -j.x, i.x); } + + Mat inv() { + Type detV = det(); + DEBUG_ASSERT(detV != 0) + return (cofactors() /= detV); + } + }; + + template + using mat3 = Mat; + using mat3f = mat3; + + template + class Mat { + typedef Vec3 vec; + + public: + vec I; + vec J; + vec K; + + public: + Mat() = default; + + explicit Mat(Type val) { + I.assign(val, 0.f, 0.f); + J.assign(0.f, val, 0.f); + K.assign(0.f, 0.f, val); + } + + Mat(const vec& i, const vec& j, const vec& k) { + I = i; + J = j; + K = k; + } + + Mat(const Mat& in) { + this->I = in.I; + this->J = in.J; + this->K = in.K; + } + + void assign(const vec& i, const vec& j, const vec& k) { + I = i; + J = j; + K = k; + } + + Mat& fillRandom() { + I.randf(); + J.randf(); + K.randf(); + return *this; + } + + vec& operator[](alni i) { + DEBUG_ASSERT(i < 3 && i >= 0) + return (&I)[i]; + } + + const vec& operator[](alni i) const { + DEBUG_ASSERT(i < 3 && i >= 0) + return (&I)[i]; + } + + // create on stack + Mat operator+(const Mat& in) { return Mat(I + in.I, J + in.J, K + in.K); } + + Mat operator-(const Mat& in) { return Mat(I - in.I, J - in.J, K - in.K); } + + Mat operator+(Type val) { return Mat(I + val, J + val, K + val); } + + Mat operator-(Type val) { return Mat(I - val, J - val, K - val); } + + Mat operator*(Type val) { return Mat(I * val, J * val, K * val); } + + Mat operator/(Type val) { return Mat(I / val, J / val, K / val); } + + // write + Mat& operator=(const Mat& in) { + I = in.I; + J = in.J; + K = in.K; + return *this; + } + + Mat& operator+=(const Mat& in) { + I += in.I; + J += in.J; + K += in.K; + return *this; + } + + Mat& operator-=(const Mat& in) { + I -= in.I; + J -= in.J; + K -= in.K; + return *this; + } + + Mat& operator+=(Type val) { + I += val; + J += val; + K += val; + return *this; + } + + Mat& operator-=(Type val) { + I -= val; + J -= val; + K -= val; + return *this; + } + + Mat& operator*=(Type val) { + I *= val; + J *= val; + K *= val; + return *this; + } + + Mat& operator/=(Type val) { + I /= val; + J /= val; + K /= val; + return *this; + } + + // Matrix transformation + vec transform(const vec& in) const { return vec(I.x * in.x + I.y * in.y + I.z * in.z, J.x * in.x + J.y * in.y + J.z * in.z, K.x * in.x + K.y * in.y + K.z * in.z); } + + Mat transform(const Mat& in) { + return Mat({(in.I.x * I.x + in.I.y * J.x + in.I.z * K.x), (in.I.x * I.y + in.I.y * J.y + in.I.z * K.y), (in.I.x * I.z + in.I.y * J.z + in.I.z * K.z)}, + {(in.J.x * I.x + in.J.y * J.x + in.J.z * K.x), (in.J.x * I.y + in.J.y * J.y + in.J.z * K.y), (in.J.x * I.z + in.J.y * J.z + in.J.z * K.z)}, + {(in.K.x * I.x + in.K.y * J.x + in.K.z * K.x), (in.K.x * I.y + in.K.y * J.y + in.K.z * K.y), (in.K.x * I.z + in.K.y * J.z + in.K.z * K.z)}); + } + + vec operator*(const vec& in) { return transform(in); } + + Mat operator*(const Mat& in) { return transform(in); } + + Mat minor(halni, halni) { + Mat out; + return out; + } + + Mat& transpose() { + swap(I.y, J.x); + swap(I.z, K.x); + swap(J.z, K.y); + return *this; + } + + Type det() { return (+I.x * (J.y * K.z - J.z * K.y) - I.y * (J.x * K.z - J.z * K.x) + I.z * (J.x * K.y - J.y * K.x)); } + + Mat cofactors() { + return Mat(vec(+(J.y * K.z - J.z * K.y), -(I.y * K.z - I.z * K.y), +(I.y * J.z - I.z * J.y)), + vec(-(J.x * K.z - J.z * K.x), +(I.x * K.z - I.z * K.x), -(I.x * J.z - I.z * J.x)), + vec(+(J.x * K.y - J.y * K.x), -(I.x * K.y - I.y * K.x), +(I.x * J.y - I.y * J.x))); + } + + Mat inv() { return cofactors() /= det(); } + + Mat rotatorX(alnf angle) { + alnf cosA = (alnf) cos(angle); + alnf sinA = (alnf) sin(angle); + return { + {1, 0, 0 }, + {0, cosA, -sinA}, + {0, sinA, cosA } + }; + } + + Mat rotatorY(alnf angle) { + alnf cosA = (alnf) cos(angle); + alnf sinA = (alnf) sin(angle); + return { + {cosA, 0, sinA}, + {0, 1, 0 }, + {-sinA, 0, cosA} + }; + } + + Mat rotatorZ(alnf angle) { + alnf cosA = (alnf) cos(angle); + alnf sinA = (alnf) sin(angle); + return { + {cosA, -sinA, 0}, + {sinA, cosA, 0}, + {0, 0, 1} + }; + } + + static Mat rotatorDir(vec dir, alnf angle) { + dir.normalize(); + + Mat out; + alnf cosA = (alnf) cos(angle); + alnf sinA = (alnf) sin(angle); + alnf tmp = 1 - cosA; + + out.I.x = (Type) (cosA + dir.x * dir.x * tmp); + out.I.y = (Type) (dir.x * dir.y * tmp - dir.z * sinA); + out.I.z = (Type) (dir.x * dir.z * tmp + dir.y * sinA); + + out.J.x = (Type) (dir.y * dir.x * tmp + dir.z * sinA); + out.J.y = (Type) (cosA + dir.y * dir.y * tmp); + out.J.z = (Type) (dir.y * dir.z * tmp - dir.x * sinA); + + out.K.x = (Type) (dir.z * dir.x * tmp - dir.y * sinA); + out.K.y = (Type) (dir.z * dir.y * tmp + dir.x * sinA); + out.K.z = (Type) (cosA + dir.z * dir.z * tmp); + + return out; + } + }; + + template + using Mat4 = Mat; + + using Mat4F = Mat4; + using Mat4I = Mat4; + + template + class Mat { + typedef Vec MVec; + MVec dummy; + + public: + MVec& operator[](alni) { return dummy; } + + const MVec& operator[](alni) const { return dummy; } + + Type det() { return Type(); } + }; +} diff --git a/Math/public/Topology.hpp b/Math/public/Topology.hpp index bcc5f3e..2bc2ce2 100644 --- a/Math/public/Topology.hpp +++ b/Math/public/Topology.hpp @@ -1,49 +1,53 @@ #pragma once -#include "Camera.hpp" #include "Buffer.hpp" +#include "Camera.hpp" namespace tp { - class TrigCache { - static Vec3F gHitPos; + class TrigCache { + static Vec3F gHitPos; - public: - ualni mP1, mP2, mP3; - Vec3F mEdgeP1P2, mEdgeP1P3; - Vec3F mNormal; - Vec3F mOrigin; + public: + ualni mP1, mP2, mP3; + Vec3F mEdgeP1P2, mEdgeP1P3; + Vec3F mNormal; + Vec3F mOrigin; - public: - TrigCache(); - TrigCache(const TrigCache& in); - TrigCache(ualni v1, ualni v2, ualni v3); + public: + TrigCache(); + TrigCache(const TrigCache& in); + TrigCache(ualni v1, ualni v2, ualni v3); - public: - static const Vec3F& getHitPos() ; - [[nodiscard]] const Vec3F& getNormal() const; + public: + static const Vec3F& getHitPos(); + [[nodiscard]] const Vec3F& getNormal() const; - public: - void updateCache(const Buffer& points); - [[nodiscard]] bool castRay(const Ray& ray) const; - }; + public: + void updateCache(const Buffer& points); + [[nodiscard]] bool castRay(const Ray& ray) const; + }; - class Topology { - mat3f mBasis; - Vec3F mOrigin; + struct Topology { + Vec3F Origin = {0, 0, 0}; + mat3f Basis = { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1} + }; - Buffer mPoints; - Buffer mPointsTransformed; - Buffer mTrigCaches; + Buffer Points; + Buffer Normals; + Buffer Indexes; + }; - public: - Topology() = default; - ~Topology() = default; + struct TopologyCache { + const Topology* Source = nullptr; - public: - void addTrig(const Vec3F& v1, const Vec3F& v2, const Vec3F& v3); - void transformPoint(Vec3F& vert); - void updateTransformed(); - [[nodiscard]] const Buffer& getTrigs() const; - }; + Buffer TransformedPoints; + Buffer TransformedNormals; + Buffer TrigCaches; + + void updateCache(); + }; } diff --git a/RayTracer/applications/SceneLoad.cpp b/RayTracer/applications/SceneLoad.cpp index 7137cb4..7112c9f 100644 --- a/RayTracer/applications/SceneLoad.cpp +++ b/RayTracer/applications/SceneLoad.cpp @@ -19,21 +19,28 @@ bool loadMeshes(tp::Scene& scene, const tp::String& objetsPath) { } for (auto& curMesh : Loader.LoadedMeshes) { - scene.mObjects.append(Topology()); + scene.mObjects.append(Object()); + auto object = &scene.mObjects.last(); - for (int j = 0; j < curMesh.Indices.size(); j += 3) { - unsigned int idx1 = curMesh.Indices[j]; - unsigned int idx2 = curMesh.Indices[j + 1]; - unsigned int idx3 = curMesh.Indices[j + 2]; - - Vec3F v1 = {curMesh.Vertices[idx1].Position.X, curMesh.Vertices[idx1].Position.Y, curMesh.Vertices[idx1].Position.Z}; - Vec3F v2 = {curMesh.Vertices[idx2].Position.X, curMesh.Vertices[idx2].Position.Y, curMesh.Vertices[idx2].Position.Z}; - Vec3F v3 = {curMesh.Vertices[idx3].Position.X, curMesh.Vertices[idx3].Position.Y, curMesh.Vertices[idx3].Position.Z}; - - object->addTrig(v1, v2, v3); + for (auto& vertex : curMesh.Vertices) { + object->mTopology.Points.append(Vec3F {vertex.Position.X, vertex.Position.Y, vertex.Position.Z}); + object->mTopology.Normals.append(Vec3F {vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z}); } - object->updateTransformed(); + + for (int j = 0; j < curMesh.Indices.size(); j += 3) { + int idx1 = (int) curMesh.Indices[j]; + int idx2 = (int) curMesh.Indices[j + 1]; + int idx3 = (int) curMesh.Indices[j + 2]; + object->mTopology.Indexes.append(Vec3I {idx1, idx2, idx3}); + } + + if (object->mTopology.Normals.size() != object->mTopology.Points.size()) { + printf("Logic error loading normals\n"); + } + + object->mCache.Source = &object->mTopology; + object->mCache.updateCache(); } return scene.mObjects.size(); diff --git a/RayTracer/private/RayTracer.cpp b/RayTracer/private/RayTracer.cpp index 1df81bc..3c5e93f 100644 --- a/RayTracer/private/RayTracer.cpp +++ b/RayTracer/private/RayTracer.cpp @@ -22,7 +22,7 @@ void RayTracer::castRay(const Ray& ray, RayCastData& out, alnf far) { far *= far; for (auto obj : mScene->mObjects) { - for (auto trig : obj->getTrigs()) { + for (auto trig : obj->mCache.TrigCaches) { if (trig->castRay(ray)) { // printf("Hit\n"); @@ -77,15 +77,46 @@ void RayTracer::render(const Scene& scene, RayTracer::RenderBuffer& buff) { castRay(ray, castData, mScene->mCamera.getFar()); if (castData.hit) { - auto normal = castData.trig->getNormal(); + Vec3F normal = castData.trig->getNormal(); + + if (1) { + const auto& points = castData.obj->mCache.TransformedPoints; + const auto& normals = castData.obj->mCache.TransformedNormals; + const auto trig = castData.trig; + + const auto& n1 = normals[trig->mP1]; + const auto& n2 = normals[trig->mP2]; + const auto& n3 = normals[trig->mP3]; + + auto v0 = points[trig->mP1]; + auto v1 = points[trig->mP2]; + auto v2 = points[trig->mP3]; + + // Calculate barycentric coordinates + Vec3F barycentric; + + // Calculate the area of the triangle + auto areaABC = (halnf) (v1 - v0).cross(v2 - v0).length(); + auto areaPBC = (halnf) (v1 - castData.hitPos).cross(v2 - castData.hitPos).length(); + auto areaPCA = (halnf) (v2 - castData.hitPos).cross(v0 - castData.hitPos).length(); + + // Calculate the barycentric coordinates + barycentric.x = areaPBC / areaABC; + barycentric.y = areaPCA / areaABC; + barycentric.z = 1.0f - barycentric.x - barycentric.y; + + // Interpolate the normal using barycentric coordinates + normal = n1 * barycentric.x + n2 * barycentric.y + n3 * barycentric.z; + } + 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); + // 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}); + } else { buff.set({i, j}, RGBA(0.f, 0.f, 0.f, 0.f)); } diff --git a/RayTracer/public/RayTracer.hpp b/RayTracer/public/RayTracer.hpp index 6c5bbb1..812d871 100644 --- a/RayTracer/public/RayTracer.hpp +++ b/RayTracer/public/RayTracer.hpp @@ -12,10 +12,16 @@ namespace tp { extern ModuleManifest gModuleRayTracer; - class Scene { + class Object { public: - typedef Topology Object; + Object() = default; + public: + Topology mTopology; + TopologyCache mCache; + }; + + class Scene { public: Scene() = default; @@ -40,7 +46,7 @@ namespace tp { private: struct RayCastData { - const Scene::Object* obj = nullptr; + const Object* obj = nullptr; TrigCache* trig = nullptr; Vec3F hitPos = {0, 0, 0}; bool hit = false;