004:Direct 2D离屏渲染(Qt中实现)

简介:

用QT开发图像显示的小程序,需要一些标注工具,由于用的是opengl渲染,所以就在内存中进行绘制,然后纹理贴图贴出去,发现Qt绘制的效果太差,且速度一般,于是就想着用direct2d来绘制需要的纹理图像。

一、QT:QPainter绘制到QImage

下图是QT直接在QImage对象上绘制的效果,其中QImage长和宽分别为:564 - 466。在打开反走样的设置下,线段和椭圆中的锯齿非常明显,字体绘制的也非常丑陋。

QT绘制代码:

cpp 复制代码
void YGLayerScreen::UpdateQImage(){
	if (m_QImage.isNull())
		return;

	QFont m_Font;
	m_Font.setPixelSize(36);
	m_Font.setStyleStrategy(QFont::PreferAntialias);

	QPainter painter;
	if (!painter.begin(&m_QImage))
		return;

	painter.setPen(QPen(Qt::red, 1));
	painter.setFont(m_Font);

	painter.setRenderHints(QPainter::TextAntialiasing|QPainter::Antialiasing | QPainter::SmoothPixmapTransform);

	painter.drawEllipse(QPoint(m_TextureCol/2, m_TextureRow/2),100,200);
	painter.drawLine(10, 10, m_TextureCol / 2, 30);
	painter.drawText(QPoint(50, 50), QString::fromLocal8Bit("你好123TEXTtext"));
	painter.end();

}

二、Direct2D绘制

QT中Direct2D的配置(非常简单),添加头文件和对应的Lib文件即可,如下:

cpp 复制代码
#include <wrl.h>
#include <windows.h>
#include <d2d1.h>
#include <dwrite.h>
#include <wincodec.h>
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "Dwrite.lib")
#pragma comment(lib, "windowscodecs.lib")

在窗口中随机绘制100个圆形和一个字符串和椭圆,代码如下:

cpp 复制代码
void QtOpenGL::TestDirect2D()
{
	/* 统计运行时间 */
	LARGE_INTEGER start_counter, end_counter, counters, nFreq;
	QueryPerformanceFrequency(&nFreq);
	QueryPerformanceCounter(&start_counter);

	/* 离屏渲染图像的宽高 */
	UINT uiWidth = 512;// 1920;
	UINT uiHeight = 512;// 1080;

	/* IWIC 相关变量 */
	IWICBitmap *pBitmap = NULL;
	IWICImagingFactory* pImageFactory = NULL;

	/* IDWrite 相关变量 */
	IDWriteTextFormat *pTextFormat = NULL;
	IDWriteFactory* pDWriterFactory = NULL;   /* use the DrawText method */
	static const WCHAR msc_fontName[] = L"Verdana";
	static const FLOAT msc_fontSize = 50;


	HRESULT hr = CoCreateInstance(
		CLSID_WICImagingFactory,
		NULL,
		CLSCTX_INPROC_SERVER,
		IID_IWICImagingFactory,
		(LPVOID*)&pImageFactory
	);
	if (SUCCEEDED(hr)) {
		//WICPixelFormatGUID formatGUID = GUID_WICPixelFormat32bppBGRA;
		hr = pImageFactory->CreateBitmap(uiWidth, uiHeight,
			GUID_WICPixelFormat32bppPBGRA,
			WICBitmapCacheOnLoad, &pBitmap);
		if (SUCCEEDED(hr)) {
			int a = 0;
		}
	}

	/* */
	hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED,
		__uuidof(pDWriterFactory),
		reinterpret_cast<IUnknown **>(&pDWriterFactory)
	);

	// Create a DirectWrite text format object.
	hr = pDWriterFactory->CreateTextFormat(msc_fontName, NULL,
		DWRITE_FONT_WEIGHT_NORMAL,
		DWRITE_FONT_STYLE_NORMAL,
		DWRITE_FONT_STRETCH_NORMAL,
		msc_fontSize,
		L"", //locale
		&pTextFormat
	);

	pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
	pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);



	ID2D1Factory *m_pD2DFactory = NULL;

		//ID2D1DCRenderTarget *m_pRenderTarget = NULL;
	hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);

	if (SUCCEEDED(hr))
	{


		// Create a DC render target.
		D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
			D2D1_RENDER_TARGET_TYPE_DEFAULT,
			D2D1::PixelFormat(
				DXGI_FORMAT_B8G8R8A8_UNORM,
				D2D1_ALPHA_MODE_PREMULTIPLIED),
			0,
			0,
			D2D1_RENDER_TARGET_USAGE_NONE,
			D2D1_FEATURE_LEVEL_DEFAULT
		);

		ID2D1RenderTarget* m_Target = NULL;
		hr = m_pD2DFactory->CreateWicBitmapRenderTarget(pBitmap, &props, &m_Target);

		D2D1_SIZE_F rtSize = m_Target->GetSize();
		// Draw a grid background.
		int width = static_cast<int>(rtSize.width);
		int height = static_cast<int>(rtSize.height);

		ID2D1SolidColorBrush* pBlackBrush = NULL;
		hr = m_Target->CreateSolidColorBrush(
			D2D1::ColorF(D2D1::ColorF::Red),//颜色
			&pBlackBrush//接收画刷
		);


		static const WCHAR sc_txt[] = L"你好!Direct 2D!";

		if (SUCCEEDED(hr))
		{
			m_Target->BeginDraw();
			m_Target->Clear(D2D1::ColorF(0.26f, 0.56f, 0.87f));
			m_Target->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(150, 55), 50, 30), pBlackBrush);
			m_Target->DrawTextW(
				sc_txt, 
				ARRAYSIZE(sc_txt) - 1,
				pTextFormat,
				D2D1::RectF(0, 0, uiWidth/2, uiHeight/2),
				pBlackBrush);

			for (int i = 0; i < 100; ++i)
			{
				FLOAT left = rand() % width;
				FLOAT top = rand() % height;
				FLOAT radius = rand() % 200;
				pBlackBrush->SetColor(D2D1::ColorF(rand() % 100 / 100.f, rand() % 100 / 100.f, rand() % 100 / 100.f, 100));
				//CD2DEllipse ellipse(CD2DRectF(left, top, left + radius, top + radius));
				//CD2DSolidColorBrush brush(pRenderTarget, D2D1::ColorF(rand() % 100 / 100.f, rand() % 100 / 100.f, rand() % 100 / 100.f, 100));
				m_Target->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(left, top), radius, radius), pBlackBrush);
				//pRenderTarget->FillEllipse(ellipse, &brush);
			}

			m_Target->EndDraw();
		}


		IWICBitmapLock *pLock = NULL;
		WICRect rcLock = { 0, 0, uiWidth, uiHeight };
		hr = pBitmap->Lock(&rcLock, WICBitmapLockWrite, &pLock);
		if (SUCCEEDED(hr))
		{
			UINT cbBufferSize = 0;
			UINT cbStride = 0;
			BYTE *pv = NULL;

			hr = pLock->GetStride(&cbStride);

			if (SUCCEEDED(hr))
			{
				hr = pLock->GetDataPointer(&cbBufferSize, &pv);
				FILE* pFile = fopen("bmp512.raw", "wb+");
				fwrite(pv, 1, cbBufferSize, pFile);
				fclose(pFile);
			}

			// Clear the image data
			//ZeroMemory(pv, cbBufferSize);

			// Release the bitmap lock.
			pLock->Release();
		}
	}

	if (pBitmap) {
		pBitmap->Release();
	}

	if (pImageFactory) {
		pImageFactory->Release();
	}

	QueryPerformanceCounter(&end_counter);
	counters.QuadPart = end_counter.QuadPart - start_counter.QuadPart;

	LONGLONG fps = nFreq.QuadPart / counters.QuadPart;
	LONGLONG elapsed = counters.QuadPart * 1000 / nFreq.QuadPart;

	qDebug() << "FPS :" << fps << "ms";
	qDebug() << "TIMES :" << elapsed << "ms";
	start_counter = end_counter;
}

绘制效果如下:

三、性能:待测试

由于绘制的内容不同,暂时没对性能进行测试。

相关推荐
2601_9638699514 小时前
【计算机毕业设计】基于Java的潮牌购物网站系统的设计与实现
java·开发语言·课程设计
名字还没想好☜14 小时前
Go 的 io.Reader/Writer 组合实战:io.Copy、TeeReader、MultiWriter 优雅处理数据流
开发语言·后端·golang·go·iphone
郝学胜-神的一滴15 小时前
Qt 高级编程 042:进度条从入门到自定义美化
开发语言·c++·qt·软件开发·用户界面
鸿芯微控科技15 小时前
压电纳米定位分辨率怎么测?噪声、带宽、最小可检测位移与Python分析
开发语言·python·噪声分析·压电执行器·纳米定位·位移测量
AI的探索之旅15 小时前
嵌入式视觉学习路线:Qt + OpenCV + 工业相机,从零到综合项目
qt·opencv·学习
@小匠15 小时前
Spring Boot Nacos绑定 Map 时中文 key 导致启动失败:一次从复现到源码的排查实录
java·开发语言·前端
Knight_AL15 小时前
Lombok @Builder 踩坑:build() 前后对象类型不一样
android·java·开发语言
神明不懂浪漫15 小时前
【第五章】队列
开发语言·数据结构·经验分享·笔记·算法
吃好睡好便好15 小时前
MATLAB仿真框图3
开发语言·matlab·仿真·simulink
-银雾鸢尾-16 小时前
C#中的反射关键类-Type
开发语言·c#