【BumpMap】凹凸贴图绘制简单图形

来源:互联网 发布:双向冒泡排序算法 编辑:程序博客网 时间:2024/04/29 18:19

BumpMap 的主要思想就是通过 (x + dx, y), (x - dx, y), (x, y + dy), (x, y - dy) 这四个点的高度计算出(x, y) 点法向量的改变量:

if (i != XMAX)normal[i][j] = normal[i][j] - (position[i][j] - position[i + 1][j]).Unitization() * (height[i][j] - height[i + 1][j]);if (i != 0)normal[i][j] = normal[i][j] - (position[i][j] - position[i - 1][j]).Unitization() * (height[i][j] - height[i - 1][j]);if (j != YMAX)normal[i][j] = normal[i][j] - (position[i][j] - position[i][j + 1]).Unitization() * (height[i][j] - height[i][j + 1]);if (j != 0)normal[i][j] = normal[i][j] - (position[i][j] - position[i][j - 1]).Unitization() * (height[i][j] - height[i][j - 1]);

在实现过程中我们取 dx, dx 为相邻的格点就可以方便计算啦!其中 Unitization() 是单位化操作。


尝试理解一下第二行的运算,如果 (i + 1, j) 的高度要低于 (i, j),显然 (i, j) 点的法向量应该偏向 (i + 1, j) 的方向。

(position[i][j] - position[i + 1][j]).Unitization()

是从 (i + 1, j) 指向 (i, j) 的单位向量,如果
(height[i][j] - height[i + 1][j])
是一个正值,那么
- (position[i][j] - position[i + 1][j]).Unitization() * (height[i][j] - height[i + 1][j])
就会沿着 (i, j) 到 (i + 1, j) 的方向,也就是normal应有的改变量。


还有一个小难点是建立球体的模型,我选择了使用三角片去贴满球体的表面,这里涉及到了球坐标到直角坐标的变换。

float theta = i * 2.0 * PI / XMAX, fai = j * PI / YMAX;position[i][j].x = 1.0 * sin(fai) * sin(theta);position[i][j].y = 1.0 * cos(fai);position[i][j].z = 1.0 * sin(fai) * cos(theta);
而直角坐标的优点就是,(i, j) 的法线和 (i, j) 的坐标是一致的。

normal[i][j] = position[i][j];

剩下的就是用OpenGL绘制三角形和设置光照属性啦!就很简单~


附完整代码【当然可能有错咯】:

#include <GL/freeglut.h>#include <iostream>#include <iomanip>#include <algorithm>#include <cmath>#include "MyMath.h"using namespace std;const int XINIT = 800, YINIT = 800;const int XMAX = 1600, YMAX = 800;float height[XMAX + 1][YMAX + 1];int XCURR = XINIT, YCURR = YINIT;const int MY_POLYGON = 0, MY_SPHERE = 1;const int MY_MODE = MY_SPHERE;Vector3f position[XMAX + 1][YMAX + 1], normal[XMAX + 1][YMAX + 1];void InitNormal() {for (int i = 0; i <= XMAX; i++)for (int j = 0; j <= YMAX; j++) {if (MY_MODE == MY_POLYGON) {normal[i][j].x = 0.0;normal[i][j].y = 0.0;normal[i][j].z = 1.0;}if (MY_MODE == MY_SPHERE) {normal[i][j] = position[i][j];}if (i != XMAX)normal[i][j] = normal[i][j] - (position[i][j] - position[i + 1][j]).Unitization() * (height[i][j] - height[i + 1][j]);if (i != 0)normal[i][j] = normal[i][j] - (position[i][j] - position[i - 1][j]).Unitization() * (height[i][j] - height[i - 1][j]);if (j != YMAX)normal[i][j] = normal[i][j] - (position[i][j] - position[i][j + 1]).Unitization() * (height[i][j] - height[i][j + 1]);if (j != 0)normal[i][j] = normal[i][j] - (position[i][j] - position[i][j - 1]).Unitization() * (height[i][j] - height[i][j - 1]);normal[i][j].Unitization();}}void RenderScene() {glClearColor(0.0, 0.0, 0.0, 1.0);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glPointSize(10.0f);glLineWidth(1.0f);glPushMatrix();{GLfloat sunLightPosition[] = {1.0f, 1.0f, 1.0f, 0.0f};GLfloat sunLightAmbient[] = {0.6f, 0.6f, 0.6f, 1.0f};GLfloat sunLightDiffuse[] = {0.6f, 0.6f, 0.6f, 1.0f};GLfloat sunLightSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};glLightfv(GL_LIGHT0, GL_POSITION, sunLightPosition);glLightfv(GL_LIGHT0, GL_AMBIENT, sunLightAmbient);   glLightfv(GL_LIGHT0, GL_DIFFUSE, sunLightDiffuse);glLightfv(GL_LIGHT0, GL_SPECULAR, sunLightSpecular);glEnable(GL_LIGHT0);glEnable(GL_LIGHTING);}/*static float rotateTheta = 0.0;glRotated(-23.5, 0.0, 0.0, 1.0);glRotated(rotateTheta, 0.0, 1.0, 0.0);rotateTheta += 1;*/{GLfloat triangleMatAmbient[] = {0.6f, 0.6f, 0.6f, 1.0f};GLfloat triangleMatDiffuse[] = {0.6f, 0.6f, 0.6f, 1.0f};GLfloat triangleMatSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};GLfloat triangleMatEmission[] = {0.1f, 0.1f, 0.3f, 1.0f};GLfloat triangleMatShininess = 100.0f;glMaterialfv(GL_FRONT, GL_AMBIENT, triangleMatAmbient);glMaterialfv(GL_FRONT, GL_DIFFUSE, triangleMatDiffuse);glMaterialfv(GL_FRONT, GL_SPECULAR, triangleMatSpecular);glMaterialfv(GL_FRONT, GL_EMISSION, triangleMatEmission);glMaterialf(GL_FRONT, GL_SHININESS, triangleMatShininess);}glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);glBegin(GL_TRIANGLES);{for (int i = 0; i < XMAX; i++)for (int j = 0; j < YMAX; j++) {glNormal3fv(normal[i][j]());glVertex3fv(position[i][j]());glNormal3fv(normal[i + 1][j]());glVertex3fv(position[i + 1][j]());glNormal3fv(normal[i][j + 1]());glVertex3fv(position[i][j + 1]());}for (int i = 0; i < XMAX; i++)for (int j = 0; j < YMAX; j++) {glNormal3fv(normal[i + 1][j]());glVertex3fv(position[i + 1][j]());glNormal3fv(normal[i + 1][j + 1]());glVertex3fv(position[i + 1][j + 1]());glNormal3fv(normal[i + 1][j + 1]());glVertex3fv(position[i][j + 1]());}}glEnd();glPopMatrix();glutSwapBuffers();}void ReshapeWindow(int w, int h) {glViewport(0, 0, w, h);XCURR = w;YCURR = h;glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(2 * atan(h / (YINIT * 5.0)) / PI * 180, 1.0 * w / h, 0.5, 18);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0f, 1.0f, 0.0);}void MouseMotion(int x, int y) {float xFloat = (x - XCURR * 0.5f) / (YINIT * 0.5);float yFloat = (YCURR * 0.5f - y) / (YINIT * 0.5);if (xFloat < -1.0 || xFloat > 1.0 || yFloat < -1.0 || yFloat > 1.0)return;int xInt = floor((xFloat + 1.0) * 0.5 * XMAX);int yInt = floor((yFloat + 1.0) * 0.5 * YMAX);height[xInt + 0][yInt + 0] = -3;height[xInt + 1][yInt + 0] = -3;height[xInt + 0][yInt + 1] = -3;height[xInt + 1][yInt + 1] = -3;}void MyInit() {for (int i = 0; i <= XMAX; i++)for (int j = 0; j <= YMAX; j++) {{if (i % 80 >= 20 && i % 80 < 60 && j % 80 >= 20 && j % 80 < 60)height[i][j] = 2.0;elseheight[i][j] = 0.0;}if (MY_MODE == MY_POLYGON) {position[i][j].x = i * 2.0 / XMAX - 1.0;position[i][j].y = j * 2.0 / YMAX - 1.0;position[i][j].z = 0.0;}if (MY_MODE == MY_SPHERE) {float theta = i * 2.0 * PI / XMAX, fai = j * PI / YMAX;position[i][j].x = 1.0 * sin(fai) * sin(theta);position[i][j].y = 1.0 * cos(fai);position[i][j].z = 1.0 * sin(fai) * cos(theta);}}InitNormal();}int main(int argc, char** argv) {glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);glutInitWindowPosition(800, 40);glutInitWindowSize(XINIT, YINIT);glutCreateWindow("OpenGL");glEnable(GL_POINT_SMOOTH);glEnable(GL_LINE_SMOOTH);glEnable(GL_DEPTH_TEST);glutDisplayFunc(RenderScene);glutReshapeFunc(ReshapeWindow);//glutIdleFunc(RenderScene);//glutMotionFunc(MouseMotion);MyInit();glutMainLoop();}

这个程序还有一些别的功能哦!


以下是用到的数据结构【其实只有一个】:

#pragma once#include <math.h>#include <iostream>using namespace std;const float PI = 3.1415926f;class Vector3f {public:float x, y, z, *array;Vector3f(float x = 0.0, float y = 0.0, float z = 0.0): x(x), y(y), z(z) {array = new float[3];}Vector3f operator * (const float lambda) {return Vector3f(x * lambda, y * lambda, z * lambda);}Vector3f operator + (const Vector3f & tempVector3f) {return Vector3f(x + tempVector3f.x, y + tempVector3f.y,z + tempVector3f.z);}Vector3f operator - (const Vector3f & tempVector3f) {return Vector3f(x - tempVector3f.x, y - tempVector3f.y,z - tempVector3f.z);}Vector3f operator * (const Vector3f & tempVector3f) {return Vector3f(y * tempVector3f.z - z * tempVector3f.y,z * tempVector3f.x - x * tempVector3f.z,x * tempVector3f.y - y * tempVector3f.x);}Vector3f & operator = (const Vector3f & tempVector3f) {x = tempVector3f.x;y = tempVector3f.y;z = tempVector3f.z;return (*this);}~Vector3f() {delete[] array;}float Modulus() {return sqrt(x * x + y * y + z * z);}Vector3f & Unitization() {float modulus = Modulus();x /= modulus;y /= modulus;z /= modulus;return (*this);}float * operator () () {array[0] = x;array[1] = y;array[2] = z;return array;}friend ostream & operator << (ostream & out, const Vector3f & vec) {return out << vec.x << " " << vec.y << " " << vec.z;}};

0 0
原创粉丝点击