对于 fancy/high-perf Win32 应用程序 UI,我应该使用 Direct3D 还是只使用 Windows GDI?

Should I use Direct3D or just Windows GDI for a fancy/high-perf Win32 app UI?

正在寻找使 UI 真正活泼的正确通用方法。

我正在考虑开发一个 UI 工具,它可能超越某些 "in house" 工具。它将涉及复杂的自定义 2d 元素,并且需要支持大型虚拟表面的快速滚动,这可能需要非常快速地重绘大量自定义内容。

我在 XP 刚出来的时候做过一些 GDI 编程,我 运行 遇到了一些性能问题,其中有很多全屏 blitting(无论如何,这是一台速度很慢的计算机)。我知道 GDI 有一定程度的加速,但我很难确定我可以期望在这里加速什么。

我只在游戏中使用过 Direct3D。让 D3D 支持窗口化的 GUI 应用程序是否合理?此外,如果我使用 D3D,我是否必须从头开始做所有事情,或者我可以做某种 GDI/D3D 混合,例如,在 WM_PAINT 内使用 Direct3D 调用或其他东西,以利用一些像菜单栏或列表框这样的 Win32 东西与充满 D3D 渲染的东西的面板并排?有没有人有混合 D3D 和 Win32 gui 垃圾的例子?或者这不是真正正确的方法?

AutoCad 或 3ds Max 或 Photoshop 等程序,或具有类似 UI 的其他主要 Win32 应用程序有什么作用?

简单的 C 风格 D3D9 应用程序代码(显示网格)。

////////////////////////////////////////////////////////////////
// Defines main Direct3D rendering funcions


#include <windows.h>
#include <mmsystem.h>
#include <d3d9.h>
#include "d3dx9.h"
#include "cube_prim.h"


#ifndef __D3D_RENDERER_H__
#define __D3D_RENDERER_H__


#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)

LPDIRECT3D9 pDirect3D = NULL;
LPDIRECT3DDEVICE9 pDirect3DDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 pDirect3DVertexBuffer = NULL;
LPDIRECT3DINDEXBUFFER9 pDirect3DIndexBuffer = NULL;
LPDIRECT3DTEXTURE9 pDirect3DTexture01 = NULL;
LPDIRECT3DTEXTURE9 pDirect3DTexture02 = NULL;

LPD3DXMESH pD3DXMesh = NULL;
D3DMATERIAL9* pDirect3DMaterial = NULL;
LPDIRECT3DTEXTURE9* pDirect3DTexture = NULL;
DWORD Subsets = 0;

FLOAT XRot = 0.0f;
FLOAT YRot = 0.0f;


HRESULT InitializeD3D(HWND hWnd)
{
    D3DDISPLAYMODE dispMode;
    D3DPRESENT_PARAMETERS parameters;

    pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);

    if (pDirect3D == NULL)
        return E_FAIL;

    if (FAILED(pDirect3D->GetAdapterDisplayMode(
        D3DADAPTER_DEFAULT,&dispMode)))
        return E_FAIL;

    ZeroMemory(&parameters,sizeof(D3DPRESENT_PARAMETERS));
    parameters.Windowed = FALSE;
    parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
    parameters.BackBufferFormat = dispMode.Format;
    parameters.BackBufferWidth = dispMode.Width;
    parameters.BackBufferHeight = dispMode.Height;
    parameters.BackBufferCount = 2;
    parameters.EnableAutoDepthStencil = TRUE;
    parameters.AutoDepthStencilFormat = D3DFMT_D24S8;


    if (FAILED(pDirect3D->CreateDevice(D3DADAPTER_DEFAULT,
        D3DDEVTYPE_HAL,hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING,
        &parameters,&pDirect3DDevice)))
        return E_FAIL;

    pDirect3DDevice->SetRenderState(D3DRS_LIGHTING,TRUE);
    pDirect3DDevice->SetRenderState(D3DRS_AMBIENT,RGB(180,180,180));
    pDirect3DDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
    pDirect3DDevice->SetRenderState(D3DRS_ZENABLE,TRUE);
    //pDirect3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE,D3DMCS_COLOR2);
    //pDirect3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE,D3DMCS_COLOR2);
    pDirect3DDevice->SetRenderState(D3DRS_SPECULARENABLE,TRUE);

    return S_OK;
}


HRESULT InitializeD3DBufferObject(void)
{
    VOID* pVertices = NULL;
    VOID* pIndicies = NULL;


    if (pDirect3DDevice != NULL)
    {
        if (FAILED(pDirect3DDevice->CreateVertexBuffer(
            sizeof(vertices),0,D3DFVF_CUSTOMVERTEX,
            D3DPOOL_DEFAULT,&pDirect3DVertexBuffer,NULL)))
            return E_FAIL;

        if (FAILED(pDirect3DVertexBuffer->Lock(0,
            sizeof(vertices),(void**)&pVertices,NULL)))
            return E_FAIL;

        memcpy(pVertices,vertices,sizeof(vertices));

        pDirect3DVertexBuffer->Unlock();

        if (FAILED(pDirect3DDevice->CreateIndexBuffer(
            sizeof(indices),0,D3DFMT_INDEX32,D3DPOOL_DEFAULT,
            &pDirect3DIndexBuffer,NULL)))
            return E_FAIL;

        if (FAILED(pDirect3DIndexBuffer->Lock(0,
            sizeof(indices),(void**)&pIndicies,NULL)))
            return E_FAIL;

        memcpy(pIndicies,indices,sizeof(indices));

        pDirect3DIndexBuffer->Unlock();

        if (FAILED(D3DXCreateTextureFromFile(pDirect3DDevice,
            _T("wood.tga"),&pDirect3DTexture01)))
            return E_FAIL;

        if (FAILED(D3DXCreateTextureFromFile(pDirect3DDevice,
            _T("stripes.tga"),&pDirect3DTexture02)))
            return E_FAIL;

        return S_OK;
    }
    else
        return E_FAIL;
}



HRESULT InitialMesh(void)
{
    LPD3DXBUFFER pMeshObj = NULL;
    LPD3DXMATERIAL pMaterial = NULL;
    char buffer[255];

    if (pDirect3DDevice != NULL)
    {
        if (FAILED(D3DXLoadMeshFromX(_T("Dwarf\Dwarf.x"),
            D3DXMESH_SYSTEMMEM,
            pDirect3DDevice,
            NULL,
            &pMeshObj,
            NULL,
            &Subsets,
            &pD3DXMesh)))
            return E_FAIL;

        pMaterial = (D3DXMATERIAL*)pMeshObj->GetBufferPointer();

        pDirect3DMaterial = new D3DMATERIAL9[Subsets];
        pDirect3DTexture = new LPDIRECT3DTEXTURE9[Subsets];

        for (INT i = 0; i < Subsets; i++)
        {
            pDirect3DMaterial[i] = pMaterial[i].MatD3D;

            sprintf(buffer,"Dwarf\");
            strcat(buffer,pMaterial[i].pTextureFilename);

            if (FAILED(D3DXCreateTextureFromFileA(
                pDirect3DDevice,buffer,&pDirect3DTexture[i])))
                return E_FAIL;
        }

        pMeshObj->Release();

        return S_OK;
    }
    else
        return E_FAIL;
}



VOID ChangeSize(INT cx,INT cy)
{
    D3DXMATRIX projMatrix;

    if (pDirect3DDevice != NULL)
    {
        if (cy == 0)
            cy = 1;

        FLOAT aspectRatio = static_cast<FLOAT>(cx) / 
            static_cast<FLOAT>(cy);

        D3DXMatrixPerspectiveFovLH(&projMatrix,45.0f,
            aspectRatio,1.0f,150.0f);

        pDirect3DDevice->SetTransform(D3DTS_PROJECTION,&projMatrix);
    }
}


VOID RotateScene(void)
{
    if (GetAsyncKeyState(VK_ESCAPE))
        exit(0);

    if (GetAsyncKeyState(VK_UP))
        XRot -= 0.1f;

    if (GetAsyncKeyState(VK_DOWN))
        XRot += 0.1f;

    if (GetAsyncKeyState(VK_LEFT))
        YRot -= 0.1f;

    if (GetAsyncKeyState(VK_RIGHT))
        YRot += 0.1f;
}



VOID RenderScene(void)
{
    D3DXMATRIX worldMatrix;
    D3DMATERIAL9 material;
    D3DLIGHT9 light;
    D3DCAPS9 caps;

    D3DCOLORVALUE ambientLight = { 0.0f, 0.0f, 0.0f, 1.0f };
    D3DCOLORVALUE diffuseLight = { 0.7f, 0.7f, 0.7f, 1.0f };
    D3DCOLORVALUE specularLight = { 1.0f, 1.0f, 1.0f, 1.0f };
    D3DCOLORVALUE materialColor = { 1.0f, 1.0f, 1.0f, 1.0f };

    ZeroMemory(&material,sizeof(D3DMATERIAL9));
    material.Ambient = materialColor;
    material.Diffuse = materialColor;
    material.Specular = specularLight;
    material.Power = 20.0f;

    ZeroMemory(&light,sizeof(D3DLIGHT9));
    light.Ambient = ambientLight;
    light.Diffuse = diffuseLight;
    light.Specular = specularLight;
    light.Range = 300.0f;
    light.Position = D3DXVECTOR3(-30,150,-10);
    light.Type = D3DLIGHT_POINT;
    light.Attenuation0 = 1.0f;

    if (pDirect3DDevice != NULL)
    {
        D3DXMatrixIdentity(&worldMatrix);
        pDirect3DDevice->SetTransform(D3DTS_WORLD,&worldMatrix);

        D3DXMatrixTranslation(&worldMatrix,0.0f,0.0f,4.0f);
        pDirect3DDevice->MultiplyTransform(D3DTS_WORLD,&worldMatrix);

        D3DXMatrixRotationX(&worldMatrix,XRot);
        pDirect3DDevice->MultiplyTransform(D3DTS_WORLD,&worldMatrix);

        D3DXMatrixRotationY(&worldMatrix,YRot);
        pDirect3DDevice->MultiplyTransform(D3DTS_WORLD,&worldMatrix);

        pDirect3DDevice->Clear(0,0,D3DCLEAR_TARGET | 
            D3DCLEAR_ZBUFFER,D3DCOLOR_ARGB(255,0,0,0),1.0f,0);

        pDirect3DDevice->SetMaterial(&material);
        pDirect3DDevice->SetLight(0,&light);
        pDirect3DDevice->LightEnable(0,TRUE);

        pDirect3DDevice->SetTexture(0,pDirect3DTexture01);
        //pDirect3DDevice->SetTexture(1,pDirect3DTexture02);

        pDirect3DDevice->SetTextureStageState(0,
            D3DTSS_COLORARG1,D3DTA_TEXTURE);
        pDirect3DDevice->SetTextureStageState(0,
            D3DTSS_COLORARG2,D3DTA_DIFFUSE);
        pDirect3DDevice->SetTextureStageState(0,
            D3DTSS_COLOROP,D3DTOP_MODULATE);

        pDirect3DDevice->SetTextureStageState(1,
            D3DTSS_TEXCOORDINDEX,0);
        pDirect3DDevice->SetTextureStageState(1,
            D3DTSS_COLORARG1,D3DTA_TEXTURE);
        pDirect3DDevice->SetTextureStageState(1,
            D3DTSS_COLORARG1,D3DTA_TEXTURE);
        pDirect3DDevice->SetTextureStageState(1,
            D3DTSS_COLOROP,D3DTOP_MODULATE);

        pDirect3DDevice->GetDeviceCaps(&caps);

        pDirect3DDevice->SetSamplerState(0,D3DSAMP_MAXANISOTROPY,caps.MaxAnisotropy);
        pDirect3DDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
        pDirect3DDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC);
        pDirect3DDevice->SetSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_ANISOTROPIC);

        pDirect3DDevice->SetSamplerState(1,D3DSAMP_MAXANISOTROPY,caps.MaxAnisotropy);
        pDirect3DDevice->SetSamplerState(1,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
        pDirect3DDevice->SetSamplerState(1,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC);
        pDirect3DDevice->SetSamplerState(1,D3DSAMP_MIPFILTER,D3DTEXF_ANISOTROPIC);

        pDirect3DDevice->BeginScene();
        {
            pDirect3DDevice->SetStreamSource(0,pDirect3DVertexBuffer,0,
                sizeof(CUSTOMVERTEX));
            pDirect3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
            pDirect3DDevice->SetIndices(pDirect3DIndexBuffer);
            /*pDirect3DDevice->DrawIndexedPrimitive(
                D3DPT_TRIANGLELIST,0,0,36,0,12);*/


            for (int i = 0; i < Subsets; i++)
            {
                pDirect3DDevice->SetMaterial(&pDirect3DMaterial[i]);
                pDirect3DDevice->SetTexture(0,pDirect3DTexture[i]);
                pD3DXMesh->DrawSubset(i);
            }
        }
        pDirect3DDevice->EndScene();

        pDirect3DDevice->Present(NULL,NULL,NULL,NULL);
    }
}


VOID ReleaseD3D(void)
{
    if (pDirect3DTexture)
    {
        for (int i = 0; i < 0; i++)
            pDirect3DTexture[i]->Release();
    }

    if (pDirect3DMaterial)
    {
        delete [] pDirect3DMaterial;
    }

    if (pD3DXMesh)
        pD3DXMesh->Release();

    if (pDirect3DTexture02)
        pDirect3DTexture02->Release();

    if (pDirect3DTexture01)
        pDirect3DTexture01->Release();

    if (pDirect3DIndexBuffer)
        pDirect3DIndexBuffer->Release();

    if (pDirect3DVertexBuffer)
        pDirect3DVertexBuffer->Release();

    if (pDirect3DDevice)
        pDirect3DDevice->Release();

    if (pDirect3D)
        pDirect3D->Release();
}

#endif

应用程序使用带有 WinMain 等的简单 Win32 框架...

MFC 中的示例代码类

#include "MainWnd.h"
#include "d3d_renderer.h"

CMainWnd::CMainWnd(void)
{
}

CMainWnd::~CMainWnd(void)
{
}
BEGIN_MESSAGE_MAP(CMainWnd, CWnd)
    ON_WM_CREATE()
    ON_WM_DESTROY()
    ON_WM_SIZE()
    ON_WM_TIMER()
    ON_WM_PAINT()
END_MESSAGE_MAP()

// WM_CREATE
int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    if (FAILED(InitializeD3D(m_hWnd)))
        exit(0);

    if (FAILED(InitializeD3DBufferObject()))
        exit(0);

    if (FAILED(InitialMesh()))
        exit(0);

    SetTimer(33,1,NULL);

    return 0;
}

// WM_DESTROY
void CMainWnd::OnDestroy()
{
    CWnd::OnDestroy();

    KillTimer(101);

    ReleaseD3D();
}

// WM_SIZE
void CMainWnd::OnSize(UINT nType, int cx, int cy)
{
    CWnd::OnSize(nType, cx, cy);

    ChangeSize(cx,cy);
}

// WM_TIMER
void CMainWnd::OnTimer(UINT_PTR nIDEvent)
{
    InvalidateRect(NULL,FALSE);

    CWnd::OnTimer(nIDEvent);
}

// WM_PAINT
void CMainWnd::OnPaint()
{
    RotateScene();

    RenderScene();

    ValidateRect(NULL);
}

所以决定你想用什么(D3D 明显比 GDI 快)

您还可以使用OpenGL绘制加速图形(比D3D慢一点),代码量更少。

使用 OpenGL 和纯 Win32 显示 3D 文本UI

#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>

// Palette Handle
HPALETTE hPalette = NULL;


static LPCTSTR lpszAppName = "Text3D";
GLint nFontList;

// Light values and coordinates
GLfloat  whiteLight[] = { 0.4f, 0.4f, 0.4f, 1.0f };
GLfloat  diffuseLight[] = { 0.8f, 0.8f, 0.8f, 1.0f };
GLfloat  specular[] = { 0.9f, 0.9f, 0.9f, 1.0f};
GLfloat lightPos[] = { -100.0f, 200.0f, 50.0f, 1.0f };


// Declaration for Window procedure
LRESULT CALLBACK WndProc(   HWND    hWnd,
                            UINT    message,
                            WPARAM  wParam,
                            LPARAM  lParam);

// Set Pixel Format function - forward declaration
void SetDCPixelFormat(HDC hDC);



void ChangeSize(GLsizei w, GLsizei h)
    {
    GLfloat nRange = 100.0f;
    GLfloat fAspect;

    // Prevent a divide by zero
    if(h == 0)
        h = 1;

    fAspect = (GLfloat)w/(GLfloat)h;

    // Set Viewport to window dimensions
    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);

    // Reset coordinate system
    glLoadIdentity();

    // Setup perspective for viewing
    gluPerspective(17.5f,fAspect,1,300);

    // Viewing transformation
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(-1.8f, 0.0f, -15.0f);
    glRotatef(-20.0f, 0.0f, 1.0f,0.0f);

    glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
    }


void RenderScene(void)
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Blue 3D Text
    glColor3ub(0, 0, 255);

    glPushMatrix();
    glListBase(nFontList);
    glCallLists (6, GL_UNSIGNED_BYTE, "OpenGL");    
    glPopMatrix();
    }


void SetupRC(HDC hDC)
    {
    // Setup the Font characteristics
    HFONT hFont;
    GLYPHMETRICSFLOAT agmf[128]; // Throw away
    LOGFONT logfont;

    logfont.lfHeight = -10;
    logfont.lfWidth = 0;
    logfont.lfEscapement = 0;
    logfont.lfOrientation = 0;
    logfont.lfWeight = FW_BOLD;
    logfont.lfItalic = FALSE;
    logfont.lfUnderline = FALSE;
    logfont.lfStrikeOut = FALSE;
    logfont.lfCharSet = ANSI_CHARSET;
    logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
    logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    logfont.lfQuality = DEFAULT_QUALITY;
    logfont.lfPitchAndFamily = DEFAULT_PITCH;
    strcpy(logfont.lfFaceName,"Arial");

    // Create the font and display list
    hFont = CreateFontIndirect(&logfont);
    SelectObject (hDC, hFont); 


    //create display lists for glyphs 0 through 128 with 0.1 extrusion 
    // and default deviation. 
    nFontList = glGenLists(128);
    wglUseFontOutlines(hDC, 0, 128, nFontList, 0.0f, 0.5f, 
                WGL_FONT_POLYGONS, agmf); 

    DeleteObject(hFont);

    glEnable(GL_DEPTH_TEST);    // Hidden surface removal
    glEnable(GL_COLOR_MATERIAL);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

    glEnable(GL_LIGHTING);
    glLightfv(GL_LIGHT0,GL_AMBIENT,whiteLight);
    glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
    glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
    glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
    glEnable(GL_LIGHT0);


    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    glMaterialfv(GL_FRONT, GL_SPECULAR,specular);
    glMateriali(GL_FRONT,GL_SHININESS,128);
    }


// If necessary, creates a 3-3-2 palette for the device context listed.
HPALETTE GetOpenGLPalette(HDC hDC)
    {
    HPALETTE hRetPal = NULL;    // Handle to palette to be created
    PIXELFORMATDESCRIPTOR pfd;  // Pixel Format Descriptor
    LOGPALETTE *pPal;           // Pointer to memory for logical palette
    int nPixelFormat;           // Pixel format index
    int nColors;                // Number of entries in palette
    int i;                      // Counting variable
    BYTE RedRange,GreenRange,BlueRange;
                                // Range for each color entry (7,7,and 3)


    // Get the pixel format index and retrieve the pixel format description
    nPixelFormat = GetPixelFormat(hDC);
    DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

    // Does this pixel format require a palette?  If not, do not create a
    // palette and just return NULL
    if(!(pfd.dwFlags & PFD_NEED_PALETTE))
        return NULL;

    // Number of entries in palette.  8 bits yeilds 256 entries
    nColors = 1 << pfd.cColorBits;  

    // Allocate space for a logical palette structure plus all the palette entries
    pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));

    // Fill in palette header 
    pPal->palVersion = 0x300;       // Windows 3.0
    pPal->palNumEntries = nColors; // table size

    // Build mask of all 1's.  This creates a number represented by having
    // the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
    // pfd.cBlueBits.  
    RedRange = (1 << pfd.cRedBits) -1;
    GreenRange = (1 << pfd.cGreenBits) - 1;
    BlueRange = (1 << pfd.cBlueBits) -1;

    // Loop through all the palette entries
    for(i = 0; i < nColors; i++)
        {
        // Fill in the 8-bit equivalents for each component
        pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
        pPal->palPalEntry[i].peRed = (unsigned char)(
            (double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);

        pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
        pPal->palPalEntry[i].peGreen = (unsigned char)(
            (double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);

        pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
        pPal->palPalEntry[i].peBlue = (unsigned char)(
            (double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);

        pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
        }


    // Create the palette
    hRetPal = CreatePalette(pPal);

    // Go ahead and select and realize the palette for this device context
    SelectPalette(hDC,hRetPal,FALSE);
    RealizePalette(hDC);

    // Free the memory used for the logical palette structure
    free(pPal);

    // Return the handle to the new palette
    return hRetPal;
    }


// Select the pixel format for a given device context
void SetDCPixelFormat(HDC hDC)
    {
    int nPixelFormat;

    static PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),  // Size of this structure
        1,                              // Version of this structure    
        PFD_DRAW_TO_WINDOW |            // Draw to Window (not to bitmap)
        PFD_SUPPORT_OPENGL |            // Support OpenGL calls in window
        PFD_DOUBLEBUFFER,               // Double buffered mode
        PFD_TYPE_RGBA,                  // RGBA Color mode
        32,                             // Want 32 bit color
        0,0,0,0,0,0,                    // Not used to select mode
        0,0,                            // Not used to select mode
        0,0,0,0,0,                      // Not used to select mode
        16,                             // Size of depth buffer
        0,                              // Not used to select mode
        0,                              // Not used to select mode
        0,                              // Draw in main plane
        0,                              // Not used to select mode
        0,0,0 };                        // Not used to select mode

    // Choose a pixel format that best matches that described in pfd
    nPixelFormat = ChoosePixelFormat(hDC, &pfd);

    // Set the pixel format for the device context
    SetPixelFormat(hDC, nPixelFormat, &pfd);
    }



// Entry point of all Windows programs
int APIENTRY WinMain(   HINSTANCE   hInstance,
                        HINSTANCE   hPrevInstance,
                        LPSTR       lpCmdLine,
                        int         nCmdShow)
    {
    MSG         msg;        // Windows message structure
    WNDCLASS    wc;         // Windows class structure
    HWND        hWnd;       // Storeage for window handle


    // Register Window style
    wc.style            = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc      = (WNDPROC) WndProc;
    wc.cbClsExtra       = 0;
    wc.cbWndExtra       = 0;
    wc.hInstance        = hInstance;
    wc.hIcon            = NULL;
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);

    // No need for background brush for OpenGL window
    wc.hbrBackground    = NULL;     

    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = lpszAppName;

    // Register the window class
    if(RegisterClass(&wc) == 0)
        return FALSE;


    // Create the main application window
    hWnd = CreateWindow(
                lpszAppName,
                lpszAppName,

                // OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,

                // Window position and size
                100, 100,
                250, 250,
                NULL,
                NULL,
                hInstance,
                NULL);

    // If window was not created, quit
    if(hWnd == NULL)
        return FALSE;


    // Display the window
    ShowWindow(hWnd,SW_SHOW);
    UpdateWindow(hWnd);

    // Process application messages until the application closes
    while( GetMessage(&msg, NULL, 0, 0))
        {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        }

    return msg.wParam;
    }



// Window procedure, handles all messages for this program
LRESULT CALLBACK WndProc(   HWND    hWnd,
                            UINT    message,
                            WPARAM  wParam,
                            LPARAM  lParam)
    {
    static HGLRC hRC;       // Permenant Rendering context
    static HDC hDC;         // Private GDI Device context

    switch (message)
        {
        // Window creation, setup for OpenGL
        case WM_CREATE:
            // Store the device context
            hDC = GetDC(hWnd);      

            // Select the pixel format
            SetDCPixelFormat(hDC);      

            // Create the rendering context and make it current
            hRC = wglCreateContext(hDC);
            wglMakeCurrent(hDC, hRC);

            // Create the palette
            hPalette = GetOpenGLPalette(hDC);

            SetupRC(hDC);

            break;

        // Window is being destroyed, cleanup
        case WM_DESTROY:
            // Kill the timer that we created
            KillTimer(hWnd,101);

            glDeleteLists(nFontList, 128);

            // Deselect the current rendering context and delete it
            wglMakeCurrent(hDC,NULL);
            wglDeleteContext(hRC);

            // Delete the palette
            if(hPalette != NULL)
                DeleteObject(hPalette);

            // Tell the application to terminate after the window
            // is gone.
            PostQuitMessage(0);
            break;

        // Window is resized.
        case WM_SIZE:
            // Call our function which modifies the clipping
            // volume and viewport
            ChangeSize(LOWORD(lParam), HIWORD(lParam));
            break;

        // The painting function.  This message sent by Windows 
        // whenever the screen needs updating.
        case WM_PAINT:
            {
            // Call OpenGL drawing code
            RenderScene();

            // Call function to swap the buffers
            SwapBuffers(hDC);

            ValidateRect(hWnd,NULL);
            }
            break;


        // Windows is telling the application that it may modify
        // the system palette.  This message in essance asks the 
        // application for a new palette.
        case WM_QUERYNEWPALETTE:
            // If the palette was created.
            if(hPalette)
                {
                int nRet;

                // Selects the palette into the current device context
                SelectPalette(hDC, hPalette, FALSE);

                // Map entries from the currently selected palette to
                // the system palette.  The return value is the number 
                // of palette entries modified.
                nRet = RealizePalette(hDC);

                // Repaint, forces remap of palette in current window
                InvalidateRect(hWnd,NULL,FALSE);

                return nRet;
                }
            break;


        // This window may set the palette, even though it is not the 
        // currently active window.
        case WM_PALETTECHANGED:
            // Don't do anything if the palette does not exist, or if
            // this is the window that changed the palette.
            if((hPalette != NULL) && ((HWND)wParam != hWnd))
                {
                // Select the palette into the device context
                SelectPalette(hDC,hPalette,FALSE);

                // Map entries to system palette
                RealizePalette(hDC);

                // Remap the current colors to the newly realized palette
                UpdateColors(hDC);
                return 0;
                }
            break;


        default:   // Passes it on if unproccessed
            return (DefWindowProc(hWnd, message, wParam, lParam));

        }

    return (0L);
    }

无需重置调色板即可工作

AS window 句柄您可以使用所有合法的 window 句柄(面板、列表框、按钮等...),因此您几乎可以在任何地方显示 3d 内容

Photoshop 使用 OpenGL,3DS Max 可选(OpenGL,Direct3D),AutoCad 很难说:GDI 旧版本,最新版本也使用 .NET。

如果您的 GUI 涉及 3D 场景的 3D 操作,Direct3D 或 OpenGL 可能会胜出。如果你只是想给你的 GUI 一个 "non-boring" 的外观,其中控件被风格化并使用 alpha 混合位图等绘制,那么你最好坚持使用传统的窗口系统(即 GDI)作为底部-最渲染层。然而,实现这种 "look and feel" 的最简单方法是使用更高级别的工具包,如 wxWidgets 或 Qt,以实现主题化和自定义,使您的 GUI 看起来 "modern" 而不是无聊的公司申请。

另一种选择是从本机应用程序使用 XAML/WPF,并使用可用于创建基于 XAML 的 GUI 的工具,例如 Microsoft 的 Expression。我自己还没有探索过,但是使用 MSDN 杂志 2013 年 3 月号 this article 中的技术应该是可行的。