0

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;
}
Olivier Moindrot
  • 27,908
  • 11
  • 92
  • 91
user2958542
  • 331
  • 1
  • 8
  • 18
  • It would be fairly useful to simplify your code snippet as much as possible in order to make your code easier to read. There is plenty of code which basicaly has nothing to do with the issue you want to deal with... – Michal Hosala Aug 24 '14 at 20:00
  • @MichalHosala On the contrary, the code loses its definitions for important aspects of the camera and rays coming from it - when it needs to utilize the linear algebra - wrong? I think it is more helpful to actually see the numbers and implementations to grasps what is going on. I have been trying to debug this particular section of code for the past two days and this is the most basic it has gotten without breaking. I also know that the `xAMT` and `yAMT` for landscape and portrait are broken to and want to know what other solutions can be given for the entirety of the code snippet. – user2958542 Aug 24 '14 at 20:37
  • Well, you say that landscape/portrait are broken as well, but having hardcoded `WIDTH == HEIGHT == 10` the provided code will always default to square mode... So it would be nice to at least mention somewhere in your post that you are not only interested in solution when `WIDTH == HEIGHT` ... Also, at the first sight, what purpose does `camRay` have, except for being declared? And on the other hand, where is `Y` declared, which you are using to compute `camRight` ... ? – Michal Hosala Aug 24 '14 at 21:32
  • @MichalHosala I did not realize the `Y` was left out. Thank you for pointing that out. Everything else is fixed. I will be keeping `camRay` there to show that the new ray is getting set from the camera origin with the new specific direction. The print is there as a supplement. – user2958542 Aug 24 '14 at 22:00
  • Your ray tracer produced an image of text? – Jongware Aug 24 '14 at 22:02
  • @Jongware No it does not. I have a bitmap and pixel setting, but for debug purpose I have it printing out the rays to the console and soon found out the rays are incorrect – user2958542 Aug 24 '14 at 22:04
  • 1
    For plain text output it would have been more logically to *paste it as text*. (And use a better caption: "the exact output from this code is this image"...) – Jongware Aug 24 '14 at 22:11
  • @Jongware The text could not be copied and I didn't feel like copy all 100+ lines... sorry – user2958542 Aug 24 '14 at 22:18
  • Windows Command Line, right? [Copy text from a command prompt window](https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/windows_dos_copy.mspx?mfr=true) – Jongware Aug 24 '14 at 22:20
  • @user2958542 How the Vector class looks like? – Cédric Bignon Aug 24 '14 at 23:07
  • @CédricBignon Vector class added – user2958542 Aug 24 '14 at 23:14

1 Answers1

2

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;
}
Cédric Bignon
  • 12,892
  • 3
  • 39
  • 51