Home / C/C++ On Github

Utility

Procedural

The Procedural library defines the pattern2 class, which can store 2D arrays of floating-point values. The pattern2 class provides utilities for copying one image onto another, adding and multiplying the values of corresponding pixels in two images, normalizing images, and so on.

The other class is procedural. This class defines a number of functions that fill pattern2 objects with various patterns such as simplex and Worley noise, waves, and gradients. The below code generates both simplex and Worley noise, and saves the generated images to disk as pgm files.


	#include <stdio.h>

	#include "util.hpp"

	using namespace util;

	int main() {
		// Create a 2D pattern object and a procedural generator.
		pattern2 pat(1024, 1024);
		procedural proc;
		
		// Generate and save simplex noise.
		proc.simplex(pat, 10, 10);
		pat.saveppm("simplex.pgm");
		
		// Generate and save worley noise.
		proc.worley(pat, 10, 10);
		pat.saveppm("worley.pgm");
		
		return 0;
	}
			
Simplex noise.

Simplex Noise.

Worley cell noise.

Worley Noise.

The procedural library can also generate a variety of less complex patterns.

Circle of decreasing brightness. Gradient. Sine wave emanating from a point. Sine wave propagating in a specific direction.

The goal of the library is to allow patterns to be generated and then combined creatively to produce the desired result. The below image is the sum of three simplex noise samples, multiplied by a fourth and limited in height by a logistic function with the goal of producing the heightmap for a random island.

Procedurally generated heightmap of an island.

The most sophisticated algorithm in the procedural library is the simplex noise algorithm. This algorithm is based on an older noise generation algorithm referred to as Perlin noise after Ken Perlin. The algorithm involves creating a grid of random vectors and interpolating between the dot products of those vectors with the differences between the grid points and the point being sampled. When generating an image of simplex noise, it may be tempting to use a function that samples simplex noise at a point to generate each pixel of the image individually. This, however, results in substantial amounts of redundant calculations. In particular, the vectors on the grid whose values affect the sample are regenerated for every point within that grid square. Instead, it makes more sense to generate all of the random vectors and cache them for the duration of the render.

An additional complication imposed by simplex noise is that it uses "simples", or equilateral triangles in the 2D case, rather than a square grid. This is accomplished by scaling the sampling point along the line y=x and dividing the squares in half to produce the necessary grid. It has the effect of reducing artifacts along the grid lines of the square grid, making the noise appear more natural.

Vec

The vec library implements 2, 3, and 4 dimensional vectors, each with floating-point and integer variants. These classes support numerous operations as applicable, such as normalizing, dot product, cross product, vector arithmetic, and so on. Another class, complex, inherits from the vecd2 class and represents complex numbers, allowing additional functionality such as representing rotations. The quaternion class works the same except that it inherits from vecd4 and represents rotations in 3D space. This class is particularly useful as it allows 3D points to be rotated around arbitrary axes, a fundamental first steps in 3D animation and simulation. The following code demonstrates the process of rotating a point about an axis with the vec library.


	#include <stdio.h>

	#include "util.hpp"

	using namespace util;

	int main() {
		// The point to be rotated.
		vecd3 p(1, 0, 1);
		
		// The axis to rotate around and amount to rotate in radians.
		vecd3 axis(2, 1, 1);
		float theta = 0.79; // About 45 degrees.
		
		//Create a quaternion to represent the rotation.
		quaternion rot(axis, theta);
		
		// Rotate the point.
		vecd3 p_n = rot.apply(p);
		
		// Prints (1.29, -0.14, 0.56)
		printf("(%.2f, %.2f, %.2f)\n", p_n.x, p_n.y, p_n.z);
		
		return 0;
	}
			

Additional Libraries

This library also includes the darray class, a dynamically allocated array implementation that strictly requires the array to be manually resized as needed. This ensures that all array reallocations, and their performance impacts, are explicitly visible to the programmer. It also presents the programmer with the problem of figuring out exactly how an array should be resized if resizing may be necessary, to minimize performance and memory impacts.

The library includes an expression tree class as well, where the operations can be arbitrary functions. Finally there is a geometry library that was originally planned to be used for many kinds of intersection functions, but it only contains one such function because it turns out you can do just about anything if you can test for intersection between a triangle and a line.