使用Glut库和gluLookAt在OpenGL中旋转摄影机
我正在尝试在OpenGl中实现一个能够绘制Lorenz系统的软件。我实现了我的目标,但是以一种静态的方式:系统只绘制一次,仅此而已。现在,我想在系统周围移动我的相机,并显示系统本身的3D效果。我注意到,我无法更新绘制的图像,因为如果我更新系统的点,它们在每次更新中都会不断变化(洛伦兹系统是数学方程的结果,因此我的结果是大浮点数)。然后我意识到我只需要画一次系统,然后以某种方式移动相机。不幸的是,我不知道怎么做。为了我的目的,我在更改gluLookAt呼叫时尤其遇到问题。假设我想根据键盘给出的输入移动相机。你能帮帮我吗?在这里你可以看看我的简单代码 初始化方法:使用Glut库和gluLookAt在OpenGL中旋转摄影机,opengl,glut,glulookat,Opengl,Glut,Glulookat,我正在尝试在OpenGl中实现一个能够绘制Lorenz系统的软件。我实现了我的目标,但是以一种静态的方式:系统只绘制一次,仅此而已。现在,我想在系统周围移动我的相机,并显示系统本身的3D效果。我注意到,我无法更新绘制的图像,因为如果我更新系统的点,它们在每次更新中都会不断变化(洛伦兹系统是数学方程的结果,因此我的结果是大浮点数)。然后我意识到我只需要画一次系统,然后以某种方式移动相机。不幸的是,我不知道怎么做。为了我的目的,我在更改gluLookAt呼叫时尤其遇到问题。假设我想根据键盘给出的输入
void myinit() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor4f(1.0f, 0.0f, 0.0f, 0.09f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POINT_SMOOTH);
glPointSize(1.0f);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glViewport(0, 0, 400, 400); //glViewport(0, 0, width_of_window_rendering_area, height_of_window_rendering area);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)400/400, 0.1, 100); //Sets the frustum to perspective mode, sets up the way in which objects
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
绘图方法
void mydisplay() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //if perspective
glLoadIdentity();
gluLookAt(0.0, 0.0, 100.0, //position
0.0, 0.0, 0.0, //where we are looking
0.0, 1.0, 0.0); //up vector
glBegin(GL_POINTS);
for (int i = 0; i < iterations; i++) {
if(i == 200000){
glColor4f(1.0f, 0.0f, 0.0f, 0.09f);
}
if(i == 400000){
glColor4f(1.0f, 0.0f, 1.0f, 0.09f);
}
if(i == 600000){
glColor4f(0.0f, 0.0f, 1.0f, 0.09f);
}
if(i == 800000){
glColor4f(0.0f, 1.0f, 1.0f, 0.09f);
}
// compute a new point using the strange attractor equations
float xnew=x + h*(s*(y - x));
float ynew=y + h*(x*(p - z) - y);
float znew=z + h*(x*y - b*z);
x = xnew;
y = ynew;
z = znew;
glVertex3f(x, y, z);
}
glEnd();
glutSwapBuffers();
}
结果是:
我想您可能会发现,通常使用glut函数会太慢,无法制作有用的动画 我做了一些类似的事情,分辨率为1200 X 800 X 1200像素,我从openGL函数开始,与您使用的类似。将数据一次一点地传递到gpu的速度非常慢 现在,我首先计算图像,然后使用glsl着色器对gpu进行编程以设置图像动画 我将大数组(如顶点数组和颜色纹理)传递给gpu一次,然后在每次重画时只需传递少量数据(如更新的模型矩阵和一些制服)。重画是通过计时器调用的方法完成的(可能是30-60次/s) 摄像机保持在一个位置;对象旋转(更新的模型矩阵) 由于大多数数据在一次(快速)操作中传输到gpu,并且由于大量计算从cpu卸载到gpu管道,因此这是一个非常有效的过程 这方面的学习曲线可能比你想投资的时间要长,但如果你愿意,红皮书和橘皮书是很好的起点。它们有点过时了,但仍然很好
红皮书(OpenGL编程指南,第8版)和橙皮书(OpenGL®着色语言,第二版)均可免费下载。只需谷歌一下;它们很容易找到。使用计时器回调来增加角度并发布重画:
#include <GL/glut.h>
#include <vector>
struct Vertex
{
float x, y, z, w;
float r, g, b, a;
};
std::vector< Vertex > verts;
void fillVerts()
{
// calculate vertices
// http://paulbourke.net/fractals/lorenz/
double h = 0.01;
double a = 10.0;
double b = 28.0;
double c = 8.0 / 3.0;
Vertex cur;
cur.a = 0.09f;
double x0 = 0.1;
double y0 = 0;
double z0 = 0;
for( unsigned int i = 0; i < 100000; i++ )
{
if(i == 20000)
{
cur.r = 1.0f;
cur.g = 0.0f;
cur.b = 0.0f;
}
if(i == 40000)
{
cur.r = 1.0f;
cur.g = 0.0f;
cur.b = 1.0f;
}
if(i == 60000)
{
cur.r = 0.0f;
cur.g = 0.0f;
cur.b = 1.0f;
}
if(i == 80000)
{
cur.r = 0.0f;
cur.g = 1.0f;
cur.b = 1.0f;
}
const double x1 = x0 + h * a * (y0 - x0);
const double y1 = y0 + h * (x0 * (b - z0) - y0);
const double z1 = z0 + h * (x0 * y0 - c * z0);
x0 = x1;
y0 = y1;
z0 = z1;
if( i > 100 )
{
cur.x = x0;
cur.y = y0;
cur.z = z0;
verts.push_back( cur );
}
}
}
float angle = 0;
void timer( int extra )
{
// spin
angle += 0.5;
glutPostRedisplay();
glutTimerFunc( 16, timer, 0 );
}
void display(void)
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
const double w = glutGet( GLUT_WINDOW_WIDTH );
const double h = glutGet( GLUT_WINDOW_HEIGHT );
gluPerspective( 60.0, w / h, 1.0, 10000.0 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( 70, 70, 70, 0, 0, 0, 0, 0, 1 );
glRotatef( angle, 0, 0, 1 );
// draw curve
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
glVertexPointer( 3, GL_FLOAT, sizeof( Vertex ), &verts[0].x );
glColorPointer( 4, GL_FLOAT, sizeof( Vertex ), &verts[0].r );
glDrawArrays( GL_LINE_STRIP, 0, verts.size() );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 800,600 );
glutCreateWindow( "Attractor" );
glutDisplayFunc( display );
glutTimerFunc( 0, timer, 0 );
fillVerts();
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_POINT_SMOOTH );
glPointSize(1.0f);
glutMainLoop();
return 0;
}
#包括
#包括
结构顶点
{
浮动x,y,z,w;
浮子r,g,b,a;
};
标准::向量<顶点>顶点;
void fillVerts()
{
//计算顶点
// http://paulbourke.net/fractals/lorenz/
双h=0.01;
双a=10.0;
双b=28.0;
双c=8.0/3.0;
顶点电流;
电流a=0.09f;
双x0=0.1;
双y0=0;
双z0=0;
for(无符号整数i=0;i<100000;i++)
{
如果(i==20000)
{
电流r=1.0f;
电流g=0.0f;
电流b=0.0f;
}
如果(i==40000)
{
电流r=1.0f;
电流g=0.0f;
电流b=1.0f;
}
如果(i==60000)
{
电流r=0.0f;
电流g=0.0f;
电流b=1.0f;
}
如果(i==80000)
{
电流r=0.0f;
电流g=1.0f;
电流b=1.0f;
}
常数双x1=x0+h*a*(y0-x0);
常数双y1=y0+h*(x0*(b-z0)-y0);
常数双z1=z0+h*(x0*y0-c*z0);
x0=x1;
y0=y1;
z0=z1;
如果(i>100)
{
电流x=x0;
电流y=y0;
电流z=z0;
垂直推回(cur);
}
}
}
浮动角度=0;
无效计时器(整数额外)
{
//旋转
角度+=0.5;
再发现();
glutTimerFunc(16,定时器,0);
}
作废显示(作废)
{
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
glMatrixMode(GL_投影);
glLoadIdentity();
常数双w=glutGet(GLUT\u窗口\u宽度);
常数双h=glutGet(GLUT\U窗口\U高度);
gluPerspective(60.0,w/h,1.0,10000.0);
glMatrixMode(GLU模型视图);
glLoadIdentity();
gluLookAt(70,70,70,0,0,0,0,0,1);
glRotatef(角度,0,0,1);
//绘制曲线
glEnableClientState(GL_顶点_数组);
glEnableClientState(GL_颜色_阵列);
glVertexPointer(3,GL_FLOAT,sizeof(顶点),&verts[0].x);
glColorPointer(4,GL_FLOAT,sizeof(顶点),&verts[0].r);
glDrawArray(GL_LINE_STRIP,0,verts.size());
glDisableClientState(GL_顶点_数组);
glDisableClientState(GL_颜色_数组);
glutSwapBuffers();
}
int main(int argc,字符**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_深度| GLUT_双精度);
glutInitWindowSize(800600);
窗口(“吸引子”);
glutDisplayFunc(显示器);
glutTimerFunc(0,定时器,0);
fillVerts();
glEnable(GL_混合物);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_减去GL_SRC_ALPHA);
glEnable(GL_POINT_SMOOTH);
glPointSize(1.0f);
glutMainLoop();
返回0;
}
提前计算点位置/颜色,而不是在显示回调中也是一个好主意。将结果存储在缓冲区中,并使用不同的方法多次绘制该缓冲区matrices@ratchetfreak谢谢这已经是我可以使用的非常有用的技巧了。我编辑了这个问题,因为我正在寻找关于如何修改gluLookAt调用的更深入的答案。再次感谢!我不知道为什么人们没有解释为什么就把这个问题降级了。我正在努力寻找解决方案并寻求帮助。由于格式问题和缺少a,我投了反对票。虽然使用现代构造是最好的,但通过将大的
for
循环分解为其他四个循环,可以节省对glColor
的大约迭代次数-4次调用
#include <GL/glut.h>
#include <vector>
struct Vertex
{
float x, y, z, w;
float r, g, b, a;
};
std::vector< Vertex > verts;
void fillVerts()
{
// calculate vertices
// http://paulbourke.net/fractals/lorenz/
double h = 0.01;
double a = 10.0;
double b = 28.0;
double c = 8.0 / 3.0;
Vertex cur;
cur.a = 0.09f;
double x0 = 0.1;
double y0 = 0;
double z0 = 0;
for( unsigned int i = 0; i < 100000; i++ )
{
if(i == 20000)
{
cur.r = 1.0f;
cur.g = 0.0f;
cur.b = 0.0f;
}
if(i == 40000)
{
cur.r = 1.0f;
cur.g = 0.0f;
cur.b = 1.0f;
}
if(i == 60000)
{
cur.r = 0.0f;
cur.g = 0.0f;
cur.b = 1.0f;
}
if(i == 80000)
{
cur.r = 0.0f;
cur.g = 1.0f;
cur.b = 1.0f;
}
const double x1 = x0 + h * a * (y0 - x0);
const double y1 = y0 + h * (x0 * (b - z0) - y0);
const double z1 = z0 + h * (x0 * y0 - c * z0);
x0 = x1;
y0 = y1;
z0 = z1;
if( i > 100 )
{
cur.x = x0;
cur.y = y0;
cur.z = z0;
verts.push_back( cur );
}
}
}
float angle = 0;
void timer( int extra )
{
// spin
angle += 0.5;
glutPostRedisplay();
glutTimerFunc( 16, timer, 0 );
}
void display(void)
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
const double w = glutGet( GLUT_WINDOW_WIDTH );
const double h = glutGet( GLUT_WINDOW_HEIGHT );
gluPerspective( 60.0, w / h, 1.0, 10000.0 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( 70, 70, 70, 0, 0, 0, 0, 0, 1 );
glRotatef( angle, 0, 0, 1 );
// draw curve
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
glVertexPointer( 3, GL_FLOAT, sizeof( Vertex ), &verts[0].x );
glColorPointer( 4, GL_FLOAT, sizeof( Vertex ), &verts[0].r );
glDrawArrays( GL_LINE_STRIP, 0, verts.size() );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 800,600 );
glutCreateWindow( "Attractor" );
glutDisplayFunc( display );
glutTimerFunc( 0, timer, 0 );
fillVerts();
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_POINT_SMOOTH );
glPointSize(1.0f);
glutMainLoop();
return 0;
}