2008年6月7日星期六

What the hell is it

I once let the truest love slip away from before my eyes.

Only to find myself regretting when it was too late,

No pain in the world comes near to this.

If only the God would give me another chance,

I would say to the girl I love you.

If there had to be a limit of time,

I pray its ten thousand years.


 

心情

什么时候,我开始了烦恼?

我也不知道,

只知道,我的心情开始复杂起来。

2007年5月25日星期五

2007年5月20日星期日

Radiance RGBE文件格式 C语言读写类

2.2 Radiance RGBE文件格式
RGBE文件的扩展名为.hdr,RGBE正式名称为Radiance RGBE格式。这个本来是BR、FR等作为radiance材质的一种格式,也叫做radiance map,后来成为流行的一种HDR格式。所谓E,就是指数。Radiance RGBE文件每个通道为8bit BYTE数据类型,4个通道一共是32 bit。RGBE可以使用RLE压缩编码压缩,也可以不压缩。由文件头、RGBE数据组成。
文件头如下:
类型 输出格式
char programtype[16]; //#?Radiance\n#Generated by still\n
float gamma; //1.0
float exposure; //1.0
字符串常量 //FORMAT=32-bit_rle_rgbe\n\n
int nWidth, int nHeight //-Y nHeight +X nWidth\n
RGBE数据与HDR FP32(RGB)相互转换公式如下:
1、rgbe->FP32(RGB)
如果e为0, R = G = B = 0.0,否则:
R = r * 2^(e – 128 - 8);
G = g * 2^(e – 128 - 8);
B = b * 2^(e – 128 - 8);

2、FP32(RGB) -> rgbe
v = max(R, G, B);
如果v < 1e-32, r = g = b = e = 0, 否则:
将v用科学计算法表示成 v = m * 2 ^ n ( 0 < m < 1):
r = R * m * 256.0/v;
g = G * m * 256.0/v;
b = B * m * 256.0/v;
e = n + 128;

Still注:
1、我们一般说HDR采用FP32,指的是HDR图象运算时候的内存数据类型,而Radiance RGBE文件采用8bit BYTE类型存储HDR数据。也就是说打开Radiance RGBE文件,要使用上面的公式1将Radiance RGBE文件的8bit BYTE文件数据转换为FP 32的HDR内存数据进行运算;保存为Radiance RGBE文件时,要使用上面的公式2将HDR的FP32内存数据转换为Radiance RGBE的8bit BYTE文件数据进行保存。同理,OpenEXR文件的读写也存在将其FP 16的文件数据到HDR的 FP32图象数据的转换;而下面将要讲的Float Tiff是不需要进行数据转换,直接将HDR的FP 32图象数据保存到TIFF文件中即可。
2、Radiance有多种文件格式,其官方库包含内容比较复杂,所以,实际的读写没有使用其官方库,而是使用了网络上一个简单的C语言读写类,Still并对其进行了部分修改(在文件头写入“Generated by Still”)。

读写类链接地址:http://www.graphics.cornell.edu/~bjw/rgbe.html
官方库链接地址:http://radsite.lbl.gov/radiance/

*************************************************************************

http://www.graphics.cornell.edu/~bjw/rgbe.html

RGBE File Format

What is it?
RGBE is an image format invented by Greg Ward. It stores pixels as one byte rgb (red, green, and blue) values with a one byte shared exponent. Thus it store four bytes per pixel.

Why is it?
Its biggest advantage is that it allows to have pixels to have the extended range and precision of floating point values. Often when we generate images from light simulations, the range of pixels values is much greater than will nicely fit into the standard 0 to 255 range of standard 24-bit image formats. As a result we either truncate bright pixels to 255 or we end up losing all our precision in dimmer pixels. By using a shared exponent, the rgbe format gains some of the advantages floating point values without the 12 bytes per pixel needed for single precision IEEE values. It can handle very bright pixels without loss of precision for darker ones.

Is there code to read/write RGBE files?
Greg Ward provides code to handle RGBE files in his Radiance rendering system. However the RGBE format is very useful even if you are not using Radiance and deserves to become a standard format throughout the rendering community and beyond. To facilitate this, I have implemented a minimal set of routines to read and write RGBE files. This code is provided without any guarantees whatsoever, but please do send me a note if you find any bugs.

rgbe.txt - description of interface
rgbe.h - header file
rgbe.c - C code
Where can I find more information?
See "Real Pixels" by Greg Ward in Graphics Gems II .

************************************

rgbe.txt--description of interface

The rgbe image file format was invented by Greg Ward to reduce the precision problems inherent in normal 24bit file formats. Many programs including photorealistic renderers produce pixels with a wide range of values. Internally the programs usually handle this by representing colors by floating point values. However writing out the floating point values directly would produce very large files (~96 bits/pixel). The rgbe format works by having all channels (typically red, green, and blue) share a single exponent. Thus a pixel consists of three 8 bit mantissas and an 8 bit exponent for 32 bits per pixel. This makes for a compact format which can handle wide range of pixels values (from 0 to 2^127) with reasonable precision. See "Real Pixels" by Greg Ward in Graphics Gems II for more details. This code was written based on Greg Ward's code (available from the radiance home page ftp://radsite.lbl.gov/home.html) for reading and writing rgbe files. I have rewritten the code as ANSI C and tried to clean up the code and comment it to make it easier to understand. I've also tried to make the error detection a little more robust.
Here's the minimal code for using these files. sample minimal writing code:
f = fopen(image_filename,"wb");
RGBE_WriteHeader(f,image_width,image_height,NULL);
RGBE_WritePixels(f,image,image_width*image_height);
fclose(f);
For run length encoding instead of RGBE_WritePixels, use RGBE_WritePixels_RLE(f,image,image_width,image_height). sample minimal reading code:
f = fopen(image_filename,"rb");
RGBE_ReadHeader(f,&image_width,&image_height,NULL);
image = (float *)malloc(sizeof(float)*3*image_width*image_height);
RGBE_ReadPixels_RLE(f,image,image_width,image_height);
fclose(f);
You can use RGBE_Read_Pixels instead but it will not handle run length encoded file correctly.
For more information see the rgbe.c file. (Note: these files are available at http://www.graphics.cornell.edu/~bjw/ )
Please note: By definition of the rgbe format, all pixels should be in units of watts/steradian/meter^2 unless otherwise noted in the header. If the header contains an exposure field then dividing pixels values by the should result in values in watts/steradian/meter^2. See the rgbe.h file for other fields in the header which are supported. The ReadPixels and WritePixels routines can read/write and entire image, or a single pixel, or anything in between. The run length encoding routines can only handle complete scanlines, but can handle single scanlines. No checking is done to see that an image contains the correct number of pixels. The return codes for routines are defined by RGBE_RETURN_SUCCESS and RGBE_RETURN_FAILURE and these can be modified to be compatible with whatever error convention you are using. Error reporting is handled by the rgbe_error routine. You can easily modify this if you want errors to be reported somewhere other than STDERR. /* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE. * WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY, * IT IS STRICTLY USE AT YOUR OWN RISK. */

************************************

rgbe.h--header file

#ifndef _H_RGBE
#define _H_RGBE
/* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE.
* WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY,
* IT IS STRICTLY USE AT YOUR OWN RISK. */

/* utility for reading and writing Ward's rgbe image format.
See rgbe.txt file for more details.
*/

#include

typedef struct {
int valid; /* indicate which fields are valid */
char programtype[16]; /* listed at beginning of file to identify it
* after "#?". defaults to "RGBE" */
float gamma; /* image has already been gamma corrected with
* given gamma. defaults to 1.0 (no correction) */
float exposure; /* a value of 1.0 in an image corresponds to
* watts/steradian/m^2.
* defaults to 1.0 */
} rgbe_header_info;

/* flags indicating which fields in an rgbe_header_info are valid */
#define RGBE_VALID_PROGRAMTYPE 0x01
#define RGBE_VALID_GAMMA 0x02
#define RGBE_VALID_EXPOSURE 0x04

/* return codes for rgbe routines */
#define RGBE_RETURN_SUCCESS 0
#define RGBE_RETURN_FAILURE -1

/* read or write headers */
/* you may set rgbe_header_info to null if you want to */
int RGBE_WriteHeader(FILE *fp, int width, int height, rgbe_header_info *info);
int RGBE_ReadHeader(FILE *fp, int *width, int *height, rgbe_header_info *info);

/* read or write pixels */
/* can read or write pixels in chunks of any size including single pixels*/
int RGBE_WritePixels(FILE *fp, float *data, int numpixels);
int RGBE_ReadPixels(FILE *fp, float *data, int numpixels);

/* read or write run length encoded files */
/* must be called to read or write whole scanlines */
int RGBE_WritePixels_RLE(FILE *fp, float *data, int scanline_width,
int num_scanlines);
int RGBE_ReadPixels_RLE(FILE *fp, float *data, int scanline_width,
int num_scanlines);

#endif /* _H_RGBE */

************************************

rgbe.c -- C code

/* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE.
* WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY,
* IT IS STRICTLY USE AT YOUR OWN RISK. */

#include "rgbe.h"
#include
#include
#include
#include

/* This file contains code to read and write four byte rgbe file format
developed by Greg Ward. It handles the conversions between rgbe and
pixels consisting of floats. The data is assumed to be an array of floats.
By default there are three floats per pixel in the order red, green, blue.
(RGBE_DATA_??? values control this.) Only the mimimal header reading and
writing is implemented. Each routine does error checking and will return
a status value as defined below. This code is intended as a skeleton so
feel free to modify it to suit your needs.

(Place notice here if you modified the code.)
posted to http://www.graphics.cornell.edu/~bjw/
written by Bruce Walter (bjw@graphics.cornell.edu) 5/26/95
based on code written by Greg Ward
*/

#ifdef _CPLUSPLUS
/* define if your compiler understands inline commands */
#define INLINE inline
#else
#define INLINE
#endif

/* offsets to red, green, and blue components in a data (float) pixel */
#define RGBE_DATA_RED 0
#define RGBE_DATA_GREEN 1
#define RGBE_DATA_BLUE 2
/* number of floats per pixel */
#define RGBE_DATA_SIZE 3

enum rgbe_error_codes {
rgbe_read_error,
rgbe_write_error,
rgbe_format_error,
rgbe_memory_error,
};

/* default error routine. change this to change error handling */
static int rgbe_error(int rgbe_error_code, char *msg)
{
switch (rgbe_error_code) {
case rgbe_read_error:
perror("RGBE read error");
break;
case rgbe_write_error:
perror("RGBE write error");
break;
case rgbe_format_error:
fprintf(stderr,"RGBE bad file format: %s\n",msg);
break;
default:
case rgbe_memory_error:
fprintf(stderr,"RGBE error: %s\n",msg);
}
return RGBE_RETURN_FAILURE;
}

/* standard conversion from float pixels to rgbe pixels */
/* note: you can remove the "inline"s if your compiler complains about it */
static INLINE void
float2rgbe(unsigned char rgbe[4], float red, float green, float blue)
{
float v;
int e;

v = red;
if (green > v) v = green;
if (blue > v) v = blue;
if (v < 1e-32) {
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
}
else {
v = frexp(v,&e) * 256.0/v;
rgbe[0] = (unsigned char) (red * v);
rgbe[1] = (unsigned char) (green * v);
rgbe[2] = (unsigned char) (blue * v);
rgbe[3] = (unsigned char) (e + 128);
}
}

/* standard conversion from rgbe to float pixels */
/* note: Ward uses ldexp(col+0.5,exp-(128+8)). However we wanted pixels */
/* in the range [0,1] to map back into the range [0,1]. */
static INLINE void
rgbe2float(float *red, float *green, float *blue, unsigned char rgbe[4])
{
float f;

if (rgbe[3]) { /*nonzero pixel*/
f = ldexp(1.0,rgbe[3]-(int)(128+8));
*red = rgbe[0] * f;
*green = rgbe[1] * f;
*blue = rgbe[2] * f;
}
else
*red = *green = *blue = 0.0;
}

/* default minimal header. modify if you want more information in header */
int RGBE_WriteHeader(FILE *fp, int width, int height, rgbe_header_info *info)
{
char *programtype = "RGBE";

if (info && (info->valid & RGBE_VALID_PROGRAMTYPE))
programtype = info->programtype;
if (fprintf(fp,"#?%s\n",programtype) < 0)
return rgbe_error(rgbe_write_error,NULL);
/* The #? is to identify file type, the programtype is optional. */
if (info && (info->valid & RGBE_VALID_GAMMA)) {
if (fprintf(fp,"GAMMA=%g\n",info->gamma) < 0)
return rgbe_error(rgbe_write_error,NULL);
}
if (info && (info->valid & RGBE_VALID_EXPOSURE)) {
if (fprintf(fp,"EXPOSURE=%g\n",info->exposure) < 0)
return rgbe_error(rgbe_write_error,NULL);
}
if (fprintf(fp,"FORMAT=32-bit_rle_rgbe\n\n") < 0)
return rgbe_error(rgbe_write_error,NULL);
if (fprintf(fp, "-Y %d +X %d\n", height, width) < 0)
return rgbe_error(rgbe_write_error,NULL);
return RGBE_RETURN_SUCCESS;
}

/* minimal header reading. modify if you want to parse more information */
int RGBE_ReadHeader(FILE *fp, int *width, int *height, rgbe_header_info *info)
{
char buf[128];
int found_format;
float tempf;
int i;

found_format = 0;
if (info) {
info->valid = 0;
info->programtype[0] = 0;
info->gamma = info->exposure = 1.0;
}
if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == NULL)
return rgbe_error(rgbe_read_error,NULL);
if ((buf[0] != '#')||(buf[1] != '?')) {
/* if you want to require the magic token then uncomment the next line */
/*return rgbe_error(rgbe_format_error,"bad initial token"); */
}
else if (info) {
info->valid |= RGBE_VALID_PROGRAMTYPE;
for(i=0;iprogramtype)-1;i++) {
if ((buf[i+2] == 0) || isspace(buf[i+2]))
break;
info->programtype[i] = buf[i+2];
}
info->programtype[i] = 0;
if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
return rgbe_error(rgbe_read_error,NULL);
}
for(;;) {
if ((buf[0] == 0)||(buf[0] == '\n'))
return rgbe_error(rgbe_format_error,"no FORMAT specifier found");
else if (strcmp(buf,"FORMAT=32-bit_rle_rgbe\n") == 0)
break; /* format found so break out of loop */
else if (info && (sscanf(buf,"GAMMA=%g",&tempf) == 1)) {
info->gamma = tempf;
info->valid |= RGBE_VALID_GAMMA;
}
else if (info && (sscanf(buf,"EXPOSURE=%g",&tempf) == 1)) {
info->exposure = tempf;
info->valid |= RGBE_VALID_EXPOSURE;
}
if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
return rgbe_error(rgbe_read_error,NULL);
}
if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
return rgbe_error(rgbe_read_error,NULL);
if (strcmp(buf,"\n") != 0)
return rgbe_error(rgbe_format_error,
"missing blank line after FORMAT specifier");
if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
return rgbe_error(rgbe_read_error,NULL);
if (sscanf(buf,"-Y %d +X %d",height,width) < 2)
return rgbe_error(rgbe_format_error,"missing image size specifier");
return RGBE_RETURN_SUCCESS;
}

/* simple write routine that does not use run length encoding */
/* These routines can be made faster by allocating a larger buffer and
fread-ing and fwrite-ing the data in larger chunks */
int RGBE_WritePixels(FILE *fp, float *data, int numpixels)
{
unsigned char rgbe[4];

while (numpixels-- > 0) {
float2rgbe(rgbe,data[RGBE_DATA_RED],
data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
data += RGBE_DATA_SIZE;
if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
return rgbe_error(rgbe_write_error,NULL);
}
return RGBE_RETURN_SUCCESS;
}

/* simple read routine. will not correctly handle run length encoding */
int RGBE_ReadPixels(FILE *fp, float *data, int numpixels)
{
unsigned char rgbe[4];

while(numpixels-- > 0) {
if (fread(rgbe, sizeof(rgbe), 1, fp) < 1)
return rgbe_error(rgbe_read_error,NULL);
rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],
&data[RGBE_DATA_BLUE],rgbe);
data += RGBE_DATA_SIZE;
}
return RGBE_RETURN_SUCCESS;
}

/* The code below is only needed for the run-length encoded files. */
/* Run length encoding adds considerable complexity but does */
/* save some space. For each scanline, each channel (r,g,b,e) is */
/* encoded separately for better compression. */

static int RGBE_WriteBytes_RLE(FILE *fp, unsigned char *data, int numbytes)
{
#define MINRUNLENGTH 4
int cur, beg_run, run_count, old_run_count, nonrun_count;
unsigned char buf[2];

cur = 0;
while(cur < numbytes) {
beg_run = cur;
/* find next run of length at least 4 if one exists */
run_count = old_run_count = 0;
while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) {
beg_run += run_count;
old_run_count = run_count;
run_count = 1;
while( (beg_run + run_count < numbytes) && (run_count < 127)
&& (data[beg_run] == data[beg_run + run_count]))
run_count++;
}
/* if data before next big run is a short run then write it as such */
if ((old_run_count > 1)&&(old_run_count == beg_run - cur)) {
buf[0] = 128 + old_run_count; /*write short run*/
buf[1] = data[cur];
if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1)
return rgbe_error(rgbe_write_error,NULL);
cur = beg_run;
}
/* write out bytes until we reach the start of the next run */
while(cur < beg_run) {
nonrun_count = beg_run - cur;
if (nonrun_count > 128)
nonrun_count = 128;
buf[0] = nonrun_count;
if (fwrite(buf,sizeof(buf[0]),1,fp) < 1)
return rgbe_error(rgbe_write_error,NULL);
if (fwrite(&data[cur],sizeof(data[0])*nonrun_count,1,fp) < 1)
return rgbe_error(rgbe_write_error,NULL);
cur += nonrun_count;
}
/* write out next run if one was found */
if (run_count >= MINRUNLENGTH) {
buf[0] = 128 + run_count;
buf[1] = data[beg_run];
if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1)
return rgbe_error(rgbe_write_error,NULL);
cur += run_count;
}
}
return RGBE_RETURN_SUCCESS;
#undef MINRUNLENGTH
}

int RGBE_WritePixels_RLE(FILE *fp, float *data, int scanline_width,
int num_scanlines)
{
unsigned char rgbe[4];
unsigned char *buffer;
int i, err;

if ((scanline_width < 8)||(scanline_width > 0x7fff))
/* run length encoding is not allowed so write flat*/
return RGBE_WritePixels(fp,data,scanline_width*num_scanlines);
buffer = (unsigned char *)malloc(sizeof(unsigned char)*4*scanline_width);
if (buffer == NULL)
/* no buffer space so write flat */
return RGBE_WritePixels(fp,data,scanline_width*num_scanlines);
while(num_scanlines-- > 0) {
rgbe[0] = 2;
rgbe[1] = 2;
rgbe[2] = scanline_width >> 8;
rgbe[3] = scanline_width & 0xFF;
if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1) {
free(buffer);
return rgbe_error(rgbe_write_error,NULL);
}
for(i=0;i float2rgbe(rgbe,data[RGBE_DATA_RED],
data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
buffer[i] = rgbe[0];
buffer[i+scanline_width] = rgbe[1];
buffer[i+2*scanline_width] = rgbe[2];
buffer[i+3*scanline_width] = rgbe[3];
data += RGBE_DATA_SIZE;
}
/* write out each of the four channels separately run length encoded */
/* first red, then green, then blue, then exponent */
for(i=0;i<4;i++) {
if ((err = RGBE_WriteBytes_RLE(fp,&buffer[i*scanline_width],
scanline_width)) != RGBE_RETURN_SUCCESS) {
free(buffer);
return err;
}
}
}
free(buffer);
return RGBE_RETURN_SUCCESS;
}

int RGBE_ReadPixels_RLE(FILE *fp, float *data, int scanline_width,
int num_scanlines)
{
unsigned char rgbe[4], *scanline_buffer, *ptr, *ptr_end;
int i, count;
unsigned char buf[2];

if ((scanline_width < 8)||(scanline_width > 0x7fff))
/* run length encoding is not allowed so read flat*/
return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines);
scanline_buffer = NULL;
/* read in each successive scanline */
while(num_scanlines > 0) {
if (fread(rgbe,sizeof(rgbe),1,fp) < 1) {
free(scanline_buffer);
return rgbe_error(rgbe_read_error,NULL);
}
if ((rgbe[0] != 2)||(rgbe[1] != 2)||(rgbe[2] & 0x80)) {
/* this file is not run length encoded */
rgbe2float(&data[0],&data[1],&data[2],rgbe);
data += RGBE_DATA_SIZE;
free(scanline_buffer);
return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines-1);
}
if ((((int)rgbe[2])<<8 | rgbe[3]) != scanline_width) {
free(scanline_buffer);
return rgbe_error(rgbe_format_error,"wrong scanline width");
}
if (scanline_buffer == NULL)
scanline_buffer = (unsigned char *)
malloc(sizeof(unsigned char)*4*scanline_width);
if (scanline_buffer == NULL)
return rgbe_error(rgbe_memory_error,"unable to allocate buffer space");

ptr = &scanline_buffer[0];
/* read each of the four channels for the scanline into the buffer */
for(i=0;i<4;i++) {
ptr_end = &scanline_buffer[(i+1)*scanline_width];
while(ptr < ptr_end) {
if (fread(buf,sizeof(buf[0])*2,1,fp) < 1) {
free(scanline_buffer);
return rgbe_error(rgbe_read_error,NULL);
}
if (buf[0] > 128) {
/* a run of the same value */
count = buf[0]-128;
if ((count == 0)||(count > ptr_end - ptr)) {
free(scanline_buffer);
return rgbe_error(rgbe_format_error,"bad scanline data");
}
while(count-- > 0)
*ptr++ = buf[1];
}
else {
/* a non-run */
count = buf[0];
if ((count == 0)||(count > ptr_end - ptr)) {
free(scanline_buffer);
return rgbe_error(rgbe_format_error,"bad scanline data");
}
*ptr++ = buf[1];
if (--count > 0) {
if (fread(ptr,sizeof(*ptr)*count,1,fp) < 1) {
free(scanline_buffer);
return rgbe_error(rgbe_read_error,NULL);
}
ptr += count;
}
}
}
}
/* now convert data from buffer into floats */
for(i=0;i rgbe[0] = scanline_buffer[i];
rgbe[1] = scanline_buffer[i+scanline_width];
rgbe[2] = scanline_buffer[i+2*scanline_width];
rgbe[3] = scanline_buffer[i+3*scanline_width];
rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],
&data[RGBE_DATA_BLUE],rgbe);
data += RGBE_DATA_SIZE;
}
num_scanlines--;
}
free(scanline_buffer);
return RGBE_RETURN_SUCCESS;
}

************************************

2007年5月9日星期三

Lesson13 nehe

Lesson 13 Bitmap Fonts

#include // Header File For Variable Argument Routines ( ADD )
the stdarg.h header file to parse the text and convert variables to text

You can play around with this value if you want. Make the font wide, etc.
0, // Width Of Font

FW_DONTCARE is 0, FW_NORMAL is 400, FW_BOLD is 700 and FW_BLACK is 900.


Not much to say about this, just leave it set to default.

Bitmap fonts work better when you use an ortho projection rather than a perspective projection, but ortho looks bad,

so to make it work in projection, translate.


If you tranlate 10 units into the screen, you place the text from -5 to +5. It just gives you more control instead

of using decimal places to position the text at exact locations.Nothing will change the size of the text. Not even

glScalef(x,y,z).

2007年5月6日星期日

坐标变换














坐标变换
视图造型变换
视图造型变换过程就是一个将顶点坐标从世界坐标系变换到视觉坐标系的过程。这里很重要的是对两个坐标系的认识。
世界坐标系,也称为全局坐标系。它是一个右手坐标系,可以认为该坐标系是固定不变的,在初始态下,其x轴为沿屏幕水平向右,y轴为沿屏幕垂直向上,z轴则为垂直屏幕面向外指向用户,当然,如果在程序中对视点进行了转换,就不能再认为是这样的了。
视觉坐标系,也称为局部坐标系。它是一个左手坐标系,该坐标系是可以活动的。在初始态下,其原点及x,y 轴分别与世界坐标系的原点及x,y 轴重合,而z 轴则正好相反,即为垂直屏幕面向内。
• 变换的顺序

先旋转后平移 先平移后旋转






图5-1-9 几何变换的顺序
当执行变换A和B时,如果按不同顺序执行时,结果往往会大不相同。例如变换A为旋转45度角,变换B为向x轴方向移动一个距离,不同的执行顺序产生不同的结果。
考察下面利用三个变换绘制顶点的代码:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(N); /* apply transformation N */
glMultMatrixf(M); /* apply transformation M */
glMultMatrixf(L); /* apply transformation L */
glBegin(GL_POINTS);
glVertex3f(v); /* draw transformed vertex v */
glEnd();
在这个过程中,GL_MODELVIEW状态相继引入了I(单位阵)、N、M、L矩阵。变换后的顶点为NMLv。因此,顶点的变换为N(M(Lv)),即是先作变换L,然后是变换M,最后才是N。这里,顶点v的实际变换顺序正好与指定的顺序相反。
• 造型变换
造型变换有三个基本的OpenGL命令:
glTranslate*() 平移
glRotate*() 旋转
glScale*() 缩放
OpenGL自动计算这三个命令的平移、旋转和缩放矩阵,这些命令的作用等价于调用glMultMatrix*(),参数设置为相应的矩阵。但前者比后者计算要快。
void glTranslate*(TYPE x,TYPE y,TYPE z);
该函数以平移矩阵乘当前矩阵。
x,y,z 指定沿世界坐标系x、y、z轴的平移量。
void glRotate*(TYPE angle,TYPE x,TYPE y,TYPE z);
该函数以旋转矩阵乘当前矩阵,其中:
angle 指定旋转的角度(以度为单位)。
x,y,z 指定旋转轴向量的三个分量(该向量位于世界坐标系中)。
void glScale*(TYPE x,TYPE y,TYPE z);
该函数以缩放矩阵乘当前矩阵,x、y、z 指定沿x、y和z轴的比例因子。
• 视图变换
视图变换改变视点的位置和方向,也就是改变视觉坐标系。在世界坐标系中,视点和物体的位置是一个相对的关系,对物体作一些平移、旋转变换,必定可以通过对视点作相应的平移、旋转变换来达到相同的视觉效果。完成视图变换可以有以下几种方法:
(1).利用一个或几个造型变换命令(即glTranslate*()和glRotate*())。由于这些命令也是在GL_MODELVIEW状态下执行的,所以较难和那些造型变换命令区分开来,移动视点的变换和移动物体的变换很容易混淆。为了便于建立清晰的物体和场景模型,可以认为只有其中一个变换在起作用,比如认为只有模型变换的话,那么glTranslate*()和glRotate*()将统一被视为对物体的变换。
(2).利用实用库函数gluLookAt()设置视觉坐标系。在实际的编程应用中,用户在完成场景的建模后,往往需要选择一个合适的视角或者不停地变换视角,以对场景作观察。实用库函数gluLookAt()就提供了这样的一个功能。
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,
GLdouble centerx,GLdouble centery,GLdouble centerz,
GLdouble upx,GLdouble upy,GLdouble upz);
该函数定义一个视图矩阵,并与当前矩阵相乘。
eyex, eyey,eyez 指定视点的位置
centerx,centery,centerz 指定参考点的位置
upx,upy,upz 指定视点向上的方向








图5-1-10 函数gluLookAt()的设置
视点E、参考点C、视点向上的方向U实际上就是设定了一个视觉坐标系。这个视觉坐标系的原点是E,视线的方向(即z轴)是C-U,y轴方向就是视点向上的方向U,剩下的x轴方向就是向量((C-E)*U)。由于y轴和x轴是垂直的,所以也要求向量(C-U)和U互相垂直。这点在设置该函数参数时是必须注意的。
(3).创建封装旋转和平移命令的实用函数。有些应用需要用简便方法指定视图变换的定制函数。例如,在飞机飞行中指定滚动、俯仰和航向旋转角,或对环绕对象运动的照相机指定一种利用极坐标的变换。