Skip to content

Commit

Permalink
cube
Browse files Browse the repository at this point in the history
  • Loading branch information
ChenxiZhou0619 committed Feb 28, 2023
1 parent bf8b069 commit c06b4c6
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 9 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ add_executable(Moer
src/FunctionLayer/Light/EnvironmentLight.cpp
src/FunctionLayer/Shape/Shape.cpp
src/FunctionLayer/Shape/Triangle.cpp
src/FunctionLayer/Shape/Cube.cpp
src/FunctionLayer/Shape/Sphere.cpp
src/FunctionLayer/Shape/Parallelogram.cpp
src/FunctionLayer/Texture/NormalTexture.cpp
Expand Down
Binary file added examples/cornell-box/images/indoor.hdr
Binary file not shown.
Binary file added examples/cornell-box/images/tex.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions examples/cornell-box/scene.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"output" : {
"filename" : "cornell-1.hdr"
},
"sampler" : {
"type" : "independent",
"xSamples" : 16,
"ySamples" : 16
},
"camera" : {
"type" : "pinhole",
"transform" : {
"position" : [2, 4, 8],
"up" : [0, 1, 0],
"lookAt" : [0, 0, 0]
},
"tNear" : 0.1,
"tFar" : 10000,
"verticalFov" : 45,
"timeStart" : 0,
"timeEnd" : 0,
"film" : {
"size" : [900, 600]
}
},
"integrator" : {
"type" : "directSampleBSDF"
},
"scene" : {
"shapes" : [
{
"type" : "cube",
"transform" : {
"scale" : [1, 2, 1.5],
"rotate" : {
"axis" : [1, 1, 1],
"radian" : 1.4
}
},
"material" : {
"type" : "matte",
"albedo" : {
"type" : "imageTex",
"file" : "images/tex.jpg"
}
}
}
],
"lights" : [
{
"type" : "environmentLight",
"texture" : {
"type" : "imageTex",
"file" : "images/indoor.hdr"
}
}
]
}
}
1 change: 1 addition & 0 deletions src/CoreLayer/Math/Transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Transform::Transform() {
Transform::Transform(const Matrix4f &_translation, const Matrix4f &_rotation,
const Matrix4f &_scalation)
: translate(_translation), rotate(_rotation), scale(_scalation) {
invTranslate = invRotate = invScale = Matrix4f::identity();
for (int i = 0; i < 3; ++i) {
invTranslate.rows[i][3] = -translate.rows[i][3];
invScale.rows[i][i] = 1.f / scale.rows[i][i];
Expand Down
2 changes: 1 addition & 1 deletion src/CoreLayer/Math/Transform.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct Transform {
//* 当对C应用该Transform后,toWorld返回point发生变换后的世界坐标系表达
Point3f toWorld(const Point3f &point) const;

protected:
public:
Matrix4f translate, invTranslate;
Matrix4f rotate, invRotate;
Matrix4f scale, invScale;
Expand Down
4 changes: 1 addition & 3 deletions src/FunctionLayer/Integrator/DirectIntegrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ DirectIntegratorSampleBSDF ::li(const Ray &ray, const Scene &scene,
}

auto intersection = intersectionOpt.value();

if (auto light = intersection.shape->light; light) {
spectrum += light->evaluateEmission(intersection, -ray.direction);
}
Expand All @@ -82,9 +83,6 @@ DirectIntegratorSampleBSDF ::li(const Ray &ray, const Scene &scene,
auto bsdf = material->computeBSDF(intersection);
auto bsdfSampleResult = bsdf->sample(-ray.direction, sampler->next2D());

Vector3f n = bsdf->normal;
Vector3f wh = normalize(-ray.direction + bsdfSampleResult.wi);

//* 该入射方向上如果有光源,那么将得到一条有贡献的、长度为1的光路
Ray shadowRay{intersection.position, bsdfSampleResult.wi};
auto findLight = scene.rayIntersect(shadowRay);
Expand Down
7 changes: 3 additions & 4 deletions src/FunctionLayer/Material/BxDF/Lambert.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@ class LambertReflection : public BSDF {

virtual Spectrum f(const Vector3f &wo, const Vector3f &wi) const override {
Vector3f woLocal = toLocal(wo), wiLocal = toLocal(wi);
if (woLocal[1] <= .0f || wiLocal[1] <= .0f)
return Spectrum(.0f);
// if (woLocal[1] <= .0f || wiLocal[1] <= .0f)
// return Spectrum(0.f);
return albedo * INV_PI * wiLocal[1];
}

virtual BSDFSampleResult sample(const Vector3f &wo,
const Vector2f &sample) const override {
Spectrum weight = albedo;
Vector3f wi = squareToCosineHemisphere(sample);
float pdf = squareToCosineHemispherePdf(wi);
return {weight, toWorld(wi), pdf, BSDFType::Diffuse};
return {albedo, toWorld(wi), pdf, BSDFType::Diffuse};
}

private:
Expand Down
1 change: 0 additions & 1 deletion src/FunctionLayer/Material/Matte.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ MatteMaterial::computeBSDF(const Intersection &intersection) const {
computeShadingGeometry(intersection, &normal, &tangent, &bitangent);

Spectrum s = albedo->evaluate(intersection);

return std::make_shared<LambertReflection>(normal, tangent, bitangent, s);
}

Expand Down
142 changes: 142 additions & 0 deletions src/FunctionLayer/Shape/Cube.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include "Cube.h"
#include "ResourceLayer/Factory.h"

// Cube的transform有特殊处理

Cube::Cube(const Json &json) : Shape(json) {
// Cube默认是中心位于(0, 0, 0)处,棱长为2的AABB,其形状可以通过transform调整
boxMin = Point3f{-1.f, -1.f, -1.f};
boxMax = Point3f{1.f, 1.f, 1.f};

// 构建AABB
pMin = pMax = transform.toWorld(boxMin);
for (int i = 0; i < 8; ++i) {
Point3f p;
p[0] = (i & 0x100) ? boxMax[0] : boxMin[0];
p[1] = (i & 0x010) ? boxMax[1] : boxMin[1];
p[2] = (i & 0x001) ? boxMax[2] : boxMin[2];
p = transform.toWorld(p);

for (int j = 0; j < 3; ++j) {
pMin[j] = std::min(pMin[j], p[j]);
pMax[j] = std::max(pMax[j], p[j]);
}
}

// 在计算时,所有计算都是在局部坐标系内完成的,因此这里只对boxMin和boxMax做scale操作
Matrix4f scale = transform.scale;
vecmat::vec4f min{boxMin[0], boxMin[0], boxMin[0], 1.f},
max{boxMax[0], boxMax[0], boxMax[0], 1.f};
min = scale * min, max = scale * max;
min /= min[3], max /= max[3];
boxMin = Point3f{min[0], min[1], min[2]};
boxMax = Point3f{max[0], max[1], max[2]};
}

bool Cube::rayIntersectShape(const Ray &ray, float *distance, int *primID,
float *u, float *v) const {
// 我们将shape的旋转和平移的逆变换应用到光线上,在不改变两者的相对位置的情况下
// 在局部坐标系中完成求交计算,局部坐标系中cube一直是Axis-aligned box
Point3f origin = ray.origin;
Vector3f direction = ray.direction;

vecmat::vec4f o{origin[0], origin[1], origin[2], 1.f},
d{direction[0], direction[1], direction[2], 0.f};

o = transform.invRotate * transform.invTranslate * o;
d = transform.invRotate * transform.invTranslate * d;

o /= o[3];
origin = Point3f{o[0], o[1], o[2]};
direction = Vector3f{d[0], d[1], d[2]};

float tNear = ray.tNear, tFar = ray.tFar;

for (int i = 0; i < 3; ++i) {
float invDir = 1.f / direction[i]; // 没有做除0检查,该算法貌似不需要?
float t0 = (boxMin[i] - origin[i]) * invDir,
t1 = (boxMax[i] - origin[i]) * invDir;
if (t0 > t1)
std::swap(t0, t1);
tNear = std::max(tNear, t0);
tFar = std::min(tFar, t1);

if (tNear > tFar)
return false;
}

auto compute = [min = boxMin, max = boxMax](Point3f hitpoint, int *primID,
float *u, float *v) {
float minBias = FLT_MAX;
int flag = -1;
for (int i = 0; i < 3; ++i) {
if (float bias = std::abs(hitpoint[i] - min[i]); bias < minBias) {
flag = 2 * i;
minBias = bias;
}
if (float bias = std::abs(hitpoint[i] - max[i]); bias < minBias) {
flag = 2 * i + 1;
minBias = bias;
}
}

*primID = flag;
int axis = (flag / 2 + 1) % 3;
*u = (float)(hitpoint[axis] - min[axis]) / (max[axis] - min[axis]);
axis = (axis + 1) % 3;
*v = (float)(hitpoint[axis] - min[axis]) / (max[axis] - min[axis]);
};

bool hit = false;
if (ray.tNear < tFar && tFar < ray.tFar) {
Point3f hitpoint = origin + tFar * direction;
compute(hitpoint, primID, u, v);
*distance = tFar;
hit = true;
}
if (ray.tNear < tNear && tNear < ray.tFar) {
Point3f hitpoint = origin + tNear * direction;
compute(hitpoint, primID, u, v);
*distance = tNear;
hit = true;
}
return hit;
}

void Cube::fillIntersection(float distance, int primID, float u, float v,
Intersection *intersection) const {
intersection->shape = this;
intersection->distance = distance;
vecmat::vec4f normal{.0f, .0f, .0f, .0f};
normal[primID / 2] = (primID % 2) ? 1 : -1;

normal = transform.rotate * normal;
intersection->normal = normalize(Vector3f{normal[0], normal[1], normal[2]});

vecmat::vec4f hitpoint;
hitpoint[primID / 2] = (primID % 2) ? boxMax[primID / 2] : boxMin[primID / 2];
int axis = (primID / 2 + 1) % 3;
hitpoint[axis] = boxMin[axis] + u * (boxMax[axis] - boxMin[axis]);
axis = (axis + 1) % 3;
hitpoint[axis] = boxMin[axis] + v * (boxMax[axis] - boxMin[axis]);
hitpoint[3] = 1.f;

hitpoint = transform.translate * transform.rotate * hitpoint;
hitpoint /= hitpoint[3];

intersection->position = Point3f{hitpoint[0], hitpoint[1], hitpoint[2]};

intersection->texCoord = Vector2f{u, v};
// TODO 计算交点的切线和副切线
Vector3f tangent{1.f, 0.f, .0f};
Vector3f bitangent;
if (std::abs(dot(tangent, intersection->normal)) > .9f) {
tangent = Vector3f(.0f, 1.f, .0f);
}
bitangent = normalize(cross(tangent, intersection->normal));
tangent = normalize(cross(intersection->normal, bitangent));
intersection->tangent = tangent;
intersection->bitangent = bitangent;
}

REGISTER_CLASS(Cube, "cube")
25 changes: 25 additions & 0 deletions src/FunctionLayer/Shape/Cube.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once
#include "Shape.h"

class Cube : public Shape {
public:
Cube() = delete;

Cube(const Json &json);

virtual bool rayIntersectShape(const Ray &ray, float *distance, int *primID,
float *u, float *v) const override;

virtual void fillIntersection(float distance, int primID, float u, float v,
Intersection *intersection) const override;

virtual void uniformSampleOnSurface(Vector2f sample,
Intersection *intersection,
float *pdf) const override {
// TODO finish this
return;
}

protected:
Point3f boxMin, boxMax;
};

0 comments on commit c06b4c6

Please sign in to comment.