记录DirectX和OpenGL渲染的动画简介 当我们创建游戏和仿真模拟时,有时我们有必要记录渲染的内容。在某些情况下渲染过于复杂和耗时,这是不可避免的。
在DirectX中,库函数D3DXSaveSurfaceToFile()保存表面为一张图片文件。对OpenGL,我们用glReadPixels()来读渲染的图像像素然后手动的保存它们为一张图片文件。然而这些表面只是针对单帧记录的,对记录一段连续帧没有简单的方法存在。换句话说,没有库函数来记录我们的完整存在渲染动画效果。
在这方面,本文提出了几类,这有助于创造电影DirectX的方法和动画。用类CDxToMovie和 CGLToMovie电影可以选择性地或连续的从DirectX和OpenGL渲染帧来创建。一般来说,一个典型的电影创作过程涉及复杂的任务,例如读图的内容,选择帧速率设置,编解码器的设置,初始化媒体流,写媒体流等(详细讨论关于如何创建位图图像序列的电影,请参考这篇文章
Create Movie from HBitmap)。类CDxToMovie和CGLToMovie这里介绍的抽象出所有不必要的复杂性和易于使用的界面,提供简单方法解释如下
从DirectX渲染序列记录一个电影
类CDxToMovie可以记录DirectX渲染序列成电影文件。该类用到DirectX 9.0接口例如LPDIRECT3DSURFACE9,因此你应该用DirectX 9.0 SDK 或者其他的兼容的地方使用这个类 。
开始从本文中的DirectX代码拷贝文件DxToMovie.h,RenderTarget.h,AviFile.h和AviFile.cpp到你的工程目录下然后添加他们到你的工程中,然后添加vfw.lib,一旦添加到你的工程中,你可以通过#include "DxToMovie.h"访问。CDxToMovie构造函数接受不同的参数如输出电影文件名,电影帧的宽度和高度的要求,每像素比特数等…如下所示,
CDxToMovie(LPCTSTR lpszOutputMovieFileName = _T("Output.avi"),
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
int nFrameWidth = GetSystemMetrics(SM_CXSCREEN), /**//*Movie Frame Width*/
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
int nFrameHeight = GetSystemMetrics(SM_CYSCREEN), /**//*Movie Frame Height*/
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
int nBitsPerPixel = 32, /**//*Bits per Pixel*/
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
DWORD dwCodec = mmioFOURCC('M','P','G','4'), /**//*Video Codec for Compression*/
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
DWORD dwFrameRate = 1) /**//*Frame Rate (FPS) setting for the Movie*/
![](/Images/OutliningIndicators/None.gif)
然而,应该注意到的是,这是一个时间设置,后来在电影记录时候不能改变 。每个CDxToMovie对应一个不同的电影文件和再造一个CDxToMovie对象具有相同的输出文件的名字不会追加以前的电影内容,将覆盖它。
CDxToMovie g_MovieRecorder("Output.Avi", 320, 240); 一旦创建CDxToMovie对象,方法CDxToMovie::OnCreateDevice()在你的程序Direct3D设备创建的时候会被调用。类似的,CDxToMovie::OnLostDevice(),CDxToMovie::OnResetDevice()和CDxToMovie::OnDestroyDevice()也会在设备丢失销毁的时候各自被调用。这些函数的原型显示如下
class CDxToMovie
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
HRESULT OnCreateDevice(LPDIRECT3DDEVICE9 pd3dDevice);
HRESULT OnDestroyDevice(LPDIRECT3DDEVICE9 pd3dDevice);
HRESULT OnLostDevice();
HRESULT OnResetDevice(LPDIRECT3DDEVICE9 pd3dDevice,
const D3DSURFACE_DESC* pBackBufferSurfaceDesc);
};函数OnCreateDevice()和OnDestroyDevice()接受一个单单参数,指向你程序的Direct3D设备对象。OnLostDevice()没有参数,但是OnResetDevice()还要有一个指针指向你设备的后缓冲区表面 D3DSURFACE_DESC*。CDxToMovie对象提供一些信息在D3DSURFACE_DESC里 创造一个合适的offscreen渲染目标,可以用来记录你的应用程序的渲染。
真正记录的功能是通过函数CDxToMovie::StartRecordingMovie()和CDxToMovie::PauseRecordingMovie().这两个函数必须每一帧都要在
IDirect3DDevice9::BeginScene() 和
IDirect3DDevice9::EndScene()之间。如下所示
g_pd3dDevice->BeginScene();
![](/Images/OutliningIndicators/None.gif)
// Capture the Rendering onto CDxToMovie's Render Target
g_MovieRecorder.StartRecordingMovie(g_pd3dDevice);
// Render as usual
..
g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,200),1,0);
g_pd3dDevice->SetStreamSource(0,g_pVB,0,sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,1);
g_MovieRecorder.PauseRecordingMovie(g_pd3dDevice);
![](/Images/OutliningIndicators/None.gif)
// Copy the CDxToMovie's Render Target content back onto BackBuffer's Surface
g_pd3dDevice->StretchRect(g_MovieRecorder.RecordingSurface(),
NULL,pBackSurface,
0,D3DTEXF_NONE);
![](/Images/OutliningIndicators/None.gif)
g_pd3dDevice->EndScene();
在上面的代码段中,
g_MovieRecorder.StartRecordingMovie(g_pd3dDevice)
将所有随后的渲染在CDxToMovie的内部渲染目标直到
g_MovieRecorder.PauseRecordingMovie(g_pd3dDevice)被调用。所有的渲染工作在CDxToMovie的内部渲染目标上做,你的程序back surface将没有任何有效的内容显示在你的应用程序窗口。这不要紧,如果你的申请不只是创作这部电影没有任何动画直接呈现在屏幕上。然而,如果你记录电影从一个互动游戏会话上,它会变坏屏幕不更新到最新的渲染的内容(因为通过重新渲染目标,CDxToMovie内容被偷了)。为了避免它,你可以选择性地复制回CDxToMovie内部的渲染目标的内容到你的应用程序的back surface 使用方法IDirect3DDevice9:StretchRect(),其次是常见的g_pd3dDevice - > EndScene()和g_pd3dDevice - >Present()的要求会更新内容的呈现在屏幕上背缓冲区,使屏幕上更新。
如果你想避免一些帧被选择性记录在这部电影,只是不要叫g_MovieRecorder.StartRecordingMovie和g_MovieRecorder.PauseRecordingMovie()(相应的 g_pd3dDevice - > StretchRect())对那些帧,并会直接渲染动画在屏幕上(没有被重定向到CDxToMovie内部的渲染目标)。
演示代码提供这个项目提供了一个简单的应用程序,使得DirectX屏幕上的一个三角形的动作,鼠标移动窗户上,这将simulatenously被渲染成电影文件和记录(名叫output.avi)。跑演示的可执行程序,确保你有MPG4编解码器的计算机上安装,目录有写权限去创建输出电影文件。详情请设置解码器和平衡,请参考这篇文章
Create Movie from HBitmapRecording a Movie from OpenGL Rendered Sequence先暂时不翻译了,以后再翻。
注:第一次翻译,水平比较差,还望各位看客见谅。
Reference:
Recording DirectX and OpenGL Rendered Animations