【游戏课】技术片段之——使用BillBoard技术进行快速绘制
来源:互联网 发布:ug nx11编程新功能 编辑:程序博客网 时间:2024/06/18 08:01
BillBoard技术是计算机图形学领域中进行快速绘制的一种方法。在类似游戏这种对实时性要求较高的场景下采取BillBoard技术可以大大加快绘制的速度从而提高画面的流畅性。
那么什么是BillBoard技术,BillBoard技术的原理是什么呢?
“BillBoard技术采用一个带有纹理的四边形,其纹理图像为该BillBoard所代表的物体的图像,即用带有该物体图像的长方形,代替生成该物体的图形画面。BillBoard放置于所代表物体的位置中心,并随相机的运动而变化,始终面对用户。将BillBoard技术与Alpha纹理和动画技术相结合,可以模拟很多自然现象,如树、烟、火、爆炸、云等。”——《计算机游戏程序设计》
简单地说,就是把3D的物体用2D来表示,然后让该物体始终朝向镜头。比如场景中的一棵树,对于整个场景来说不是主要物体,因此无需花费大量的时间去计算树的每一部分的细节。通常的做法是首先准备好一张树的照片,然后镜头运动的时候使得树始终正对着镜头,我们看到的始终是树的正面。
BillBoard四边形法向和向上向量的设置方式对应着不同的BillBoard技术,分为平行屏幕的BillBoard技术、平行物体的BillBoard技术、视点朝向的BillBoard技术和轴向BillBoard技术。下面实现的是平行屏幕的BillBoard技术。
采用OpenGL实现的思路是,在绘制树的时候将ModelView矩阵的左上角的3*3矩阵置为单位阵。
核心代码:
float mat[16]; glGetFloatv(GL_MODELVIEW_MATRIX, mat); // Identify the 3*3 sub matrix in Top-left corner mat[1] = mat[2] = mat[6] = 0; mat[4] = mat[8] = mat[9] = 0; mat[0] = mat[5] = mat[10] = 1; glLoadMatrixf(mat);
为了演示BillBoard技术,我们假设场景有一个茶壶和一棵树(好怪异的搭配)。达到的效果应该是视点转动时茶壶不动,树始终跟人的视线垂直。
在OpenGL中当视点发生变化时,实际上我们的视线是不动的,始终朝向电脑屏幕,而场景在做相对运动。所以实际上绘制出的效果应该是树始终处于画面中朝向保持不变,茶壶会发生转动。
场景一:
场景二(视点变化):
项目的代码如下:
控制:WSAD控制视点上下左右移动,ZC控制视点前后移动。
#define GLUT_DISABLE_ATEXIT_HACK#define _CRT_SECURE_NO_WARNINGS#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <gl/glut.h>#include <gl/glext.h>#define BITMAP_ID 0x4D42//about multitexturePFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB = NULL;PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL;PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL;//texture identifiersstatic GLuint texture[1];//for scene movementGLfloat fRotate;//whether perspective or orthographicbool bPersp = true;//whether to animatebool bAnim = false;//whether wire or solidbool bWire = false;//whether to combine texure and lighteningbool bTexLit = false;//view port sizeint wHeight = 512;int wWidth = 512;unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader){ FILE *filePtr; BITMAPFILEHEADER bitmapFileHeader; unsigned char *bitmapImage; intimageIdx = 0; unsigned char tempRGB; filePtr = fopen(filename, "rb"); if (filePtr == NULL) return NULL; fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr); if (bitmapFileHeader.bfType != BITMAP_ID) { fprintf(stderr, "Error in LoadBitmapFile: the file is not a bitmap file\n"); return NULL; } fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr); fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET); bitmapImage = new unsigned char[bitmapInfoHeader->biSizeImage]; if (!bitmapImage) { fprintf(stderr, "Error in LoadBitmapFile: memory error\n"); return NULL; } fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr); if (bitmapImage == NULL) { fprintf(stderr, "Error in LoadBitmapFile: memory error\n"); return NULL; } for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3) { tempRGB = bitmapImage[imageIdx]; bitmapImage[imageIdx] = bitmapImage[imageIdx + 2]; bitmapImage[imageIdx + 2] = tempRGB; } fclose(filePtr); return bitmapImage;}void TextLoad(int i, char *filename){ BITMAPINFOHEADER bitmapInfoHeader; unsigned char* bitmapData; bitmapData = LoadBitmapFile(filename, &bitmapInfoHeader); glBindTexture(GL_TEXTURE_2D, texture[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);}void Init(){ glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); // initialize OpenGL lighting GLfloat lightPos[] = { 0.0, 0.0, 1.0, 1 }; GLfloat lightAmb[4] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat lightDiff[4] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat lightSpec[4] = { 1.0, 1.0, 1.0, 1.0 }; //glLightfv(GL_LIGHT0, GL_POSITION, lightPos); glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb); glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiff); glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpec); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, lightPos); glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SEPARATE_SPECULAR_COLOR_EXT); GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 }; //glLightModelfv(GL_LIGHT_MODEL_AMBIENT, black); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1, texture); TextLoad(0, "tree.bmp"); //define multitexture glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC)wglGetProcAddress("glMultiTexCoord1fARB"); glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)wglGetProcAddress("glMultiTexCoord2fARB"); glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB"); glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)wglGetProcAddress("glClientActiveTextureARB");}void Draw_Teapot(){ glPushMatrix(); glTranslatef(0, -1.5, 0); glutSolidTeapot(0.5); glPopMatrix();}void Draw_Tree(){ glPushMatrix(); float mat[16]; glGetFloatv(GL_MODELVIEW_MATRIX, mat); // Identify the 3*3 sub matrix in Top-left corner mat[1] = mat[2] = mat[6] = 0; mat[4] = mat[8] = mat[9] = 0; mat[0] = mat[5] = mat[10] = 1; glLoadMatrixf(mat); //choose texture glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture[0]); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE); //top glBegin(GL_QUADS); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1, 0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1, 1); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 1); //bottom glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1, 1); glVertex3f(2, 2, 0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1, 0); glVertex3f(2, -2, 0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 0); glVertex3f(-2, -2, 0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 1); glVertex3f(-2, 2, 0); glEnd(); glTranslatef(0, 0, 0); glActiveTextureARB(GL_TEXTURE0_ARB); glDisable(GL_TEXTURE_2D); glPopMatrix();}void DrawScene(){ Draw_Teapot(); Draw_Tree();}void updateView(int width, int height){ // Reset The Current View port glViewport(0, 0, (GLsizei)width, (GLsizei)height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); float whRatio = (GLfloat)width / (GLfloat)height; if (bPersp) { gluPerspective(45.0f, whRatio, 0.1f, 100.0f); } else { glOrtho(-3, 3, -3, 3, -100, 100); } glMatrixMode(GL_MODELVIEW);}void reshape(int width, int height){ if (height == 0) { height = 1; } wHeight = height; wWidth = width; updateView(wHeight, wWidth);}void idle(){ glutPostRedisplay();}//eye positionGLdouble eye[] = { 0, 0, 8 };//where it is aimedGLdouble center[] = { 0, 0, 0 };void key(unsigned char k, int x, int y){ switch (k) { case 27: case 'q': {exit(0); break; } case 'p': {bPersp = !bPersp; break; } case ' ': {bAnim = !bAnim; break; } case 'o': {bWire = !bWire; break; } case 'a': { eye[0] += 0.2f; //center[0] += 0.2f; break; } case 'd': { eye[0] -= 0.2f; //center[0] -= 0.2f; break; } case 'w': { eye[1] -= 0.2f; //center[1] -= 0.2f; break; } case 's': { eye[1] += 0.2f; //center[1] += 0.2f; break; } case 'z': { eye[2] -= 0.2f; center[2] -= 0.2f; break; } case 'c': { eye[2] += 0.2f; center[2] += 0.2f; break; } case 'l':{ bTexLit = !bTexLit; break; } } updateView(wHeight, wWidth);}void begin_window_coords(){ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, wWidth, 0.0, wHeight, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}void end_window_coords(){ glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW);}void display(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // gradient background glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); begin_window_coords(); glBegin(GL_QUADS); glColor3f(0.2, 0.4, 0.8); glVertex2f(0.0, 0.0); glVertex2f(wWidth, 0.0); glColor3f(0.05, 0.1, 0.2); glVertex2f(wWidth, wHeight); glVertex2f(0, wHeight); glEnd(); end_window_coords(); glLoadIdentity(); gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0); if (bWire) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } else { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glPushMatrix(); glRotatef(fRotate, 0, 1, 0); DrawScene(); glPopMatrix(); if (bAnim){ fRotate += 0.5f; } glutSwapBuffers();}int main(int argc, char *argv[]){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); glutInitWindowPosition(400, 200); glutInitWindowSize(512, 512); glutCreateWindow("BillBoard Illustration"); Init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(key); glutIdleFunc(idle); glutMainLoop(); return 0;}
- 【游戏课】技术片段之——使用BillBoard技术进行快速绘制
- 【游戏课】技术片段之——BSP树在游戏中的应用
- 【游戏课】技术片段之——三个矩阵相乘的结果
- 【游戏课】技术片段之——四元数与旋转矩阵的关系
- 【游戏课】技术片段之——球面线性插值(SLERP)
- 【游戏课】技术片段之——弹簧质点模型与布料动画
- Billboard技术浅析
- Billboard技术浅析
- 基于移动平台消除冗余GPU绘制片段的技术
- 快速提升游戏开发技术
- 【UI技术分享】游戏技能图标绘制
- billboard技术的XNA实现
- 公告牌技术( Billboard ) - 完
- unity中的Billboard技术实现
- 游戏开发技术——游戏引擎
- 软件,互联网,游戏——我的技术之路
- 游戏中如何进行Python技术
- Android之优化技术 --- 使用layoutopt进行布局优化
- Hibernate乐观锁实现之Version
- wchar和char的转换
- Linux下高并发socket最大连接数所受的各种限制
- MATLAB的plot函数颜色和线型设定参数
- 第六周项目1-体验常成员函数
- 【游戏课】技术片段之——使用BillBoard技术进行快速绘制
- TCP/IP详解--ICMP 控制报文和差错报文 && Tracerouter 命令的过程
- 等待事件--db file sequential read
- C++ 智能指针 shared_ptr unique_ptr weak_ptr
- Android SparseArray指的是稀疏数组(Sparse array)
- 双击BACK键退出程序
- Intent以及IntentFileter大全
- 类加载器---创建并使用自定义的类加载器
- 文件下载