make all
The current status of this entry is:
STATUS: INABIAF - please **DO NOT** fix
For more detailed information see 2013 hou bugs.
./hou [scene-file-name] [options]
Follow the instructions in stdout
, preferably with an auto-refreshing PPM
image viewer ready. Refresh the image every time the output refreshes, all
effects should be more or less recognizable when you see 16.
./try.sh
Try opening the file noted by the program then let the program run a while and every so often reopen the file, to see how it changes. The author suggests that you leave the program running overnight to see what happens. If however you do not have all night :-) then the following JPEG files should show you what happens with some of the invocations above:
This program does not terminate by itself: you must kill hou
(but not Qiming
Hou :-) ) in order to end the program.
You could consider that this program violates the source code size limit. This is because the first compilation of this program is really just a decompressor to generate the real source code of the program.
This program will loop infinitely while progressively refining a raytraced image.
NOTE: the author refers to a.c, placed in a gzipped file a.c.gz
. We do not
include it but it can be generated like:
cc -Wall hou.c -o hou -lm
./hou > a.c
but there is no need to do this as the Makefile takes care of it without even needing to create a temporary file.
This program is a programmable rendering engine with a built-in default scene. The standard command line is:
./hou [scene-file-name] [options]
As hou
runs, it writes a progressively refining image to a ppm file specified
in the scene. The initialization may take a while, but once it’s done, a rough
preview should be available in seconds. Leave hou
running for the night, and you
get a high quality result like the attached *.jpg
files. Kill hou
manually
after you’re satisfied with the image quality.
To save time and energy for the judges, rendered images for all provided scenes are provided as attached files.
./hou otherroom.scene
gives a rough idea about the overall
illumination at 16 samples per pixel (i.e., when the program prints 16), whereas
the naive approach ./hou otherroom.scene NAIVE
only produces a mess of white
dots../hou
overnight? No problem! You can kill and
resume a rendering session whenever you want. The renderer automatically saves
the progress every 16 samples and resumes where it’s left off when restarted.
Also, each scene/parameter combination gets a different saved session so you
don’t have to worry about conflicts.grep
“size limit”). Please see the Self-imposed
restrictions section below for more details.hou
does not terminate (as suggested by the second line of rule 6).cc(1)
and
make(1)
. No gzip(1)
compression! a.c.gz
doesn’t fit in 2053 bytes, anyway.#define
(or cc -D
) at all.fopen()
ed with "rb"
/ "wb"
for Windows compatibility. The PPM
header has a comment line for non-standard-compliant viewers (specifically, my
old HDRShop 1.0). And there is a nice text message saying “please wait…”.
Despite the messy look, a.c and hou.c compile warning-free
(hou.c even wastes 18 bytes on #include<stdio.h>
just for putchar(3)
).
a.c compiles mostly clean in the C99/ANSI modes of clang and gcc (with -Wall --pedantic
). The only warning generated is a pedantic one: "string constant too long"
.double
, and assumes int
to be
32-bits. 3225 3225 3225 9 9 3225 3225
1 1 1 1 1 1 1 1 1 1
4225 1226 1 1 1 1 1222 1226
1 1 1 1 1 1 1 1 1
4226 1 4226 8 4222 4226 1 1
The program consists of a recursive-descent interpreter, a 3DDDA
(3D Discrete
Differential Analysis) ray tracer, a PSSMLT
(Primary Sample Space Metropolis
Light Transport) light path sampler, all squeezed into the size limit using a
PPM
compressor (Prediction by Partial Matching, and yes, the output format is
chosen for the pun..).
PSSMLT
uses the Metropolis-Hasting algorithm to sample a 32D unit hypercube.
Each point in the hypercube is interpreted as a sequence of random numbers, and
is sent to a path tracer to generate a light path. The point’s
Metropolis-Hasting energy is then defined as the corresponding path’s
contribution value to the final image. Since each path is sampled with a
probability proportional to its energy, the sample distribution directly
corresponds to the final image, which can then be produced as a simple per-pixel
histogram of all generated paths. The robustness comes from a state mutation
strategy that actively tries to explore the neighborhood of high energy peaks
(e.g. paths that happen to hit the light source in
otherroom.scene). In addition, a rudimentary form of lens
path stratification is added to balance the attention each pixel receives. The
Metropolis-Hasting process completely avoids the tell-tale pixel sampling loop
required in most other image generation methods.
The 3DDDA
tracer is chosen for scalability: its performance doesn’t get much
worse as scene complexity increases. Another benefit is that with the DDA
code
in place one can naturally use hierarchical grids as an acceleration structure.
The downside, of course, is that the setup involves quite a few divisions, which
naturally turns into divisions-by-zero. Fortunately, the IEEE754 standard has a
nice set of rules just for this purpose and the arithmetics are organized in a
specific way to take advantage of this. The shader interpreter component is
relatively straightforward, just an expression evaluator stripped to the bare
minimum – it doesn’t even support numerical constants natively. A final little
bit is a just-good-enough PRNG (Pseudo Random Number Generator) to replace the
low precision Windows rand()
and the non-C99 Unix drand48(3)
. An overnight
session would run through its short period many times, but that doesn’t
necessarily map to the same set of paths in PSSMLT
. After all,
Metropolis-Hasting used an even worse PRNG in their 1953 paper.
The PPM
compressor uses statically weighted fixed order contexts with an
arithmetic encoder tweaked for iocccsize.c. The encoder emits octet-space pairs
where each octet encodes ~6.5 bits of information and each space encodes 2 bits
(thanks to the generous definition of “space” in iocccsize.c). The compressor
actively shuffles the variable names around until the compressed string happens
to contain enough {};
s to pass the final iocccsize.c test.
There are a few other tweaks:
The PPM
model uses mostly whitespace characters for weights.
The encoder never emits '"'
and '\\'
.
The decoder uses an O(n^2) algorithm to avoid the gigabytes-sized hash table
frequently found in other PPM
implementations.