晚上看到大牛http://fabiensanglard.net/ 的好早的文章将Tunnel Effect的,觉得挺好看,根据他给的算法,自己实现了opengl版,读BMP函数直接网上摘得
他给的链接里面有Tunnel Effect的详细原理 http://lodev.org/cgtutor/tunnel.html
/*
=========================================
参考:
http://lodev.org/cgtutor/tunnel.html
http://fabiensanglard.net/Tunnel/index.php
=========================================
*/
#include <cstdio>
#include <cmath>
#include <gl/glut.h>
#pragma comment(lib, "glut32.lib")
typedef struct BMPImage {
int width, height;
unsigned char *data;
void ReleaseRes() {
delete [] data;
}
}BmpImage;
bool loadBMP_custom(const char *imagepath, BMPImage &bmpData) {
printf("Reading image %s\n", imagepath);
// Data read from the header of the BMP file
unsigned char header[54];
unsigned int dataPos;
unsigned int imageSize;
unsigned int width, height;
unsigned char *data;
// Open the file
FILE * file = fopen(imagepath,"rb");
if (!file) {
printf("%s could not be opened. Are you in the right directory ? Don't forget to read the FAQ !\n", imagepath);
return false;
}
// Read the header, i.e. the 54 first bytes
// If less than 54 byes are read, problem
if (fread(header, 1, 54, file)!=54){
printf("Not a correct BMP file\n");
return 0;
}
// A BMP files always begins with "BM"
if (header[0]!='B' || header[1]!='M'){
printf("Not a correct BMP file\n");
return 0;
}
// Make sure this is a 24bpp file
if ( *(int*)&(header[0x1E])!=0 ) {printf("Not a correct BMP file\n"); return 0;}
if ( *(int*)&(header[0x1C])!=24 ) {printf("Not a correct BMP file\n"); return 0;}
// Read the information about the image
dataPos = *(int*)&(header[0x0A]);
imageSize = *(int*)&(header[0x22]);
width = *(int*)&(header[0x12]);
height = *(int*)&(header[0x16]);
// Some BMP files are misformatted, guess missing information
if (imageSize==0) imageSize=width*height*3; // 3 : one byte for each Red, Green and Blue component
if (dataPos==0) dataPos=54; // The BMP header is done that way
// Create a buffer
data = new unsigned char [imageSize];
// Read the actual data from the file into the buffer
fread(data,1,imageSize,file);
bmpData.data = data;
bmpData.width = width;
bmpData.height = height;
// Everything is in memory now, the file wan be closed
fclose (file);
return true;
}
#define screenWidth 400
#define screenHeight 400
static BMPImage bmpImage;
int distanceTable[screenWidth][screenHeight];
int angleTable[screenWidth][screenHeight];
unsigned char dynamicTex[screenWidth][screenHeight][3];
static float animation;
void init() {
glClearColor(0.0f,0.0f,0.0f,1.0f);
glShadeModel(GL_SMOOTH);
loadBMP_custom("./tex99.bmp", bmpImage);
//generate non-linear transformation table
for(int x = 0; x < screenWidth; x++)
for(int y = 0; y < screenHeight; y++)
{
int angle, distance;
float ratio = 32.0;
distance = int(ratio * bmpImage.height / sqrt((x - screenWidth / 2.0) * (x - screenWidth / 2.0)
+ (y - screenHeight / 2.0) * (y - screenHeight / 2.0))) % bmpImage.height;
angle = (unsigned int)(0.5 * bmpImage.width * atan2(y - screenHeight / 2.0, x - screenWidth / 2.0) / 3.1416);
distanceTable[x][y] = distance;
angleTable[x][y] = angle;
}
}
void reshape(int w, int h) {
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,0,1,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void calculate() {
animation = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
//calculate the shift values out of the animation value
int shiftX = int(bmpImage.width * 1.0 * animation);
int shiftY = int(bmpImage.height * 0.25 * animation);
for(int x = 0; x < screenWidth; x++)
for(int y = 0; y < screenHeight; y++)
{
//get the texel from the texture by using the tables, shifted with the animation values
unsigned char *pBmpData = bmpImage.data;
unsigned char r = pBmpData[(unsigned int)(distanceTable[x][y] + shiftX) % bmpImage.width *3
+ (unsigned int)(angleTable[x][y] + shiftY) % bmpImage.height * bmpImage.width * 3];
unsigned char g = pBmpData[(unsigned int)(distanceTable[x][y] + shiftX) % bmpImage.width *3
+ (unsigned int)(angleTable[x][y] + shiftY) % bmpImage.height * bmpImage.width * 3 + 1];
unsigned char b = pBmpData[(unsigned int)(distanceTable[x][y] + shiftX) % bmpImage.width *3
+ (unsigned int)(angleTable[x][y] + shiftY) % bmpImage.height * bmpImage.width * 3 + 2];
dynamicTex[x][y][0] = r;
dynamicTex[x][y][1] = g;
dynamicTex[x][y][2] = b;
}
}
void display() {
calculate();
glDrawPixels(screenWidth, screenHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, dynamicTex);
glutSwapBuffers();
glutPostRedisplay();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(screenWidth,screenHeight);
glutInitWindowPosition(200,200);
glutCreateWindow("Tunnel Effect");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
bmpImage.ReleaseRes();
return 0;
}