然后是下载glut包,它帮助你使用opengl
复制文末的代码,Ctrl+F5 运行。这个时候应该会比较卡。
如果改变这里的迭代关系可以很多做出其他效果!
不了解代码的就可以就到这里了。
代码的核心就是使用特定方法得到每一个像素点应该的RGB值(先不管如何通过像素点的坐标如何对应转化到RGB值的),然后通过OpenGL的顶点数组功能将每一个点的位置和对应的颜色传入显卡进行渲染得到结果。
这里的特定方法就是Julia集,这个的相关解释可以百度。简单的说就是:
最终就得到了一张分形图了。
然后就是如果让分形图动起来。这里的关系就是:
上面3条的合理运用就可以让分形图动起来!
OpenGL参考资料: http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html
然后是顶点数组:
减少函数的调用次数,是提高运行效率的方法之一。于是我们想到了显示列表。把绘制立方体的代码装到一个显示列表中,以后只要调用这个显示列表即可。
这样看起来很不错,但是显示列表有一个缺点,那就是一旦建立后不可再改。如果我们要绘制的不是立方体,而是一个能够走动的人物,因为人物走动时,四肢的位置不断变化,几乎没有办法把所有的内容装到一个显示列表中。必须每种动作都使用单独的显示列表,这样会导致大量的显示列表管理困难。
顶点数组是解决这个问题的一个方法。使用顶点数组的时候,也是像前面的方法一样,用一个数组保存所有的顶点,用一个数组保存顶点的序号。但最后绘制的时候,不是编写循环语句逐个的指定顶点了,而是通知OpenGL,“保存顶点的数组”和“保存顶点序号的数组”所在的位置,由OpenGL自动的找到顶点,并进行绘制。
这里使用顶点数组管理个人认为是很好的方法。核心就是:
struct col {
GLushort r, g, b;
} colKTable[N];
struct pos {
double x, y, z;
} posArr[HEIGHT * WIDTH];
col colArr[HEIGHT * WIDTH];
int index_list[HEIGHT * WIDTH];
index_list
中。index_list[i * WIDTH + j] = i * WIDTH + j;
,就是直接的0,1,2…posArr
中posArr[i * WIDTH + j].x = -0.5 + (double)i / (HEIGHT); // (-1,1)
posArr[i * WIDTH + j].y = -0.5 + (double)j / (WIDTH); // (1,-1)
posArr[i * WIDTH + j].z = 0.1;
colKTable
中colArr
中有了上面的这些准备工作,剩下的就是逻辑实现了。
#include
#include
#include
#include
static double myratio; // angle绕y轴的旋转角,ratio窗口高宽比
static double x = 0.0f, y = 0.0f, z = 1.3f; //相机位置
static double lx = 0.0f, ly = 0.0f, lz = -1.0f; //视线方向,初始设为沿着Z轴负方向
const int WIDTH = 1000;
const int HEIGHT = 1000;
bool mouseDown = false;
double xrot = 0.0f, yrot = 0.0f;
double xdiff = 0.0f, ydiff = 0.0f;
/**
* 定义观察方式
*/
void changeSize(int w, int h) {
//除以0的情况
if (h == 0) h = 1;
myratio = 1.0f * w / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//设置视口为整个窗口大小
glViewport(0, 0, w, h);
//设置可视空间
gluPerspective(45, myratio, 1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}
/**
* 视野漫游函数
*/
void orientMe(double directionx, double directiony) {
x += directionx * 0.1;
y += directiony * 0.1;
glLoadIdentity();
gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}
/**
* 视野漫游函数
*/
void moveMeFlat(int direction) {
z += direction * (lz) * 0.1;
glLoadIdentity();
gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}
// 鼠标右键stop
bool stop = false;
/**
* 鼠标事件
*/
void mouse(int button, int state, int x, int y) {
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
stop = !stop;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
mouseDown = true;
xdiff = x - yrot;
ydiff = -y + xrot;
}
else
mouseDown = false;
}
/**
* 鼠标移动事件
*/
void mouseMotion(int x, int y) {
if (mouseDown) {
yrot = x - xdiff;
xrot = y + ydiff;
glutPostRedisplay();
}
}
/**
* 加入按键控制
*/
double rateZoom = 1.5f;
const int N = 110, M = 1000;
struct col {
GLushort r, g, b;
} colKTable[N];
struct pos {
double x, y, z;
} posArr[HEIGHT * WIDTH];
col colArr[HEIGHT * WIDTH];
int index_list[HEIGHT * WIDTH];
struct complex {
double i, j;
inline complex mul(complex& b) {
double tempI = i * b.i - j * b.j;
double tempJ = i * b.j + j * b.i;
i = tempI, j = tempJ;
return *this;
}
inline complex add(complex& b) {
i += b.i, j += b.j;
return *this;
}
};
complex alpha{ 0, 0 };
void myDisplay() {
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
// 实现鼠标旋转的核心
glRotatef(xrot, 1.0f, 0.0f, 0.0f);
glRotatef(yrot, 0.0f, 1.0f, 0.0f);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_DOUBLE, sizeof(pos), posArr);
glColorPointer(3, GL_UNSIGNED_SHORT, sizeof(col), colArr);
glDrawElements(GL_POINTS, HEIGHT * WIDTH, GL_UNSIGNED_INT, index_list);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glFlush();
glutSwapBuffers();
}
double CalFrequency() {
static int count;
static double save;
static clock_t last, current;
double timegap;
++count;
if (count <= 50)
return save;
count = 0;
last = current;
current = clock();
timegap = (current - last) / (double)CLK_TCK;
save = 50.0 / timegap;
return save;
}
bool isGo = true;
void myIdle() {
if (stop) return;
double FPS = CalFrequency();
printf("FPS = %f\n", FPS);
double rate = 0.03;
static double ii = -1, jj = -1;
if (isGo) {
static bool flag = true;
if (flag) ii += rate;
else ii -= rate;
if (ii > 1) {
jj += rate;
flag = false;
}
if (ii < -1) {
jj += rate;
flag = true;
}
if (jj == 0) {
ii += rate;
}
}
complex C{ ii, jj };
double d = rateZoom * 2 / HEIGHT;
#pragma omp parallel for
for (int i = 0; i < HEIGHT; i++)
for (int j = 0; j < WIDTH; j++) {
auto& item = colArr[i * WIDTH + j];
item.r = item.g = item.b = 0;
complex X{ -rateZoom + i * d, -rateZoom + j * d }; // (-1.5,1.5)
X = X.add(alpha);
for (auto& k : colKTable) {
X = X.mul(X).add(C);
if (X.i * X.i + X.j * X.j > M) {
item.r = k.r;
item.g = k.g;
item.b = k.b;
break;
}
}
}
myDisplay();
}
void init() {
for (int k = 0; k < N; k++) {
int tempK = k * k;
tempK = tempK * tempK;
colKTable[k].r = tempK + tempK;
colKTable[k].g = exp(k);
colKTable[k].b = tempK * k;
}
for (int i = 0; i < HEIGHT; i++)
for (int j = 0; j < WIDTH; j++) {
posArr[i * WIDTH + j].x = -0.5 + (double)i / (HEIGHT); // (-1,1)
posArr[i * WIDTH + j].y = -0.5 + (double)j / (WIDTH); // (1,-1)
posArr[i * WIDTH + j].z = 0.1;
index_list[i * WIDTH + j] = i * WIDTH + j;
}
glClearColor(0.93f, 0.93f, 0.93f, 0.0f);
}
void processSpecialKeys(int key, int x, int y) {
bool temp;
temp = stop;
stop = false;
isGo = false;
// 越近加的越慢
double addRate = 0.1 * std::abs(std::exp(rateZoom) - 1);
switch (key) {
case GLUT_KEY_UP:
// orientMe(0, 1);
alpha.j += addRate;
break;
case GLUT_KEY_DOWN:
// orientMe(0, -1);
alpha.j -= addRate;
break;
case GLUT_KEY_LEFT:
// orientMe(-1, 0);
alpha.i -= addRate;
break;
case GLUT_KEY_RIGHT:
// orientMe(1, 0);
alpha.i += addRate;
break;
case GLUT_KEY_PAGE_DOWN:
// moveMeFlat(-1);
rateZoom = (rateZoom + addRate) > 2 ? 2 : rateZoom + addRate;
break;
case GLUT_KEY_PAGE_UP:
// moveMeFlat(1);
rateZoom -= addRate;
break;
case GLUT_KEY_END:
moveMeFlat(-1);
break;
case GLUT_KEY_HOME:
moveMeFlat(1);
break;
default:
break;
}
myIdle();
stop = temp;
isGo = true;
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE);
glutInitWindowPosition(300, 0);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("Demo"); // 改了窗口标题
glutDisplayFunc(myDisplay);
glutIdleFunc(myIdle); // 表示在CPU空闲的时间调用某一函数
glutSpecialFunc(processSpecialKeys); // 按键
glutReshapeFunc(changeSize);
glutMouseFunc(mouse);
glutMotionFunc(mouseMotion);
init();
glutMainLoop();
return 0;
}
https://www.bilibili.com/video/BV1vz4y1Q7mN?p=1
有任何问题以及评论或建议欢迎留言!
OpenGL专栏: https://blog.csdn.net/qq_40515692/article/details/103938499