[Radiance-general] Re: Radiance-general digest, Vol 1 #22 - 2 msgs

Greg Ward [email protected]
Fri, 12 Oct 2001 09:27:00 -0700


This is a multi-part message in MIME format.
--------------F2F6EFC25830270349AF3F12
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Ron wrote:

I would like to recover the surface normals of the surfaces visible in
every pixel of a Radiance scene.  In other words, I want to trace the
initial ray cast for each pixel, and find the surface normal of the first
surface that ray hits.  I figured out that I could do this using rtrace
-on, if I feed rtrace the rays corresponding to each pixel in my
image.  Is there an easy way to compute all of these rays automatically
using an existing Radiance program, or will I need to write a special .cal
file for rcalc?  I have the feeling that some Radiance gurus could
accomplish this task in one or two lines.

------------
There are two solutions to this problem.  As you say, it is a very handy
thing to be able to do, so I wrote a C program to do just that.  It is
part of the Unix distribution I've been working on and plan to release
as soon as I figure out how.  In the meantime, I am attaching the C file
and manual page to this message, which are fairly short.  The nice thing
about this solution is that it will work with any Radiance view type,
and will generate the exact rays corresponding to the center of each
pixel.  (If you want an absolute guarantee that these correspond to
the pixels sampled with rpict, you will need to set the -pj 0 option
in your rendering.)

The second solution is to apply the following .cal script with rcalc,
which works only for perspective views, found in ray/lib/lib:

{
	proj.cal - calculate image projection vector
}
				{ View Point }
VPx = 0; VPy = 0; VPz = 0;
				{ View Up }
VUx = 0; VUy = 0; VUz = 1;
				{ View Direction }
VDx = 0; VDy = 1; VDz = 0;
				{ View Horizontal and Vertical angles }
VH = 45; VV = 45;
				{ X and Y resolution }
X = 512; Y = 512;
				{ Projected Direction (computed) }
PDx = NVDx + h*IHx + v*IVx;
PDy = NVDy + h*IHy + v*IVy;
PDz = NVDz + h*IHz + v*IVz;
h = x - (X-1)/2; v = y - (Y-1)/2;
				{ Normalized View Direction }
NVDx = VDx/VDl; NVDy = VDy/VDl; NVDz = VDz/VDl;
VDl = sqrt(VDx*VDx + VDy*VDy + VDz*VDz);
				{ Increment Horizontal }
IHx = IHF*NTIHx; IHy = IHF*NTIHy; IHz = IHF*NTIHz;
NTIHx = TIHx/TIHl; NTIHy = TIHy/TIHl; NTIHz = TIHz/TIHl;
TIHx = VDy*VUz-VDz*VUy; TIHy = VDz*VUx-VDx*VUz; TIHz = VDx*VUy-VDy*VUx;
TIHl = sqrt(TIHx*TIHx + TIHy*TIHy + TIHz*TIHz);
IHF = 2*tan(PI/180/2*VH)/X;
				{ Increment Vertical }
IVx = IVF*(NTIHy*NVDz-NTIHz*NVDy);
IVy = IVF*(NTIHz*NVDx-NTIHx*NVDz);
IVz = IVF*(NTIHx*NVDy-NTIHy*NVDx);
IVF = 2*tan(PI/180/2*VV)/Y;

PI = 3.14159265358979323846

--------------
The horizontal and vertical increment vectors get added to a unit
direction vector to get the final view direction computed in PDx,
PDy, and PDz.  The view point (origin) remains the same for a
perspective view.  An example application of the above file with
a specific view origin, direction, and angle might be:

cnt 512 512 | rcalc -f proj.cal -e 'VPx=15.3;VPy=10.1;VPz=-3.3;' \
	-e 'VDx=.394;VDy=-.731;VDz=-.053;' \
	-e 'VH=30;VV=30;' -e '$1=VPx;$2=VPy;$3=VPz;' \
	-e '$4=PDx;$5=PDy;$6=PDz;' | rtrace [rtrace options]

Hope this helps.
-Greg
--------------F2F6EFC25830270349AF3F12
Content-Type: text/plain; charset=us-ascii; x-mac-type="54455854"; x-mac-creator="522A6368";
 name="vwrays.1"
Content-Transfer-Encoding: 7bit
Content-Description: Unknown Document
Content-Disposition: inline;
 filename="vwrays.1"

.\" SCCSid "@(#)vwrays.1 3.5 1/15/99 SGI"
.TH VWRAYS 1 1/15/99 RADIANCE
.SH NAME
vwrays - compute rays for a given picture or view
.SH SYNOPSIS
.B vwrays
.B "[ -i -f{a|f|d} | -d ]"
{
.B "view opts .."
|
.B picture
.B [zbuf]
}
.SH DESCRIPTION
.I Vwrays
takes a picture or view specification and computes the ray origin and
direction corresponding to each pixel in the image.
This information may then be passed to
.I rtrace(1)
to perform other calculations.
If a given pixel has no corresponding ray (because it is outside the
legal view boundaries), then six zero values are sent instead.
.PP
The
.I -i
option may be used to specify desired pixel positions on the standard
input rather than generating all the pixels for a given view.
.PP
The
.I -f
option may be used to set the record format to something other than the
default ASCII.
Using raw float or double records for example can reduce the time
requirements of transferring and interpreting information in
.I rtrace.
.PP
View options may be any combination of standard view parameters described
in the
.I rpict(1)
manual page, including input from a view file with the
.I \-vf
option.
Additionally, the target X and Y dimensions may be specified with
.I -x
and
.I -y
options, and the pixel aspect ratio may be given with
.I -p.
The default dimensions are 512x512, with a pixel aspect ratio of 1.0.
Just as in
.I rpict,
the X or the Y dimension will be reduced if necessary
to best match the specified pixel
aspect ratio, unless this ratio is set to zero.
.PP
If the
.I -d
option is given, then
.I vwrays
just prints the computed image dimensions, which are based on the view
aspect and the pixel aspect ratio just described.
The
.I -ld
switch will also be printed, with
.I -ld+
if the view file has an aft clipping plane, and
.I -ld-
otherwise.
This is useful for passing options to the
.I rtrace
command line.
(See below.)
.PP
If the view contains an aft clipping plane
.I (-va
option), then the magnitudes of the ray directions will
equal the maximum distance for each pixel, which will be interpreted
correctly by
.I rtrace
with the
.I -ld+
option.
Note that this option should not be given unless there is an aft
clipping plane, since the ray direction vectors will be normalized
otherwise, which would produce a uniform clipping distance of 1.
.PP
If a picture is given on the command line rather than a set of view options,
then the view and image dimensions are taken from the picture file, and
the reported ray origins and directions will exactly match the center of each
pixel in the picture.
.PP
If a depth buffer file is given as well, then
.I vwrays
computes the intersection point of each pixel ray (equal to the ray origin
plus the depth times the ray direction), and reports this instead of the
ray origin.
The reported ray direction will also be reversed.
The interpretation of this data is an image of origins and directions
for light rays leaving the scene surfaces to strike each pixel.
.SH EXAMPLES
To compute the ray intersection points and returned directions corresponding
to a picture and its depth buffer:
.IP "" .2i
vwrays scene_v2.pic scene_v2.zbf > scene_v2.pts
.PP
To determine what the dimensions of a given view would be:
.IP "" .2i
vwrays -d -vf myview.vf -x 2048 -y 2048
.PP
To generate a RADIANCE picture using
.I rtrace
instead of
.I rpict:
.IP "" .2i
vwrays -ff -vf view1.vf -x 1024 -y 1024 |
rtrace `vwrays -d -vf view1.vf -x 1024 -y 1024` -ffc scene.oct > view1.pic
.SH AUTHOR
Greg Ward Larson
.SH ACKNOWLEDGMENT
This work was supported by Silicon Graphics, Inc.
.SH BUGS
Although
.I vwrays
can reproduce any pixel ordering (i.e., any image orientation) when given
a rendered picture, it will only produce standard scanline-ordered rays when 
given a set of view parameters.
.SH "SEE ALSO"
rcalc(1), rpict(1), rtrace(1)

--------------F2F6EFC25830270349AF3F12
Content-Type: text/plain; charset=us-ascii; x-mac-type="54455854"; x-mac-creator="522A6368";
 name="vwrays.c"
Content-Transfer-Encoding: 7bit
Content-Description: Unknown Document
Content-Disposition: inline;
 filename="vwrays.c"

/* Copyright (c) 1997 Silicon Graphics, Inc. */

#ifndef lint
static char SCCSid[] = "@(#)vwrays.c 3.3 10/17/97 SGI";
#endif

/*
 * Compute rays corresponding to a given picture or view.
 */


#include "standard.h"

#include "view.h"

#include "resolu.h"

extern int	putf(), putd(), puta();

int	(*putr)() = puta;

VIEW	vw = STDVIEW;

RESOLU	rs = {PIXSTANDARD, 512, 512};

double	pa = 1.;

int	zfd = -1;

int	fromstdin = 0;

char	*progname;


main(argc, argv)
int	argc;
char	*argv[];
{
	char	*err;
	int	rval, getdim = 0;
	register int	i;

	progname = argv[0];
	if (argc < 2)
		goto userr;
	for (i = 1; i < argc && argv[i][0] == '-'; i++)
		switch (argv[i][1]) {
		case 'f':			/* output format */
			switch (argv[i][2]) {
			case 'a':			/* ASCII */
				putr = puta;
				break;
			case 'f':			/* float */
				putr = putf;
				break;
			case 'd':			/* double */
				putr = putd;
				break;
			default:
				goto userr;
			}
			break;
		case 'v':			/* view file or option */
			if (argv[i][2] == 'f') {
				rval = viewfile(argv[++i], &vw, NULL);
				if (rval <= 0) {
					fprintf(stderr,
						"%s: no view in file\n",
							argv[i]);
					exit(1);
				}
				break;
			}
			rval = getviewopt(&vw, argc-i, argv+i);
			if (rval < 0)
				goto userr;
			i += rval;
			break;
		case 'd':			/* report dimensions only */
			getdim++;
			break;
		case 'x':			/* x resolution */
			rs.xr = atoi(argv[++i]);
			if (rs.xr <= 0) {
				fprintf(stderr, "%s: bad x resolution\n",
						progname);
				exit(1);
			}
			break;
		case 'y':			/* y resolution */
			rs.yr = atoi(argv[++i]);
			if (rs.yr <= 0) {
				fprintf(stderr, "%s: bad y resolution\n",
						progname);
				exit(1);
			}
			break;
		case 'p':			/* pixel aspect ratio */
			pa = atof(argv[++i]);
			break;
		case 'i':			/* get pixels from stdin */
			fromstdin = 1;
			break;
		default:
			goto userr;
		}
	if (i > argc | i+2 < argc)
		goto userr;
	if (i < argc) {
		rval = viewfile(argv[i], &vw, &rs);
		if (rval <= 0) {
			fprintf(stderr, "%s: no view in picture\n", argv[i]);
			exit(1);
		}
		if (i+1 < argc) {
			zfd = open(argv[i+1], O_RDONLY);
			if (zfd < 0) {
				fprintf(stderr,
					"%s: cannot open depth buffer\n",
						argv[i+1]);
				exit(1);
			}
		}
	}
	if ((err = setview(&vw)) != NULL) {
		fprintf(stderr, "%s: %s\n", progname, err);
		exit(1);
	}
	if (i == argc)
		normaspect(viewaspect(&vw), &pa, &rs.xr, &rs.yr);
	if (getdim) {
		printf("-x %d -y %d -ld%c\n", rs.xr, rs.yr,
				vw.vaft > FTINY ? '+' : '-');
		exit(0);
	}
	if (fromstdin)
		pix2rays(stdin);
	else
		putrays();
	exit(0);
userr:
	fprintf(stderr,
	"Usage: %s [ -i -f{a|f|d} | -d ] { view opts .. | picture [zbuf] }\n",
			progname);
	exit(1);
}


pix2rays(FILE *fp)
{
	static FVECT	rorg, rdir;
	float	zval;
	double	px, py;
	int	pp[2];
	double	d;
	register int	i;

	while (fscanf(fp, "%lf %lf", &px, &py) == 2) {
		if (px < 0 || px >= rs.xr ||
				py < 0 || py >= rs.yr) {
			fprintf(stderr,
				"%s: (x,y) pair (%.0f,%.0f) out of range\n",
					px, py);
			exit(1);
		}
		if (zfd >= 0) {
			loc2pix(pp, &rs, px/rs.xr, py/rs.yr);
			if (lseek(zfd,
				(pp[1]*scanlen(&rs)+pp[0])*sizeof(float), 0)
					< 0 ||
					read(zfd, &zval, sizeof(float))
					< sizeof(float)) {
				fprintf(stderr, "%s: depth buffer read error\n",
						progname);
				exit(1);
			}
		}
		d = viewray(rorg, rdir, &vw, px/rs.xr, py/rs.yr);
		if (d < -FTINY)
			rorg[0] = rorg[1] = rorg[2] =
			rdir[0] = rdir[1] = rdir[2] = 0.;
		else if (zfd >= 0)
			for (i = 0; i < 3; i++) {
				rorg[i] += rdir[i]*zval;
				rdir[i] = -rdir[i];
			}
		else if (d > FTINY) {
			rdir[0] *= d; rdir[1] *= d; rdir[2] *= d;
		}
		(*putr)(rorg, rdir);
	}
	if (!feof(fp)) {
		fprintf(stderr, "%s: expected px py on input\n", progname);
		exit(1);
	}
}


putrays()
{
	static FLOAT	loc[2];
	static FVECT	rorg, rdir;
	float	*zbuf;
	int	sc;
	double	d;
	register int	si, i;

	if (zfd >= 0) {
		zbuf = (float *)malloc(scanlen(&rs)*sizeof(float));
		if (zbuf == NULL) {
			fprintf(stderr, "%s: not enough memory\n", progname);
			exit(1);
		}
	}
	for (sc = 0; sc < numscans(&rs); sc++) {
		if (zfd >= 0) {
			if (read(zfd, zbuf, scanlen(&rs)*sizeof(float)) <
					scanlen(&rs)*sizeof(float)) {
				fprintf(stderr, "%s: depth buffer read error\n",
						progname);
				exit(1);
			}
		}
		for (si = 0; si < scanlen(&rs); si++) {
			pix2loc(loc, &rs, si, sc);
			d = viewray(rorg, rdir, &vw, loc[0], loc[1]);
			if (d < -FTINY)
				rorg[0] = rorg[1] = rorg[2] =
				rdir[0] = rdir[1] = rdir[2] = 0.;
			else if (zfd >= 0)
				for (i = 0; i < 3; i++) {
					rorg[i] += rdir[i]*zbuf[si];
					rdir[i] = -rdir[i];
				}
			else if (d > FTINY) {
				rdir[0] *= d; rdir[1] *= d; rdir[2] *= d;
			}
			(*putr)(rorg, rdir);
		}
	}
	if (zfd >= 0)
		free((char *)zbuf);
}


puta(ro, rd)		/* put out ray in ASCII format */
FVECT	ro, rd;
{
	printf("%.5e %.5e %.5e %.5e %.5e %.5e\n",
			ro[0], ro[1], ro[2],
			rd[0], rd[1], rd[2]);
}


putf(ro, rd)		/* put out ray in float format */
FVECT	ro, rd;
{
	float v[6];

	v[0] = ro[0]; v[1] = ro[1]; v[2] = ro[2];
	v[3] = rd[0]; v[4] = rd[1]; v[5] = rd[2];
	fwrite(v, sizeof(float), 6, stdout);
}


putd(ro, rd)		/* put out ray in double format */
FVECT	ro, rd;
{
	double v[6];

	v[0] = ro[0]; v[1] = ro[1]; v[2] = ro[2];
	v[3] = rd[0]; v[4] = rd[1]; v[5] = rd[2];
	fwrite(v, sizeof(double), 6, stdout);
}

--------------F2F6EFC25830270349AF3F12--