Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment 4 #1

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Practical Assignment 4
**Dealine**: 12.11.2020

Please put your name here:
**Name:** .......

**Name:** Katrin von Seggern & Jordan Streete
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dear Katrin, dear Jordan, I asked you to submit separate solutions. I will count this submission only as the submission of Katrin.

## Problem 1
### Sphere Solid (Points 25)
In this assignment we will continue working with _compound objects_: solids.
Expand Down Expand Up @@ -35,7 +35,8 @@ Proceed as follows:
6. Extend your code in ```CSolidSphere``` constructor in such a way that the triangles will be created with the additional normals. Calculate these normals (_e.g._ using the spherical coordinate system) and pass them within the triangles' and quads' constructors.
7. Test your implementation on the scene from Problem 1. Compare the difference between the Solid and Primitive spheres. Explain below why smoothed cone looks strange. How would you fix it?

**Explanation and Suggestion:** ...
**Explanation and Suggestion:**
For the top vertex, we would take quads but since it is not in this code, it chooses a triangle. The smoothed cone was actually not completely smooth and even when we added in the height segment from the sample code, it was a bit bumpy. This might be because there are some areas of the original cone that are already smoothed but are then smoothed again. By adding the bool "smooth" in it as in the sample code, we would check for this case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that you can assign only one normal to the top vertex, per triangle. Thus smooth transitions are not possible. To reduce the effect of faced shape, one can use the technique of multiple height segments. This will reduce the the effect of faced shape to the top segments.

If everything is correct your images should look like this:

Expand Down Expand Up @@ -77,6 +78,10 @@ Using the expieriense gained so far, add to the scene Barney and apply his textu
Test your implementation on barney.obj with barney.bmp. If everything is correct your image should look like this:
![barney](./doc/barney.jpg)

We could not get the textures quite correct (except for the one on Barney). The PrimSphere's texture looks closest to what we wanted it but it's a little distorted and the cone's and solid sphere's textures look way off. This is probably because we did not get the getTextureCoords function to work in the SolidSphere.h.
The constructors for the texture coordinates are commented out but still there.
We attached a folder with two renders because we forgot to save the intermediate renders. We also did not get the camera to focus on Barney.

## Submission
Please submit the assignment by making a pull request.
**Important** : Please make sure that
Expand Down
Binary file added renders/Render.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added renders/result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 27 additions & 1 deletion src/PrimPlane.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#pragma once

#include "IPrim.h"

#include "ray.h"
// ================================ Infinite Plane Primitive Class ================================
/**
* @brief The Plane Geometrical Primitive class
Expand Down Expand Up @@ -43,6 +43,32 @@ class CPrimPlane : public IPrim

virtual Vec2f getTextureCoords(const Ray& ray) const override
{
/* Copied from OpenRT but it did not really work
Vec3f mu;
for (int i = 0; i < 3; i++)
if (fabs(m_normal.val[i]) >= 1.0f / sqrtf(3)) {
mu.val[i] = 0;
int mind, maxd;
if (fabs(m_normal.val[(i + 1) % 3]) > fabs(m_normal.val[(i + 2) % 3])) {
maxd = (i + 1) % 3;
mind = (i + 2) % 3;
}
else {
maxd = (i + 2) % 3;
mind = (i + 1) % 3;
}
mu.val[mind] = 1;
mu.val[maxd] = fabs(m_normal.val[maxd]) > Epsilon ? -m_normal.val[mind] / m_normal.val[maxd] : 0;
break;
}
mu = normalize(mu);
Vec3f mv = normalize(m_normal.cross(mu));
Vec3f hp = ray.org + ray.dir * ray.t;
Vec3f hit = hp;
Vec3f h = hit - m_origin;
Vec2f res = norm(h) > Epsilon ? Vec2f(h.dot(mu), h.dot(mv)) : Vec2f(0, 0);

return res;*/
return Vec2f(0, 0);
}

Expand Down
13 changes: 12 additions & 1 deletion src/PrimSphere.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,18 @@ class CPrimSphere : public IPrim
virtual Vec2f getTextureCoords(const Ray& ray) const override
{
// --- PUT YOUR CODE HERE ---
return Vec2f(0, 0);
Vec3f hitPoint = (ray.org + (ray.t * ray.dir)) - m_origin;
//taken from slides
float x= hitPoint.val[0];
float y= hitPoint.val[2];
float z= hitPoint.val[1];
float phi = atan2(y, x);
float theta = acosf(z / m_radius);
if (isnan(phi)) {
phi = 0;
}
return Vec2f((Pif + phi) / (2 * Pif), theta / Pif);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be return Vec2f(-0.5f * phi / Pif, theta / Pif); here

//return Vec2f(0, 0);
}

virtual CBoundingBox getBoundingBox(void) const override
Expand Down
22 changes: 18 additions & 4 deletions src/PrimTriangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,38 @@ class CPrimTriangle : public IPrim
ray.t = f;
ray.hit = shared_from_this();
// --- PUT YOUR CODE HERE ---

//Store the computed barycentric coordinates into Ray::u and Ray::v
ray.u = lambda;
ray.v = mue;
return true;
}

virtual Vec3f getNormal(const Ray& ray) const override
{
if (m_na && m_nb && m_nc) {
// --- PUT YOUR CODE HERE ---
return Vec3f(0, 0, 0);
/*Problem 2.4: Check whether the vertex normals are initialized and if yes,
use the u/v coordinates of the hitpoint to interpolate between the vertex normals
and return interpolated normal
This code is taken from: https://stackoverflow.com/questions/38717963/best-way-to-interpolate-triangle-surface-using-3-positions-and-normals-for-ray-t
but instead of u and v, we have u.ray and v.ray
*/
Vec3f r0 = m_na.value();
Vec3f r1 = m_nb.value();
Vec3f r2 = m_nc.value();
Vec3f intnorm = ((1.0f - ray.u - ray.v) * r0 + ray.u * r1 + ray.v * r2);
return intnorm;
}
else
else {
return normalize(m_edge1.cross(m_edge2));
}
}

virtual Vec2f getTextureCoords(const Ray& ray) const override
{
// --- PUT YOUR CODE HERE ---
return Vec2f(0, 0);
return(1.0f - ray.u - ray.v) * m_ta + ray.u * m_tb + ray.v * m_tc;
//return Vec2f(0, 0);
}

virtual CBoundingBox getBoundingBox(void) const override
Expand Down
4 changes: 3 additions & 1 deletion src/ShaderFlat.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class CShaderFlat : public IShader
{
if (m_pTexture) {
// --- PUT YOUR CODE HERE ---
return Vec3f(1, 1, 1);
Vec2f uv = ray.hit->getTextureCoords(ray);
//return Vec3f(1, 1, 1);
return m_pTexture->getTexel(uv);
}
else
return m_color;
Expand Down
31 changes: 26 additions & 5 deletions src/SolidCone.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ class CSolidCone : public CSolid {
const Vec3f top(0, height, 0); // The top point
Vec3f dir0(1, 0, 0); // Initial direction
Vec3f p0 = origin + radius * dir0; // Initial point
Vec3f dir1, p1; // Next point

//taken from SolidCone.cpp
const Vec3f slope(0, radius / height, 0);
Vec3f n0 = normalize(dir0 + slope); //initial normal
Vec3f dir1, p1, n1; // Next point and normal
float t0 = 0; // Initial texture coordinate
for (size_t s = 0; s < sides; s++) {
float t1 = static_cast<float>(s + 1) / sides; // Next texture coordinate: [1/sides; 1]
Expand All @@ -34,15 +38,32 @@ class CSolidCone : public CSolid {

// --- PUT YOUR CODE HERE ---
// Sides
if (height >= 0) add(std::make_shared<CPrimTriangle>(pShader, origin + top, p1, p0));
else add(std::make_shared<CPrimTriangle>(pShader, origin + top, p0, p1));
n1 = normalize(dir1 + slope);
float h0 = 0;
size_t height_segments = sides / 2;
for (int h = 0; h < height_segments - 1; h++) {
float h1 = static_cast<float>(h + 1) / height_segments; // Next height: [1/height_segments; 1]
add(std::make_shared<CSolidQuad>(pShader,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually you do not need to use quads in construction of the cone. I think this is exactly the reason why texturing did not work.

p0 + h0 * (top - radius * dir0),
p0 + h1 * (top - radius * dir0),
p1 + h1 * (top - radius * dir1),
p1 + h0 * (top - radius * dir1),
Vec2f(t0, 1 - h0), Vec2f(t0, 1 - h1), Vec2f(t1, 1 - h1), Vec2f(t1, 1 - h0),
n0, n0, n1, n1));
h0 = h1;
}
if (height >= 0) add(std::make_shared<CPrimTriangle>(pShader, origin + top, p1, p0, Vec2f(0.5f, 0), Vec2f(t1, 1), Vec2f(t0, 1),
normalize(n0 + n1), n1, n0));
else add(std::make_shared<CPrimTriangle>(pShader, origin + top, p0, p1, Vec2f(0.5f, 0), Vec2f(t0, 1), Vec2f(t1, 1),
normalize(n0 + n1), n0, n1));

// Cap
if (height >= 0) add(std::make_shared<CPrimTriangle>(pShader, origin, p1, p0));
else add(std::make_shared<CPrimTriangle>(pShader, origin, p0, p1));
if (height >= 0) add(std::make_shared<CPrimTriangle>(pShader, origin, p1, p0, Vec2f(0.5f, 1), Vec2f(t1, 1), Vec2f(t0, 1)));
else add(std::make_shared<CPrimTriangle>(pShader, origin, p0, p1, Vec2f(0.5f, 1), Vec2f(t0, 1), Vec2f(t1, 1)));

dir0 = dir1;
p0 = p1;
n0 = n1;
t0 = t1;
}
}
Expand Down
78 changes: 77 additions & 1 deletion src/SolidSphere.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,82 @@ class CSolidSphere : public CSolid
CSolidSphere(ptr_shader_t pShader, const Vec3f& origin = Vec3f::all(0), float radius = 1, size_t sides = 24)
{
// --- PUT YOUR CODE HERE ---
//use height segments as described in the problem
size_t height_segments = sides / 2;
//for our x, we have 2 pi over the sides
float x = 2 * Pif / sides;
float y = Pif / height_segments;
float z = 0;
float w = 0;
//nested for loops looping through the sides and the height
for (size_t s = 0; s < sides; s++) {
for (size_t h = 0; h < height_segments; h++) {
/*special cases on top and bottom of the sphere where
we have just triangles and no quads. With a triangle, we
need to calculate the three points*/
if (h == 0) {
/*taken from cylinder example but modified to fit sphere
p0 is again the initial point, p1 and p2 the next points.
*/
Vec3f p0 = origin + Vec3f(0, radius, 0);
Vec3f p1 = origin + Vec3f(radius * sinf(y) * cosf(z), radius * cosf(y), radius * sinf(y) * sinf(z));
Vec3f p2 = origin + Vec3f(radius * sinf(y) * cosf(z + x), radius * cosf(y), radius * sinf(y) * sinf(z + x));
Vec3f n1 = normalize(p1 - origin);
Vec3f n2 = normalize(p2 - origin);
//Vec2f uv1 = getTextureCoords(p1 - origin, radius);
//Vec2f uv2 = getTextureCoords(p2 - origin, radius);
//Vec2f uv0 = Vec2f((uv1.val[0] + uv2.val[0]) / 2, 0);

//idea taken from cylinder but modified to fit sphere
//first triangle constructor version from problem 1:
add(std::make_shared<CPrimTriangle>(pShader, p0, p1, p2));

//extended triangle constructor from problem 2
//add(std::make_shared<CPrimTriangle>(pShader, p0, p1, p2, normalize(n1 + n2), n1, n2));

//extended triangle constructor from problem 3
//add(std::make_shared<CPrimTriangle>(pShader,p0,p1,p2,uv0,uv1,uv2,normalize(n1+n2),n1,n2));
}
else if (h == height_segments-1) {
Vec3f p0 = origin + Vec3f(0, -radius, 0);
Vec3f p1 = origin + Vec3f(radius * sinf(Pif - y) * cosf(z), radius * sinf(Pif - y) * sinf(z), radius * cosf(Pif - y));
Vec3f p2 = origin + Vec3f(radius * sinf(Pif - y) * cosf(z + x), radius * cosf(Pif-y), radius * sinf(Pif-y) * sinf(z + x));
Vec3f n1 = normalize(p1 - origin);
Vec3f n2 = normalize(p2 - origin);
//Vec2f uv1 = getTextureCoords(p1 - origin, radius);
//Vec2f uv2 = getTextureCoords(p2 - origin, radius);
//Vec2f uv0 = Vec2f((uv1.val[0] + uv2.val[0]) / 2, 1);

//first triangle constructor version from problem 1:
add(std::make_shared<CPrimTriangle>(pShader, p0, p1, p2));
//extended triangle constructor from problem 2
//add(std::make_shared<CPrimTriangle>(pShader, p0, p1, p2, normalize(n1 + n2), n1, n2));
//constructor for the texture problem
//add(std::make_shared<CPrimTriangle>(pShader, p0, p1, p2, uv0, uv1, uv2, normalize(n1 + n2), n1, n2));
}
else {//It's a quad and we need for points
Vec3f p0 = origin + Vec3f(radius * sinf(w) * cosf(z), radius * cosf(w), radius * sinf(w) * sinf(z));
Vec3f p1 = origin + Vec3f(radius * sinf(w + y) * cosf(z), radius * cosf(w + y), radius * sinf(w + y) * sinf(z));
Vec3f p2 = origin + Vec3f(radius * sinf(w + y) * cosf(z + x), radius * cosf(w + y), radius * sinf(w + y) * sinf(z + x));
Vec3f p3 = origin + Vec3f(radius * sinf(w) * cosf(z + x), radius * cosf(w), radius * sinf(w) * sinf(z + x));

//Vec2f uv0 = getTextureCoords(p0 - origin, radius);
//Vec2f uv1 = getTextureCoords(p1 - origin, radius);
//Vec2f uv2 = getTextureCoords(p2 - origin, radius);
//Vec2f uv3 = getTextureCoords(p3 - origin, radius);
//add(std::make_shared<CSolidQuad>(pShader, p0, p1, p2, p3, uv0, uv1, uv2, uv3, normalize(p0 - origin), normalize(P1 - origin), normalize(P2 - origin), normalize(P3 - origin)));

//first quad constructor version from problem 1:
add(std::make_shared<CSolidQuad>(pShader, p0, p1, p2, p3));
//extended quad constructor from problem 2
//add(std::make_shared<CSolidQuad>(pShader, p0, p1, p2, p3, normalize(p0 - origin), normalize(p1 - origin), normalize(p2 - origin), normalize(p3 - origin)));
//extended quad constructor from problem 3
//add(std::make_shared<CSolidQuad>(pShader, p0, p1, p2, p3, normalize(p0 - origin), normalize(p1 - origin), normalize(p2 - origin), normalize(p3 - origin)));
}
w += y;
}
z += x;
}
}
virtual ~CSolidSphere(void) = default;
};
};
23 changes: 18 additions & 5 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,45 @@ Mat RenderFrame(void)

// Add camera to scene
auto pCamera = std::make_shared<CCameraPerspective>(resolution, Vec3f(0, 0, -30.0f), Vec3f(0, 0, 1), Vec3f(0, 1, 0), 30);
auto pCamera2 = std::make_shared<CCameraPerspective>(resolution, Vec3f(0, 5, 40.0f), Vec3f(0, 0, -1), Vec3f(0, 1, 0), 30);

#ifdef WIN32
const std::string dataPath = "../data/";
#else
const std::string dataPath = "../../data/";
const std::string dataPath = "C:/Users/katri/Documents/GitHub/eyden-tracer-04/data/";
#endif

// Texture
Mat earth = imread(dataPath + "1_earth_8k.jpg");
if (earth.empty()) printf("ERROR: Texture file is not found!\n");
if (earth.empty()) printf("ERROR: Earth texture file is not found!\n");
auto pTexture = std::make_shared<CTexture>(earth);

// Shaders
auto pShader = std::make_shared<CShaderEyelight>(RGB(0.5f, 1, 0));

//auto pShader = std::make_shared<CShaderEyelight>(RGB(0.5f, 1, 0));
auto pShader = std::make_shared<CShaderEyelight>(pTexture);

// Geometry
CSolidCone solid_cone(pShader, Vec3f(10, -4, 0), 4, 8);
CSolidSphere solid_sphere(pShader, Vec3f(0, 0, 0), 4, 36);
auto prim_sphere = std::make_shared<CPrimSphere>(pShader, Vec3f(-10, 0, 0), 4);

//Barney - bonus assignment
Mat barney = imread(dataPath + "barney.bmp");
if (barney.empty()) printf("ERROR: Barney texture file is not found!\n");
auto pTextureBarney = std::make_shared<CTexture>(barney);
auto pShaderbarney = std::make_shared<CShaderEyelight>(pTextureBarney);
CSolid barn(pShaderbarney, dataPath + "barney.obj");

// Add everything to the scene
scene.add(pCamera);
// commented out for bonus assignment
scene.add(solid_cone);
scene.add(solid_sphere);
scene.add(prim_sphere);


//add Barney and camera 2
scene.add(barn);
scene.add(pCamera2);
// Build BSPTree
scene.buildAccelStructure(20, 3);

Expand Down