I've been writing a ray tracer for fun and have gotten a decent amount into it. I have watched a tutorials, lectures, and research / other code to bring into perspective calculating the vector ray in projection to the image. Unfortunately, after the 4-5th iteration depending on the size of the image I am creating, it uses the same vector ray. Though this should be different depending on which pixel is getting looked at in the image.
Right now I am currently doing a transformation that basically shifts the ray left or right x/y
of the pixel depending on the dimension of the image getting created. Specifically, I have looked at these two Raytracer - Computing Eye Rays && calculation for ray generation in ray tracer answers, have tried implementing them, tweaked my code, and have gotten no where.
As a side note, the portrait and landscape implementations do not work either. It is hard coded with width = 10 and height = 10, because that has been the dimension I've been playing with. They can be changed and definitely will be changed in the future.
Coding in C++ with VS2013.
int WIDTH = 10;
int HEIGHT = 10;
int main(int argc, char **argv) {
std::cout << "creating rays..." << std::endl;
Vector Y(0, 1, 0);
Vector camPos(3, 1.5, -4);
Vector looking_at(0, 0, 0); // may change - but want to look at center for this scene
Vector difference(camPos - looking_at);
Vector camDir = difference.negative().normalize();
Vector camRight = (Y.cross(camDir)).normalize();
Vector camDown = camRight.cross(camDir);
double aspectRatio = (double) WIDTH / (double) HEIGHT;
double xAMT, yAMT; //slightly left of right from direction of camera
for (int x = 0; x < HEIGHT; x++) {
for (int y = 0; y < WIDTH; y++) {
if (WIDTH > HEIGHT) {
// landscape
xAMT = ((x + 0.5) / WIDTH) * aspectRatio - (((WIDTH - HEIGHT) / (double) HEIGHT) /2);
yAMT = ((HEIGHT - y) + 0.5) / HEIGHT;
}
else if (HEIGHT > WIDTH) {
// portrait
xAMT = (y + 0.5) / WIDTH;
yAMT = (((HEIGHT - y) + 0.5) / HEIGHT) / aspectRatio - (((HEIGHT - WIDTH) / (double) WIDTH) / 2);
}
else {
// square
xAMT = (x + 0.5) / WIDTH;
yAMT = ((HEIGHT - y) + 0.5) / HEIGHT;
}
// YES - this indeed does work
Vector camRayOrigin = camPos;
Vector camRightDir = camRight * (yAMT - 0.5);
Vector camDownDir = camDown * (xAMT - 0.5);
Vector camRayDirection = (camDir + (camRightDir + camDownDir)).normalize();
Ray camRay(camRayOrigin, camRayDirection);
camRayDirection.print_vector();
}
}
}
the text produced by the code above is:
creating rays...
-0.173037 0.117114 0.977928
-0.325543 -0.458438 0.826956
-0.517036 -0.198503 0.832629
-0.54971 -0.326274 0.769002
-0.575177 -0.269626 0.772316
-0.573114 -0.295291 0.764423
-0.575342 -0.283767 0.76711
-0.574404 -0.288958 0.765874
-0.574826 -0.286623 0.766435
-0.574637 -0.287674 0.766183
-0.574716 -0.287234 0.766288
-0.574689 -0.287388 0.766251
-0.574698 -0.287334 0.766264
-0.574695 -0.287353 0.76626
-0.574696 -0.287346 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
-0.574696 -0.287348 0.766261
Vector class:
#include <cmath>
class Vector {
double x, y, z;
int size = 3;
public:
~Vector() {};
Vector() : x(0), y(0), z(0) {}
Vector(double _x, double _y, double _z) : x(_x), y(_y), z(_z) {}
Vector& operator=(Vector rhs);
// Vector mathematical operations
Vector operator+(const Vector& rhs);
Vector& operator+=(const Vector& rhs);
Vector operator-(const Vector& rhs);
Vector& operator-=(const Vector& rhs);
// Vector scalar operations
Vector operator+(const double& rhs);
Vector operator-(const double& rhs);
Vector operator*(const double& rhs);
Vector operator/(const double& rhs);
Vector cross(const Vector& rhs); // Cross-Product
double dot(const Vector& rhs); // Dot-Product
Vector normalize(); // Normalize
Vector negative(); // Negative
double mag(); // Magnitude
void swap(Vector& rhs);
void print_vector();
};
Vector& Vector::operator=(Vector rhs) {
swap(rhs);
return *this;
}
Vector Vector::operator+(const Vector& rhs) {
Vector result(*this);
result += rhs;
return result;
}
Vector& Vector::operator+=(const Vector& rhs) {
this->x += rhs.x;
this->y += rhs.y;
this->z += rhs.z;
return *this;
}
Vector Vector::operator-(const Vector& rhs) {
Vector result(*this);
result -= rhs;
return result;
}
Vector& Vector::operator-=(const Vector& rhs) {
this->x -= rhs.x;
this->y -= rhs.y;
this->z -= rhs.z;
return *this;
}
Vector Vector::operator+(const double& rhs) {
this->x += rhs;
this->y += rhs;
this->z += rhs;
return *this;
}
Vector Vector::operator-(const double& rhs) {
this->x -= rhs;
this->y -= rhs;
this->z -= rhs;
return *this;
}
Vector Vector::operator*(const double& rhs) {
this->x *= rhs;
this->y *= rhs;
this->z *= rhs;
return *this;
}
Vector Vector::operator/(const double& rhs) {
this->x /= rhs;
this->y /= rhs;
this->z /= rhs;
return *this;
}
Vector Vector::cross(const Vector& rhs) {
double a = (y * rhs.z) - (z * rhs.y);
double b = (z * rhs.x) - (x * rhs.z);
double c = (x * rhs.y) - (y * rhs.x);
Vector product(a, b, c);
return product;
}
double Vector::dot(const Vector& rhs) {
double scalar = (x * rhs.x) + (y * rhs.y) + (x * rhs.z);
return scalar;
}
double Vector::mag() {
return sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2));
}
Vector Vector::normalize() {
double mag = sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2));
if (mag != 0) {
this->x /= mag;
this->y /= mag;
this->z /= mag;
}
return *this;
}
Vector Vector::negative() {
this->x *= -1;
this->y *= -1;
this->z *= -1;
return *this;
}
void Vector::swap(Vector& rhs) {
using std::swap;
swap(this->x, rhs.x);
swap(this->y, rhs.y);
swap(this->z, rhs.z);
}
void Vector::print_vector() {
std::cout
<< x
<< " "
<< y
<< " "
<< z
<< std::endl;
}
The issues are in the Vector
class.
You implement the +
, -
, *
, /
(double)
the same way you implement +=
, -=
(const Vector&)
: you change the value of this
.
When implementing the binary operator (the first operand is this
and the second one rhs
), you usually do not want to change the value of the operands. In these case, I strongly suggest you to use const
for the operator to be warned in case of mistakes like this.
Vector operator+(const double& rhs) const;
Instead of:
Vector operator+(const double& rhs);
Then, the implementation is:
Vector Vector::operator+(const double& rhs) const {
Vector result(*this);
result.x += rhs;
result.y += rhs;
result.z += rhs;
return result;
}