《基于MFC的OpenGL编程》Part 6 Animation

《基于MFC的OpenGL编程》Part 6 Animation

 原文链接
本文源码链接
    本文中将对第4—5篇文章中的太阳系模型进行修改,加入一些动画效果。此外还会加入显示帧速率的代码。

      加入动画效果最容易的方法是响应WM_TIMER消息,在其消息处理函数中改变一些参数值,比如每过多少毫秒就旋转一定的角度,并且重绘场景。

Frame Rate

Frame rate is nothing but the number of frames that can be rendered per second.The higher this rate, the smoother the animation. In order to calculate the frame rate we retrieve the system time (using the Windows multimedia API function timeGetTime()) before the rendering is performed and after the buffer is swapped. The difference between the two values is the elapsed time to render one frame. Thus we can calculate the frame rate for a given application.

1、我们需要调用timeGetTime()函数,因此在stdafx.h中加入:

#include <mmsystem.h>

注:按文中所给方法,初次编译时无法通过,总是说timeGetTime()未定义,查MSDN发现timeGetTime()函数包含在windows.h和mmsystem.h中,同时调用winmm.lib这个库,所以2OpenGLView.cpp 中直接添加如下代码:

#include <windows.h>
#include <mmsystem.h>

 
 并且Link—>Object/library modules中加入winmm.lib 
 

2、为了计算绘制用时,在CMy2OpenGLView.h中加入如下变量:

	//For elapsed timing calculations
    DWORD m_StartTime, m_ElapsedTime, m_previousElapsedTime;    
    CString m_WindowTitle;    //Window Title
    int DayOfYear;
    int HourOfDay;

并在构造函数中初始化:

CMy2OpenGLView::CMy2OpenGLView()
{
	// TODO: add construction code here
	m_xPos = 0.0f;
    m_yPos = 0.0f;
    m_xAngle = 0.0f;
    m_yAngle = 0.0f;

	m_bPoint       = FALSE;
    m_bLine        = FALSE;
    m_bPolygon     = FALSE;
    m_bTriangle    = FALSE;
    m_bCube        = FALSE;        
    m_bTorus       = FALSE;        
    m_bTeapot      = FALSE;        
    m_bIcosahedron = FALSE;
    m_bSimpleCube  = FALSE; 
	m_bSun		   = FALSE;

	DayOfYear=0;
	HourOfDay=0;
	
}

3、为了计算帧速率,修改OnCreate函数,在其中获取窗口标题,从标题中去掉”Untitled”字样,并启动定时器;

int CMy2OpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here


    //Initialize OpenGL Here
    InitializeOpenGL();
	SetTimer(0,40,NULL); 


	//_snprintf( string, 200, "%s ( %d Frames/sec )",(const char*)m_WindowTitle, FramesPerSecond() );
	//GetParentFrame()->SetWindowText(string);//PostRenderScene()中的语句


	return 0;
}

4、同样为了计算帧速率,修改OnDraw函数如下,在其中用glPushMatrix  glPopMatrixRenderScene函数包裹起来,从而确保动画会正确运行。在SwapBuffers调用后我们调用PostRenderScene来显示帧速率信息到窗口标题。

// CMy2OpenGLView drawing

void CMy2OpenGLView::OnDraw(CDC* pDC)
{
	CMy2OpenGLDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	m_ElapsedTime = ::timeGetTime(); // get current time 
	if(ElapsedTimeinMSSinceLastRender()<30)
		return ;

	  // Clear out the color & depth buffers
    ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	::glClearColor(0.0,0.0,0.5,0.5);//此函数在InitialOpenGL函数中设置默认的背景,此处重新设置,为蓝色背景

	glPushMatrix();
		RenderScene();
  		RenderScene3D();
		RenderSceneSun();
	glPopMatrix();

	 glFlush();
    // Tell OpenGL to flush its pipeline
    ::glFinish();
    // Now Swap the buffers
    ::SwapBuffers( m_pDC->GetSafeHdc() );
 //	SwapBuffers(pDC->m_hDC);
	//Perform Post Display Processing
	//Only update the title every 15 redraws (this is about every 1/2 second)
	PostRenderScene();//此函数可以让标题显示出帧速率,没必要在OnCreate()额外加那两行
	//the very last thing we do is save
	//the elapsed time,this is use with the
	//next elapsed time to calculate the elapsed time since a render and the frame rate
	m_previousElapsedTime=m_ElapsedTime;

}

5、CMy2OpenGLView类中加入下述四个成员函数:PostRenderScene()、FramePerSecond()、ElapsedTimeinMSSinceLastStartup()、ElapsedTimeinMSSinceLastRender(),PostRenderScene()最后两句是用来显示帧速率信息到窗口标题的,代码如下:

// PostRenderScene
// perform post display processing
// The default PostRenderScene places the frame rate in the
// view's title. Replace this with your own title if you like.

void CMy2OpenGLView::PostRenderScene()
{
	// Only update the title every 15 redraws (this is about
    // every 1/2 second)
    static int updateFrame = 15;
    if (16 > ++updateFrame )
        return;
    updateFrame = 0;
    char string[256];
    _snprintf( string, 200, "%s ( %d Frames/sec )",
        (const char*)m_WindowTitle, FramesPerSecond() );
    GetParentFrame()->SetWindowText( string );//这两句就是设置帧速率显示的
}
// FramesPerSecond
// fetch frame rate calculations

int CMy2OpenGLView::FramesPerSecond()
{
	double eTime = ElapsedTimeinMSSinceLastRender();
    if ( 0 == (int)eTime )
        return 0;
    return (int)(1000/(int)eTime);
}

DWORD CMy2OpenGLView::ElapsedTimeinMSSinceLastStartup()
{
	return (m_ElapsedTime - m_StartTime);
}


DWORD CMy2OpenGLView::ElapsedTimeinMSSinceLastRender()
{
	return(m_ElapsedTime-m_previousElapsedTime);
}


6、OnTimer函数中,通过增加变量DayOfYear  HourOfDay的值来控制地球和月球的位置,并且调用InvalidateRect来刷新界面。

void CMy2OpenGLView::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	if(DayOfYear<=365)
		DayOfYear++;
	else
		DayOfYear=1;
	if (HourOfDay<=24)//
		HourOfDay++;
	else
		HourOfDay=1;
	InvalidateRect(NULL,FALSE);
	
	CView::OnTimer(nIDEvent);
}


7、RenderSceneSun()中加入绘制代码:

void CMy2OpenGLView::RenderSceneSun()
{
// 	glLoadIdentity();
//     glTranslatef(m_xPos, m_yPos, -5.0f);
//     glRotatef(m_xAngle, 1.0f,0.0f,0.0f);
//     glRotatef(m_yAngle, 0.0f,1.0f,0.0f);
// 	
//     glutWireCube(1.0f);

	//绘制函数
	//glRotatef((GLfloat)(360.0*DayOfYear)/365.0,0.0f,1.0f,0.0f);//太阳嘛,最好不要转了,所以注释掉
	glTranslatef(-1.0f,+0.3f,-2.0f);//三个glTranslatef()函数分别是调整太阳、行星、月亮位置的,当前参数是我的最好视角,根据自己的位置喜好调
	//Draw the Sun
	glutWireSphere(1.0f,30,30);
	//Rotate the Planet in its orbit
	//glLoadIdentity();//这句最好别加,不然行星就会回到原点处
	glRotatef((GLfloat)(360.0*DayOfYear)/365.0,0.0f,1.0f,0.0f);
	glTranslatef(3.0f,0.0f,0.0f);
	
	glPushMatrix();
		//Rotate the Planet in its orbit
		glRotatef((GLfloat)(360.0*HourOfDay)/24.0,0.0f,1.0f,0.0f);
		//Draw the planet
		glutWireSphere(0.2f,20,20);
	glPopMatrix();
	glRotatef((GLfloat)(360.0*12.5*DayOfYear)/365.0,0.0f,1.0f,0.0f);
	glTranslatef(0.5f,0.0f,0.0f);
	//Draw the Moon
	glutWireSphere(0.05f,20,20);//月亮调大点好看些

//   	glLoadIdentity();
//   	glTranslatef(m_xPos,m_yPos,-5.0f);
//   	glRotatef(m_xAngle,1.0f,0.0f,0.0f);
//   	glRotatef(m_yAngle,0.0f,1.0f,0.0f);

}
运行效果如下,GIF的没有了,就贴静态图吧:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值