A nice new paper from Wyman, Hoetzlein, and Lefohn out of NVIDIA research digs deeper into the idea of a shadow map sampled in screen space. The paper and video are online. This basic idea has been kicking around for over a decade and most people thought it was very promising. This paper seems to have finally really made the idea live up to its promise (watch the video!).

I think this will be a big paper: my biggest surprise talking to video game programmers has been how much effort they put into shadows and yet that is still the source of their most annoying dynamic artifacts. I look forward to seeing good shadows in games!

## Tuesday, February 24, 2015

## Saturday, February 14, 2015

### A C++ vec3 class

I'm teaching an intro graphics class as an adjunct at Westminster College (and really liking it-- it is a great environment and I would recommend it as a very good place to go as an undergrad). The assignments are mostly ray tracing and I have been writing my solutions from scratch so I can understand what is needed for them. My first decision was programming language. The students are all either using Python or Java, and so I didn't want to use either of those. I tried Swift which I am enamored with but I ran into a compiler bug early and decided some old battle-tested language would be better. I almost did C but operator overloading is too much to give up. So I went with C++. In the past I have always went with the heuristic:

This can be taken to an extreme where a

On the opposite end of the spectrum are languages like GLSL which I have been using a lot lately where representation determines type and most graphics variables are

I decided to go the GLSL route simply because I am liking it in practice, and verbose variable names make errors less likely. So for the first time in at least a decade I wrote a new C++ vector class vec3. First question was "

vec3 v = vec3::cross(u, w); // ugly

So I just went with double (precision problems are a pain). Some typedef REAL might be wise but I was too lazy.

I'll be curious to see if I consider this a mistake by the end of the semester!

Here's the resulting class:

*If it has the same representation (e.g., 3D Cartesian vectors and 3D rgb colors), that doesn't mean it is the same class. What IS the thing?*This can be taken to an extreme where a

*length*and a*time*are not floats, but are rather different types, and an operator*length/time*returns a*velocity*. Jim Arvo and Brian Smits (and probably many others) experimented with this and found the C++ typing became a little too cumbersome to manage. They both thought some real language support for SI units etc. might be a good idea, but rolling your own was probably too hard in practice.On the opposite end of the spectrum are languages like GLSL which I have been using a lot lately where representation determines type and most graphics variables are

*vec3*or*float*. If you add a color to a surface normal that is your problem.I decided to go the GLSL route simply because I am liking it in practice, and verbose variable names make errors less likely. So for the first time in at least a decade I wrote a new C++ vector class vec3. First question was "

*float, double, or templated*?" I tried templated but it is too much typing. For example, here is a cross product:vec3

So I just went with double (precision problems are a pain). Some typedef REAL might be wise but I was too lazy.

I'll be curious to see if I consider this a mistake by the end of the semester!

Here's the resulting class:

#ifndef VEC3_HPP #define VEC3_HPP #includetemplate class Vec3 { private: // A Vec3 simply has three properties called x, y and z T x, y, z; public: // ------------ Constructors ------------ // Default constructor Vec3() { x = y = z = 0; }; // Three parameter constructor Vec3(T xValue, T yValue, T zValue) { x = xValue; y = yValue; z = zValue; } // ------------ Getters and setters ------------ void set(const T &xValue, const T &yValue, const T &zValue) { x = xValue; y = yValue; z = zValue; } T getX() const { return x; } T getY() const { return y; } T getZ() const { return z; } void setX(const T &xValue) { x = xValue; } void setY(const T &yValue) { y = yValue; } void setZ(const T &zValue) { z = zValue; } // ------------ Helper methods ------------ // Method to reset a vector to zero void zero() { x = y = z = 0; } // Method to normalise a vector void normalise() { // Calculate the magnitude of our vector T magnitude = sqrt((x * x) + (y * y) + (z * z)); // As long as the magnitude isn't zero, divide each element by the magnitude // to get the normalised value between -1 and +1 if (magnitude != 0) { x /= magnitude; y /= magnitude; z /= magnitude; } } // Static method to calculate and return the scalar dot product of two vectors // // Note: The dot product of two vectors tell us things about the angle between // the vectors. That is, it tells us if they are pointing in the same direction // (i.e. are they parallel? If so, the dot product will be 1), or if they're // perpendicular (i.e. at 90 degrees to each other) the dot product will be 0, // or if they're pointing in opposite directions then the dot product will be -1. // // Usage example: double foo = Vec3 ::dotProduct(vectorA, vectorB); static T dotProduct(const Vec3 &vec1, const Vec3 &vec2) { return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z; } // Non-static method to calculate and return the scalar dot product of this vector and another vector // // Usage example: double foo = vectorA.dotProduct(vectorB); T dotProduct(const Vec3 &vec) const { return x * vec.x + y * vec.y + z * vec.z; } // Static method to calculate and return a vector which is the cross product of two vectors // // Note: The cross product is simply a vector which is perpendicular to the plane formed by // the first two vectors. Think of a desk like the one your laptop or keyboard is sitting on. // If you put one pencil pointing directly away from you, and then another pencil pointing to the // right so they form a "L" shape, the vector perpendicular to the plane made by these two pencils // points directly upwards. // // Whether the vector is perpendicularly pointing "up" or "down" depends on the "handedness" of the // coordinate system that you're using. // // Further reading: http://en.wikipedia.org/wiki/Cross_product // // Usage example: Vec3 crossVect = Vec3 ::crossProduct(vectorA, vectorB); static Vec3 crossProduct(const Vec3 &vec1, const Vec3 &vec2) { return Vec3(vec1.y * vec2.z - vec1.z * vec2.y, vec1.z * vec2.x - vec1.x * vec2.z, vec1.x * vec2.y - vec1.y * vec2.x); } // Easy adders void addX(T value) { x += value; } void addY(T value) { y += value; } void addZ(T value) { z += value; } // Method to return the distance between two vectors in 3D space // // Note: This is accurate, but not especially fast - depending on your needs you might // like to use the Manhattan Distance instead: http://en.wikipedia.org/wiki/Taxicab_geometry // There's a good discussion of it here: http://stackoverflow.com/questions/3693514/very-fast-3d-distance-check // The gist is, to find if we're within a given distance between two vectors you can use: // // bool within3DManhattanDistance(Vec3 c1, Vec3 c2, float distance) // { // float dx = abs(c2.x - c1.x); // if (dx > distance) return false; // too far in x direction // // float dy = abs(c2.y - c1.y); // if (dy > distance) return false; // too far in y direction // // float dz = abs(c2.z - c1.z); // if (dz > distance) return false; // too far in z direction // // return true; // we're within the cube // } // // Or to just calculate the straight Manhattan distance you could use: // // float getManhattanDistance(Vec3 c1, Vec3 c2) // { // float dx = abs(c2.x - c1.x); // float dy = abs(c2.y - c1.y); // float dz = abs(c2.z - c1.z); // return dx+dy+dz; // } // static T getDistance(const Vec3 &v1, const Vec3 &v2) { T dx = v2.x - v1.x; T dy = v2.y - v1.y; T dz = v2.z - v1.z; return sqrt(dx * dx + dy * dy + dz * dz); } // Method to display the vector so you can easily check the values void display() { std::cout << "X: " << x << "\t Y: " << y << "\t Z: " << z << std::endl; } // ------------ Overloaded operators ------------ // Overloaded addition operator to add Vec3s together Vec3 operator+(const Vec3 &vector) const { return Vec3 (x + vector.x, y + vector.y, z + vector.z); } // Overloaded add and asssign operator to add Vec3s together void operator+=(const Vec3 &vector) { x += vector.x; y += vector.y; z += vector.z; } // Overloaded subtraction operator to subtract a Vec3 from another Vec3 Vec3 operator-(const Vec3 &vector) const { return Vec3 (x - vector.x, y - vector.y, z - vector.z); } // Overloaded subtract and asssign operator to subtract a Vec3 from another Vec3 void operator-=(const Vec3 &vector) { x -= vector.x; y -= vector.y; z -= vector.z; } // Overloaded multiplication operator to multiply two Vec3s together Vec3 operator*(const Vec3 &vector) const { return Vec3 (x * vector.x, y * vector.y, z * vector.z); } // Overloaded multiply operator to multiply a vector by a scalar Vec3 operator*(const T &value) const { return Vec3 (x * value, y * value, z * value); } // Overloaded multiply and assign operator to multiply a vector by a scalar void operator*=(const T &value) { x *= value; y *= value; z *= value; } // Overloaded multiply operator to multiply a vector by a scalar Vec3 operator/(const T &value) const { return Vec3 (x / value, y / value, z / value); } // Overloaded multiply and assign operator to multiply a vector by a scalar void operator/=(const T &value) { x /= value; y /= value; z /= value; } }; #endif

Subscribe to:
Posts (Atom)