opengl 太阳、地球、月亮 酷炫实例(二)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_40515692/article/details/100802534

自己是这方面的小白,希望大神可以对有问题以及可以优化的地方提出来。也欢迎指出不足和吐槽。希望帮到小白。

opengl 太阳、地球、月亮 酷炫实例(一):
https://blog.csdn.net/qq_40515692/article/details/100778870

自己参考得比较多的网站是这个:
http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html
以及:https://blog.csdn.net/xie_zi/article/details/1911406

所有代码都可以去github免费下载:
https://github.com/Iamttp/OpenGLTest

好先上这一节的效果图。这一节是上一节的继续,在上一节的代码基础上添加了场景漫游,可以用键盘控制“相机”了。
在这里插入图片描述
首先是添加场景漫游相关的基础函数,我们先假设初始化相机位于(0,0,3)的位置,相机镜头对着(0,0,-1)方向,那么就是相当于你的眼睛是相机,显示屏在原点,你和显示屏的距离为3(好吧,并不直观 / w \)。

gluLookAt函数提供了一个简单直观的方法来设置照相机的位置和方向。它有三组参数,每一组由三个浮点型数组成。前三个参数表明照相机的位置,第二组参数定义照相机观察的方向,最后一组表明向上的向量,这个通常设为(0.0,1.0,0.0)。也就是说照相机并没有倾斜。如你想看到所有的物体都是倒置的则可以设置为(0.0,-1.0,0.0)。

那么我们定义orientMe表示根据传入的角度对lx,lz进行更改,即给定和y轴的角度,求出方向向量。
定义moveMeFlat表示根据给定的距离对当前x,z进行更改,即给定距离,然后和当前方向相乘,然后更新x,z。

static float angle = 0.0, ratio;  // angle绕y轴的旋转角,ratio窗口高宽比
static float x = 0.0f, y = 0.0f, z = 3.0f;  //相机位置
static float lx = 0.0f, ly = 0.0f, lz = -1.0f;  //视线方向,初始设为沿着Z轴负方向

void orientMe(float ang) {
	lx = sin(ang);
	lz = -cos(ang);
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}
void moveMeFlat(int direction) {
	x = x + direction * (lx) * 0.1;
	z = z + direction * (lz) * 0.1;
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}

然后是按键控制,这个比较简单,在主函数里面加入。

glutSpecialFunc(&processSpecialKeys);  // 按键

然后定义按键函数即可,左右方向键,将照相机绕y轴旋转,上下方向键,将前后方向移动照相机。调用上面提到的函数。

void processSpecialKeys(int key, int x, int y) {
	switch (key) {
	case GLUT_KEY_LEFT:
		angle -= 0.01f;
		orientMe(angle);
		break;
	case GLUT_KEY_RIGHT:
		angle += 0.01f;
		orientMe(angle);
		break;
	case GLUT_KEY_UP:
		moveMeFlat(1);
		break;
	case GLUT_KEY_DOWN:
		moveMeFlat(-1);
		break;
	}
}

最后一步我们添加 glutReshapeFunc,设置观察方式。具体的代码我就直接放在最终代码那里了。最终代码为:

#include <gl/glut.h>
#include <stdio.h>
#include <time.h>
#include <cmath>

static float angle = 0.0, ratio;  // angle绕y轴的旋转角,ratio窗口高宽比
static float x = 0.0f, y = 0.0f, z = 3.0f;  //相机位置
static float lx = 0.0f, ly = 0.0f, lz = -1.0f;  //视线方向,初始设为沿着Z轴负方向
static int my_angle = 0; // 表示旋转的角度

/**
 * 定义观察方式
 */
void changeSize(int w, int h) {
	//除以0的情况
	if (h == 0) h = 1;
	ratio = 1.0f * w / h;
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	//设置视口为整个窗口大小
	glViewport(0, 0, w, h);
	//设置可视空间
	gluPerspective(45, ratio, 1, 1000);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}
/**
 * 视野漫游函数
 */
void orientMe(float ang) {
	lx = sin(ang);
	lz = -cos(ang);
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}
void moveMeFlat(int direction) {
	x = x + direction * (lx) * 0.1;
	z = z + direction * (lz) * 0.1;
	glLoadIdentity();
	gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);
}

/**
 * 加入按键控制
 */
void processSpecialKeys(int key, int x, int y) {
	switch (key) {
	case GLUT_KEY_LEFT:
		angle -= 0.01f;
		orientMe(angle);
		break;
	case GLUT_KEY_RIGHT:
		angle += 0.01f;
		orientMe(angle);
		break;
	case GLUT_KEY_UP:
		moveMeFlat(1);
		break;
	case GLUT_KEY_DOWN:
		moveMeFlat(-1);
		break;
	}
}

void myDisplay(void) {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// 太阳
	glPushMatrix();
	glColor3f(1.0, 1.0, 0.0);
	glutSolidSphere(0.15, 200, 200);
	glPopMatrix();

	// 地球
	glPushMatrix();
	glColor3f(0.0, 0.0, 1.0);
	glRotated(my_angle, 1.0, 1.0, 1.0);  //公转
	glTranslatef(0.5, 0.5, -0.5);        //平移
	glutSolidSphere(0.1, 200, 200);
	glPopMatrix();

	// 月亮
	glPushMatrix();
	glColor3f(1.0, 1.0, 1.0);
	glRotated(my_angle, 1.0, 1.0, 1.0);  //然后移动到地球旁边旋转
	glTranslatef(0.5, 0.5, -0.5);        //平移
	glRotated(my_angle, 1.0, 1.0, 1.0);  //先假设原点为地球旋转
	glTranslatef(-0.15, -0.15, 0.15);    //平移
	glutSolidSphere(0.05, 200, 200);     //绘制月亮
	glPopMatrix();

	glutSwapBuffers();
}
/**
 * 计时增加角度
 */
void myIdle(void) {
	static int mm = 0;
	mm++;
	if (mm % 300000 == 0) {
		++my_angle;
		if (my_angle >= 360) my_angle = 0;
		myDisplay();
	}
}

int main(int argc, char* argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(1000, 1000);
	glutCreateWindow("太阳,地球和月亮");  // 改了窗口标题

	glutDisplayFunc(&myDisplay);
	glutIdleFunc(&myIdle);  // 表示在CPU空闲的时间调用某一函数
	glutSpecialFunc(&processSpecialKeys);  // 按键
	glutReshapeFunc(&changeSize);

	// 在OpenGL中,默认是没有开启深度检测的,后绘制的物体覆盖先绘制的物体。
	// GL_DEPTH_TEST 用来开启更新深度缓冲区的功能
	glEnable(GL_DEPTH_TEST);
	glutMainLoop();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40515692/article/details/100802534