Esta página contém diversos exemplos DirectX10. Eles foram tirados de um tutorial de iniciante em DirectX10 da Microsoft, porém os comentários foram traduzidos para o português.
Obs: Há alguns erros na tradução e em alguns lugares talvez eu tenha esquecido de traduzir
Obs2: O código funciona desde que as dependências tenham sido postas nos seus devidos lugares. Eu me certifiquei disso por iniciar um projeto vazio para o primeiro tutorial e reusar tal projeto para os tutoriais subsequentes, cuidando para que o código fosse executado corretamente. Futuramente vou colocar um link apontando para os arquivos de projeto nesta página
Obs3: Futuramente colocarei estes tutoriais em páginas separadas e explicarei alguns detalhes deles. Até lá veja a explicação nos arquivos de ajuda do DirectX.
Table of Contents
|
Tutorial 00 - DXSDK - Criando uma Janela Win32
Este tutorial básico ensino a criar uma janela Win32 o que é o básico para ser exibido na tela. Em cima de tal janela que o DirectX funcionará em tutoriais posteriores.
// Este tutorial configura uma aplicação Windows com uma janela e um // procedimento para verificar as mensagens do sistema #include <windows.h> HINSTANCE g_hInst = NULL; HWND g_hWnd = NULL; HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ if( FAILED( InitWindow( hInstance, nCmdShow ) ) ) return 0; // Loop principal de mensagens MSG msg = {0}; while( GetMessage( &msg, NULL, 0, 0 ) ){ TranslateMessage( &msg ); DispatchMessage( &msg ); } return (int) msg.wParam; } // Registra classe e cria janela HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ){ // Registra a classe WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; //wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIcon = NULL; wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"TutorialWindowClass"; //wcex.hIconSm = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIconSm = NULL; if( !RegisterClassEx( &wcex ) ) return E_FAIL; // Cria a janela g_hInst = hInstance; RECT rc = { 0, 0, 640, 480 }; AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 10 Tutorial 0: Configurando uma Janela", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL ); if( !g_hWnd ) return E_FAIL; ShowWindow( g_hWnd, nCmdShow ); return S_OK; } // Chamado toda vez que a aplicação recebe uma mensagem LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){ PAINTSTRUCT ps; HDC hdc; switch( message ){ case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; }
Tutorial 01 - DXSDK - Básicos do D3D 10
Este tutorial demonstra como anexar um dispositivo D3D10 à janela
// Esta aplicação demonstra como criar um dispositivo Direct3D10 #include <windows.h> #include <d3d10.h> #include <d3dx10.h> HINSTANCE g_hInst = NULL; HWND g_hWnd = NULL; D3D10_DRIVER_TYPE g_driverType = D3D10_DRIVER_TYPE_NULL; ID3D10Device* g_pd3dDevice = NULL; IDXGISwapChain* g_pSwapChain = NULL; ID3D10RenderTargetView* g_pRenderTargetView = NULL; HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); HRESULT InitDevice(); void CleanupDevice(); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); void Render(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ if( FAILED( InitWindow( hInstance, nCmdShow ) ) ) return 0; if( FAILED( InitDevice() ) ){ CleanupDevice(); return 0; } // Loop principal de mensagens MSG msg = {0}; while( WM_QUIT != msg.message ){ if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); } } return (int) msg.wParam; } // Registra classe e cria janela HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ){ // Registra a classe WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; //wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIcon = NULL; wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"TutorialWindowClass"; //wcex.hIconSm = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIconSm = NULL; if( !RegisterClassEx( &wcex ) ) return E_FAIL; // Cria a janela g_hInst = hInstance; RECT rc = { 0, 0, 640, 480 }; AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 10 Tutorial 1: Básicos do Direct3D 10", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL ); if( !g_hWnd ) return E_FAIL; ShowWindow( g_hWnd, nCmdShow ); return S_OK; } // Chamado toda vez que a aplicação recebe uma mensagem LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){ PAINTSTRUCT ps; HDC hdc; switch( message ){ case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; } // Cria o dispositivo Direct3D e a cadeia de troca HRESULT InitDevice(){ HRESULT hr = S_OK; RECT rc; GetClientRect( g_hWnd, &rc ); UINT width = rc.right - rc.left; UINT height = rc.bottom - rc.top; UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; #endif D3D10_DRIVER_TYPE driverTypes[] = { D3D10_DRIVER_TYPE_HARDWARE, D3D10_DRIVER_TYPE_REFERENCE }; UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof( sd ) ); sd.BufferCount = 1; sd.BufferDesc.Width = width; sd.BufferDesc.Height = height; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Numerator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = g_hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ){ g_driverType = driverTypes[driverTypeIndex]; hr = D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice ); if( SUCCEEDED( hr ) ) break; } if( FAILED( hr ) ) return hr; // cria uma visão de renderização alvo (Render Target) ID3D10Texture2D* pBackBuffer; hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID *) &pBackBuffer ); if( FAILED( hr ) ) return hr; hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView ); pBackBuffer->Release(); if( FAILED( hr ) ) return hr; g_pd3dDevice->OMSetRenderTargets( 1, & g_pRenderTargetView, NULL ); // Configure o viewport D3D10_VIEWPORT vp; vp.Width = width; vp.Height = height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; g_pd3dDevice->RSSetViewports( 1, &vp ); return S_OK; } // Renderiza o quadro void Render(){ // Apenas limpe o buffer de trás float ClearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f}; g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor ); g_pSwapChain->Present(0,0); } // Limpa os objetos que nós criamos void CleanupDevice(){ if( g_pd3dDevice ) g_pd3dDevice->Release(); if( g_pRenderTargetView ) g_pRenderTargetView->Release(); if( g_pSwapChain ) g_pSwapChain->Release(); if( g_pd3dDevice ) g_pd3dDevice->Release(); }
Tutorial 02 - DXSDK - Renderizando um triângulo
Este tutorial demonstra como renderizar um triângulo na tela.
// Esta aplicação exibe um triângulo usando Direct3D10 #include <windows.h> #include <d3d10.h> #include <d3dx10.h> struct SimpleVertex{ D3DXVECTOR3 Pos; }; HINSTANCE g_hInst = NULL; HWND g_hWnd = NULL; D3D10_DRIVER_TYPE g_driverType = D3D10_DRIVER_TYPE_NULL; ID3D10Device* g_pd3dDevice = NULL; IDXGISwapChain* g_pSwapChain = NULL; ID3D10RenderTargetView* g_pRenderTargetView = NULL; ID3D10Effect* g_pEffect = NULL; ID3D10EffectTechnique* g_pTechnique = NULL; ID3D10InputLayout* g_pVertexLayout = NULL; ID3D10Buffer* g_pVertexBuffer = NULL; HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); HRESULT InitDevice(); void CleanupDevice(); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); void Render(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ if( FAILED( InitWindow( hInstance, nCmdShow ) ) ) return 0; if( FAILED( InitDevice() ) ){ CleanupDevice(); return 0; } // Loop principal de mensagens MSG msg = {0}; while( WM_QUIT != msg.message ){ if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); } } return (int) msg.wParam; } // Registra classe e cria janela HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ){ // Registra a classe WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; //wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIcon = NULL; wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"TutorialWindowClass"; //wcex.hIconSm = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIconSm = NULL; if( !RegisterClassEx( &wcex ) ) return E_FAIL; // Cria a janela g_hInst = hInstance; RECT rc = { 0, 0, 640, 480 }; AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 10 Tutorial 2: Renderizando um triângulo", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL ); if( !g_hWnd ) return E_FAIL; ShowWindow( g_hWnd, nCmdShow ); return S_OK; } // Chamado toda vez que a aplicação recebe uma mensagem LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){ PAINTSTRUCT ps; HDC hdc; switch( message ){ case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; } // Cria o dispositivo Direct3D e a cadeia de troca HRESULT InitDevice(){ HRESULT hr = S_OK; RECT rc; GetClientRect( g_hWnd, &rc ); UINT width = rc.right - rc.left; UINT height = rc.bottom - rc.top; UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; #endif D3D10_DRIVER_TYPE driverTypes[] = { D3D10_DRIVER_TYPE_HARDWARE, D3D10_DRIVER_TYPE_REFERENCE }; UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof( sd ) ); sd.BufferCount = 1; sd.BufferDesc.Width = width; sd.BufferDesc.Height = height; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Numerator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = g_hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ){ g_driverType = driverTypes[driverTypeIndex]; hr = D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice ); if( SUCCEEDED( hr ) ) break; } if( FAILED( hr ) ) return hr; // cria uma visão de renderização alvo (Render Target) ID3D10Texture2D* pBackBuffer; hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID *) &pBackBuffer ); if( FAILED( hr ) ) return hr; hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView ); pBackBuffer->Release(); if( FAILED( hr ) ) return hr; g_pd3dDevice->OMSetRenderTargets( 1, & g_pRenderTargetView, NULL ); // Configure o viewport D3D10_VIEWPORT vp; vp.Width = width; vp.Height = height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; g_pd3dDevice->RSSetViewports( 1, &vp ); //Crie o efeito DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configure a opção D3D10_SHADER_DEBUG para embutir informação de debug nos shaders. // Configurar esta opção melhora a debugação do shader, mas ainda permite aos // shaders serem otimizados e executarem da maneira que eles executarão na // configuração release deste programa dwShaderFlags |= D3D10_SHADER_DEBUG; #endif hr = D3DX10CreateEffectFromFile( L"..\\Tutorial02.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, g_pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ); if( FAILED( hr ) ){ MessageBox( g_hWnd, L"O arquivo fx não pôde ser localizado. Por favor execute este executável do diretório que contém o arquivo FX", L"Erro", MB_OK ); return hr; } // Obtenha a técnica g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); // Defina o leiaute de entrada D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Crie o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); hr = g_pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ); if( FAILED( hr ) ) return hr; // Configure o leiaute de entrada g_pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Crie o buffer de vértice SimpleVertex vertices[] = { D3DXVECTOR3( 0.0f, 0.5f, 0.5f ), D3DXVECTOR3( 0.5f, -0.5f, 0.5f ), D3DXVECTOR3( -0.5f, -0.5f, 0.5f ) }; D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( SimpleVertex ) * 3; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer ); if( FAILED( hr ) ) return hr; // Configure o buffer de vértice UINT stride = sizeof( SimpleVertex ); UINT offset = 0; g_pd3dDevice->IASetVertexBuffers( 0,1, &g_pVertexBuffer, &stride, &offset ); // Configure a topologia primitiva g_pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); return S_OK; } // Renderiza o quadro void Render(){ // Limpe o buffer de trás float ClearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f}; // vermelho, verde, azul, alfa g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor ); // Renderize um triângulo D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ){ g_pTechnique->GetPassByIndex( p )->Apply( 0 ); g_pd3dDevice->Draw( 3, 0 ); } // Apresenta a informação renderizada no buffer de trás para o buffer da frente (a tela) g_pSwapChain->Present(0,0); } // Limpa os objetos que nós criamos void CleanupDevice(){ if( g_pd3dDevice ) g_pd3dDevice->ClearState(); if( g_pVertexBuffer ) g_pVertexBuffer->Release(); if( g_pVertexLayout ) g_pVertexLayout->Release(); if( g_pEffect ) g_pEffect->Release(); if( g_pRenderTargetView ) g_pRenderTargetView->Release(); if( g_pSwapChain ) g_pSwapChain->Release(); if( g_pd3dDevice ) g_pd3dDevice->Release(); }
Tutorial 03 - DXSDK - Shaders e sistema de efeito
Este tutorial usa o mesmo código que o exemplo anterior. A mudança está na documentação do DXSDK que explica ao invés do código DirectX que renderiza o triângulo, o código do arquivo de efeito usado. O arquivo de efeito é uma maneira simples e compacta de usar shaders. Apesar de vital importância ele não vai ser explicado aqui. Numa outra oportunidade será colocado sua explicação, provavelmente na seção de shaders e quando isto acontecer esta seção será atualizada para apontar para ele. Neste tempo o que será colocado aqui é o arquivo de efeito apenas para vocês terem uma idéia de como ele é formado.
//-------------------------------------------------------------------------------------- // File: Tutorial02.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- float4 VS( float4 Pos : POSITION ) : SV_POSITION { return Pos; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( float4 Pos : SV_POSITION ) : SV_Target { return float4( 1.0f, 1.0f, 0.0f, 1.0f ); // Yellow, with Alpha = 1 } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }
Tutorial 04 - DXSDK - Renderizando um cubo
Neste tutorial ao invés de um triângulo são renderizados vários triângulos, formando um cubo. Este cubo fica girando através do eixo Y. O propósito do tutorial é introduzir os espaços 3D (Objeto, Mundo, Olho, Espaço de Recorte de coordenadas da tela).
// Esta aplicação exibe um cubo 3D usando Direct3D10 #include <windows.h> #include <d3d10.h> #include <d3dx10.h> struct SimpleVertex{ D3DXVECTOR3 Pos; D3DXVECTOR4 Color; }; HINSTANCE g_hInst = NULL; HWND g_hWnd = NULL; D3D10_DRIVER_TYPE g_driverType = D3D10_DRIVER_TYPE_NULL; ID3D10Device* g_pd3dDevice = NULL; IDXGISwapChain* g_pSwapChain = NULL; ID3D10RenderTargetView* g_pRenderTargetView = NULL; ID3D10Effect* g_pEffect = NULL; ID3D10EffectTechnique* g_pTechnique = NULL; ID3D10InputLayout* g_pVertexLayout = NULL; ID3D10Buffer* g_pVertexBuffer = NULL; ID3D10Buffer* g_pIndexBuffer = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; D3DXMATRIX g_World; D3DXMATRIX g_View; D3DXMATRIX g_Projection; HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); HRESULT InitDevice(); void CleanupDevice(); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); void Render(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ if( FAILED( InitWindow( hInstance, nCmdShow ) ) ) return 0; if( FAILED( InitDevice() ) ){ CleanupDevice(); return 0; } // Loop principal de mensagens MSG msg = {0}; while( WM_QUIT != msg.message ){ if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); } } return (int) msg.wParam; } // Registra classe e cria janela HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ){ // Registra a classe WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; //wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIcon = NULL; wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"TutorialWindowClass"; //wcex.hIconSm = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIconSm = NULL; if( !RegisterClassEx( &wcex ) ) return E_FAIL; // Cria a janela g_hInst = hInstance; RECT rc = { 0, 0, 640, 480 }; AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 10 Tutorial 4: Espaços 3D", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL ); if( !g_hWnd ) return E_FAIL; ShowWindow( g_hWnd, nCmdShow ); return S_OK; } // Chamado toda vez que a aplicação recebe uma mensagem LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){ PAINTSTRUCT ps; HDC hdc; switch( message ){ case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; } // Cria o dispositivo Direct3D e a cadeia de troca HRESULT InitDevice(){ HRESULT hr = S_OK; RECT rc; GetClientRect( g_hWnd, &rc ); UINT width = rc.right - rc.left; UINT height = rc.bottom - rc.top; UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; #endif D3D10_DRIVER_TYPE driverTypes[] = { D3D10_DRIVER_TYPE_HARDWARE, D3D10_DRIVER_TYPE_REFERENCE }; UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof( sd ) ); sd.BufferCount = 1; sd.BufferDesc.Width = width; sd.BufferDesc.Height = height; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = g_hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ){ g_driverType = driverTypes[driverTypeIndex]; hr = D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice ); if( SUCCEEDED( hr ) ) break; } if( FAILED( hr ) ) return hr; // cria uma visão de renderização alvo (Render Target) ID3D10Texture2D* pBackBuffer; hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID *) &pBackBuffer ); if( FAILED( hr ) ) return hr; hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView ); pBackBuffer->Release(); if( FAILED( hr ) ) return hr; g_pd3dDevice->OMSetRenderTargets( 1, & g_pRenderTargetView, NULL ); // Configure o viewport D3D10_VIEWPORT vp; vp.Width = width; vp.Height = height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; g_pd3dDevice->RSSetViewports( 1, &vp ); //Crie o efeito DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configure a opção D3D10_SHADER_DEBUG para embutir informação de debug nos shaders. // Configurar esta opção melhora a debugação do shader, mas ainda permite aos // shaders serem otimizados e executarem da maneira que eles executarão na // configuração release deste programa dwShaderFlags |= D3D10_SHADER_DEBUG; #endif hr = D3DX10CreateEffectFromFile( L"..\\Tutorial04.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, g_pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ); if( FAILED( hr ) ){ MessageBox( g_hWnd, L"O arquivo fx não pôde ser localizado. Por favor execute este executável do diretório que contém o arquivo FX", L"Erro", MB_OK ); return hr; } // Obtem a técnica g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); // Obtém as variáveis g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); // Defina o leiaute de entrada D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); hr = g_pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ); if( FAILED( hr ) ) return hr; // Configure o leiaute de entrada g_pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Crie o buffer de vértice SimpleVertex vertices[] = { { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 1.0f ) }, }; D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( SimpleVertex ) * 8; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer ); if( FAILED( hr ) ) return hr; // Configure o buffer de vértice UINT stride = sizeof( SimpleVertex ); UINT offset = 0; g_pd3dDevice->IASetVertexBuffers( 0,1, &g_pVertexBuffer, &stride, &offset ); // Cria o buffer de índice DWORD indices[] = { 3,1,0, 2,1,3, 0,5,4, 1,5,0, 3,4,7, 0,4,3, 1,6,5, 2,6,1, 2,7,6, 3,7,2, 6,4,5, 7,4,6, }; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( DWORD ) * 36; // 36 vértices necessários para 12 triângulos em uma lista de triângulos bd.BindFlags = D3D10_BIND_INDEX_BUFFER; bd.CPUAccessFlags = bd.MiscFlags = 0; InitData.pSysMem = indices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ); if( FAILED( hr ) ) return hr; // Configura o buffer de índice g_pd3dDevice->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 ); // Configure a topologia primitiva g_pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); // Inicialize a matriz do mundo D3DXVECTOR3 Eye( 0.0f, 1.0f, -5.0f ); D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f ); D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up ); // Inicializa a matriz de projeção D3DXMatrixPerspectiveFovLH( &g_Projection, (float) D3DX_PI * 0.5f, width / (FLOAT) height, 0.1f, 100.0f ); return S_OK; } // Renderiza o quadro void Render(){ // Atualize nosso tempo static float t = 0.0f; if( g_driverType == D3D10_DRIVER_TYPE_REFERENCE ){ t += (float) D3DX_PI * 0.0125f; } else { static DWORD dwTimeStart = 0; DWORD dwTimeCur = GetTickCount(); if( dwTimeStart == 0 ) dwTimeStart = dwTimeCur; t = ( dwTimeCur - dwTimeStart ) / 1000.0f; } // Anime o cubo D3DXMatrixRotationY( &g_World, t ); // Limpe o buffer de trás float ClearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f}; // vermelho, verde, azul, alfa g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor ); // Atualize as variáveis g_pWorldVariable->SetMatrix( (float* )&g_World ); g_pViewVariable->SetMatrix( (float* )&g_View ); g_pProjectionVariable->SetMatrix( (float* )&g_Projection ); // Renderize um triângulo D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ){ g_pTechnique->GetPassByIndex( p )->Apply( 0 ); g_pd3dDevice->DrawIndexed( 36, 0, 0 ); // 36 vértices necessários para 12 triângulos em uma lista de triângulos } // Apresenta a informação renderizada no buffer de trás para o buffer da frente (a tela) g_pSwapChain->Present(0,0); } // Limpa os objetos que nós criamos void CleanupDevice(){ if( g_pd3dDevice ) g_pd3dDevice->ClearState(); if( g_pVertexBuffer ) g_pVertexBuffer->Release(); if( g_pIndexBuffer ) g_pIndexBuffer->Release(); if( g_pVertexLayout ) g_pVertexLayout->Release(); if( g_pEffect ) g_pEffect->Release(); if( g_pRenderTargetView ) g_pRenderTargetView->Release(); if( g_pSwapChain ) g_pSwapChain->Release(); if( g_pd3dDevice ) g_pd3dDevice->Release(); }
O shader que ele faz uso é o seguinte:
//-------------------------------------------------------------------------------------- // File: Tutorial04.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- matrix World; matrix View; matrix Projection; //-------------------------------------------------------------------------------------- struct VS_OUTPUT { float4 Pos : SV_POSITION; float4 Color : COLOR0; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR ) { VS_OUTPUT output = (VS_OUTPUT)0; output.Pos = mul( Pos, World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Color = Color; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( VS_OUTPUT input ) : SV_Target { return input.Color; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }
Tutorial 05 - DXSDK - Animando cubos
Neste tutorial ocorre a animação de dois cubos. O intuito principal dele é mostrar como usar o buffer de profundidade para que os cubos sejam desenhados apropriadamente na tela
// Esta aplicação demonstra animação usando transformações de matriz #include <windows.h> #include <d3d10.h> #include <d3dx10.h> struct SimpleVertex{ D3DXVECTOR3 Pos; D3DXVECTOR4 Color; }; HINSTANCE g_hInst = NULL; HWND g_hWnd = NULL; D3D10_DRIVER_TYPE g_driverType = D3D10_DRIVER_TYPE_NULL; ID3D10Device* g_pd3dDevice = NULL; IDXGISwapChain* g_pSwapChain = NULL; ID3D10RenderTargetView* g_pRenderTargetView = NULL; ID3D10Texture2D* g_pDepthStencil = NULL; ID3D10DepthStencilView* g_pDepthStencilView = NULL; ID3D10Effect* g_pEffect = NULL; ID3D10EffectTechnique* g_pTechnique = NULL; ID3D10InputLayout* g_pVertexLayout = NULL; ID3D10Buffer* g_pVertexBuffer = NULL; ID3D10Buffer* g_pIndexBuffer = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; D3DXMATRIX g_World1; D3DXMATRIX g_World2; D3DXMATRIX g_View; D3DXMATRIX g_Projection; HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); HRESULT InitDevice(); void CleanupDevice(); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); void Render(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ if( FAILED( InitWindow( hInstance, nCmdShow ) ) ) return 0; if( FAILED( InitDevice() ) ){ CleanupDevice(); return 0; } // Loop principal de mensagens MSG msg = {0}; while( WM_QUIT != msg.message ){ if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); } } return (int) msg.wParam; } // Registra classe e cria janela HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ){ // Registra a classe WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; //wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIcon = NULL; wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"TutorialWindowClass"; //wcex.hIconSm = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIconSm = NULL; if( !RegisterClassEx( &wcex ) ) return E_FAIL; // Cria a janela g_hInst = hInstance; RECT rc = { 0, 0, 640, 480 }; AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 10 Tutorial 5", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL ); if( !g_hWnd ) return E_FAIL; ShowWindow( g_hWnd, nCmdShow ); return S_OK; } // Chamado toda vez que a aplicação recebe uma mensagem LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){ PAINTSTRUCT ps; HDC hdc; switch( message ){ case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; } // Cria o dispositivo Direct3D e a cadeia de troca HRESULT InitDevice(){ HRESULT hr = S_OK; RECT rc; GetClientRect( g_hWnd, &rc ); UINT width = rc.right - rc.left; UINT height = rc.bottom - rc.top; UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; #endif D3D10_DRIVER_TYPE driverTypes[] = { D3D10_DRIVER_TYPE_HARDWARE, D3D10_DRIVER_TYPE_REFERENCE }; UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof( sd ) ); sd.BufferCount = 1; sd.BufferDesc.Width = width; sd.BufferDesc.Height = height; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = g_hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ){ g_driverType = driverTypes[driverTypeIndex]; hr = D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice ); if( SUCCEEDED( hr ) ) break; } if( FAILED( hr ) ) return hr; // cria uma visão de renderização alvo (Render Target) ID3D10Texture2D* pBackBuffer; hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID *) &pBackBuffer ); if( FAILED( hr ) ) return hr; hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView ); pBackBuffer->Release(); if( FAILED( hr ) ) return hr; // Cria textura stencil de profundidade D3D10_TEXTURE2D_DESC descDepth; descDepth.Width = width; descDepth.Height = height; descDepth.MipLevels = 1; descDepth.ArraySize = 1; descDepth.Format = DXGI_FORMAT_D32_FLOAT; descDepth.SampleDesc.Count = 1; descDepth.SampleDesc.Quality = 0; descDepth.Usage = D3D10_USAGE_DEFAULT; descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL; descDepth.CPUAccessFlags = descDepth.MiscFlags = 0; hr = g_pd3dDevice->CreateTexture2D( &descDepth, NULL, &g_pDepthStencil ); if( FAILED( hr ) ) return hr; // Cria a visão stencil de profundidade D3D10_DEPTH_STENCIL_VIEW_DESC descDSV; descDSV.Format = descDepth.Format; descDSV.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D; descDSV.Texture2D.MipSlice = 0; hr = g_pd3dDevice->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView ); pBackBuffer->Release(); if( FAILED( hr ) ) return hr; g_pd3dDevice->OMSetRenderTargets( 1, & g_pRenderTargetView, g_pDepthStencilView ); // Configure o viewport D3D10_VIEWPORT vp; vp.Width = width; vp.Height = height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; g_pd3dDevice->RSSetViewports( 1, &vp ); //Cria o efeito DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configure a opção D3D10_SHADER_DEBUG para embutir informação de debug nos shaders. // Configurar esta opção melhora a debugação do shader, mas ainda permite aos // shaders serem otimizados e executarem da maneira que eles executarão na // configuração release deste programa dwShaderFlags |= D3D10_SHADER_DEBUG; #endif hr = D3DX10CreateEffectFromFile( L"..\\Tutorial05.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, g_pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ); if( FAILED( hr ) ){ MessageBox( g_hWnd, L"O arquivo fx não pôde ser localizado. Por favor execute este executável do diretório que contém o arquivo FX", L"Erro", MB_OK ); return hr; } // Obtem a técnica g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); // Obtém as variáveis g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); // Defina o leiaute de entrada D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); hr = g_pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ); if( FAILED( hr ) ) return hr; // Configure o leiaute de entrada g_pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Crie o buffer de vértice SimpleVertex vertices[] = { { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 1.0f ) }, }; D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( SimpleVertex ) * 8; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer ); if( FAILED( hr ) ) return hr; // Configure o buffer de vértice UINT stride = sizeof( SimpleVertex ); UINT offset = 0; g_pd3dDevice->IASetVertexBuffers( 0,1, &g_pVertexBuffer, &stride, &offset ); // Cria o buffer de índice DWORD indices[] = { 3,1,0, 2,1,3, 0,5,4, 1,5,0, 3,4,7, 0,4,3, 1,6,5, 2,6,1, 2,7,6, 3,7,2, 6,4,5, 7,4,6, }; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( DWORD ) * 36; // 36 vértices necessários para 12 triângulos em uma lista de triângulos bd.BindFlags = D3D10_BIND_INDEX_BUFFER; bd.CPUAccessFlags = bd.MiscFlags = 0; InitData.pSysMem = indices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ); if( FAILED( hr ) ) return hr; // Configura o buffer de índice g_pd3dDevice->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 ); // Configure a topologia primitiva g_pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); // Inicialize a matriz do mundo D3DXMatrixIdentity( &g_World1 ); D3DXMatrixIdentity( &g_World2 ); // Inicialize a matriz visão D3DXVECTOR3 Eye( 0.0f, 1.0f, -10.0f ); D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f ); D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up ); // Inicializa a matriz de projeção D3DXMatrixPerspectiveFovLH( &g_Projection, (float) D3DX_PI * 0.25f, width / (FLOAT) height, 0.1f, 100.0f ); return TRUE; } // Renderiza um quadro void Render(){ // Atualize nosso tempo static float t = 0.0f; if( g_driverType == D3D10_DRIVER_TYPE_REFERENCE ){ t += (float) D3DX_PI * 0.0125f; } else { static DWORD dwTimeStart = 0; DWORD dwTimeCur = GetTickCount(); if( dwTimeStart == 0 ) dwTimeStart = dwTimeCur; t = ( dwTimeCur - dwTimeStart ) / 1000.0f; } // Primeiro cubo: Rotacione ao redor da origem D3DXMatrixRotationY( &g_World1, t ); // Segundo cubo: Rotacione ao redor da origem D3DXMATRIX mTranslate; D3DXMATRIX mOrbit; D3DXMATRIX mSpin; D3DXMATRIX mScale; D3DXMatrixRotationZ( &mSpin, -t ); D3DXMatrixRotationY( &mOrbit, -t * 2.0f ); D3DXMatrixTranslation( &mTranslate, -4.0f, 0.0f, 0.0f ); D3DXMatrixScaling( &mScale, 0.3f, 0.3f, 0.3f ); D3DXMatrixMultiply( &g_World2, &mScale, &mSpin ); D3DXMatrixMultiply( &g_World2, &g_World2, &mTranslate ); D3DXMatrixMultiply( &g_World2, &g_World2, &mOrbit ); // Limpe o buffer de trás float ClearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f}; // vermelho, verde, azul, alfa g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor ); // limpe o buffer de profundidade para 1.0 (profundidade máxima) g_pd3dDevice->ClearDepthStencilView( g_pDepthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0 ); // Atualize as variáveis para o primeiro cubo g_pWorldVariable->SetMatrix( (float* )&g_World1 ); g_pViewVariable->SetMatrix( (float* )&g_View ); g_pProjectionVariable->SetMatrix( (float* )&g_Projection ); // Renderize o primeiro cubo D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ){ g_pTechnique->GetPassByIndex( p )->Apply( 0 ); g_pd3dDevice->DrawIndexed( 36, 0, 0 ); // 36 vértices necessários para 12 triângulos em uma lista de triângulos } // Atualize as variáveis para o segundo cubo g_pWorldVariable->SetMatrix( (float* )&g_World2 ); g_pViewVariable->SetMatrix( (float* )&g_View ); g_pProjectionVariable->SetMatrix( (float* )&g_Projection ); // Renderize o segundo cubo for( UINT p = 0; p < techDesc.Passes; ++p ){ g_pTechnique->GetPassByIndex( p )->Apply( 0 ); g_pd3dDevice->DrawIndexed( 36, 0, 0 ); // 36 vértices necessários para 12 triângulos em uma lista de triângulos } // Apresenta a informação renderizada no buffer de trás para o buffer da frente (a tela) g_pSwapChain->Present(0,0); } // Limpa os objetos que nós criamos void CleanupDevice(){ if( g_pd3dDevice ) g_pd3dDevice->ClearState(); if( g_pVertexBuffer ) g_pVertexBuffer->Release(); if( g_pIndexBuffer ) g_pIndexBuffer->Release(); if( g_pVertexLayout ) g_pVertexLayout->Release(); if( g_pEffect ) g_pEffect->Release(); if( g_pRenderTargetView ) g_pRenderTargetView->Release(); if( g_pSwapChain ) g_pSwapChain->Release(); if( g_pd3dDevice ) g_pd3dDevice->Release(); }
Este tutorial usa o mesmo arquivo de efeito que o anterior:
//-------------------------------------------------------------------------------------- // File: Tutorial05.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- matrix World; matrix View; matrix Projection; //-------------------------------------------------------------------------------------- struct VS_INPUT { float4 Pos : POSITION; float4 Color : COLOR; }; struct PS_INPUT { float4 Pos : SV_POSITION; float4 Color : COLOR; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- PS_INPUT VS( VS_INPUT input ) { PS_INPUT output = (PS_INPUT)0; output.Pos = mul( input.Pos, World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Color = input.Color; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input) : SV_Target { return input.Color; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }
Tutorial 06 - DXSDK - Luzes
// Esta aplicação demonstra animação usando transformações de matriz #include <windows.h> #include <d3d10.h> #include <d3dx10.h> struct SimpleVertex{ D3DXVECTOR3 Pos; D3DXVECTOR3 Normal; }; HINSTANCE g_hInst = NULL; HWND g_hWnd = NULL; D3D10_DRIVER_TYPE g_driverType = D3D10_DRIVER_TYPE_NULL; ID3D10Device* g_pd3dDevice = NULL; IDXGISwapChain* g_pSwapChain = NULL; ID3D10RenderTargetView* g_pRenderTargetView = NULL; ID3D10Texture2D* g_pDepthStencil = NULL; ID3D10DepthStencilView* g_pDepthStencilView = NULL; ID3D10Effect* g_pEffect = NULL; ID3D10EffectTechnique* g_pTechniqueRender = NULL; ID3D10EffectTechnique* g_pTechniqueRenderLight = NULL; ID3D10InputLayout* g_pVertexLayout = NULL; ID3D10Buffer* g_pVertexBuffer = NULL; ID3D10Buffer* g_pIndexBuffer = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; ID3D10EffectVectorVariable* g_pLightDirVariable = NULL; ID3D10EffectVectorVariable* g_pLightColorVariable = NULL; ID3D10EffectVectorVariable* g_pOutputColorVariable = NULL; D3DXMATRIX g_World; D3DXMATRIX g_View; D3DXMATRIX g_Projection; HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); HRESULT InitDevice(); void CleanupDevice(); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); void Render(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ if( FAILED( InitWindow( hInstance, nCmdShow ) ) ) return 0; if( FAILED( InitDevice() ) ){ CleanupDevice(); return 0; } // Loop principal de mensagens MSG msg = {0}; while( WM_QUIT != msg.message ){ if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); } } return (int) msg.wParam; } // Registra classe e cria janela HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ){ // Registra a classe WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; //wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIcon = NULL; wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"TutorialWindowClass"; //wcex.hIconSm = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIconSm = NULL; if( !RegisterClassEx( &wcex ) ) return E_FAIL; // Cria a janela g_hInst = hInstance; RECT rc = { 0, 0, 640, 480 }; AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 10 Tutorial 6", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL ); if( !g_hWnd ) return E_FAIL; ShowWindow( g_hWnd, nCmdShow ); return S_OK; } // Chamado toda vez que a aplicação recebe uma mensagem LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){ PAINTSTRUCT ps; HDC hdc; switch( message ){ case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; } // Cria o dispositivo Direct3D e a cadeia de troca HRESULT InitDevice(){ HRESULT hr = S_OK; RECT rc; GetClientRect( g_hWnd, &rc ); UINT width = rc.right - rc.left; UINT height = rc.bottom - rc.top; UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; #endif D3D10_DRIVER_TYPE driverTypes[] = { D3D10_DRIVER_TYPE_HARDWARE, D3D10_DRIVER_TYPE_REFERENCE }; UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof( sd ) ); sd.BufferCount = 1; sd.BufferDesc.Width = width; sd.BufferDesc.Height = height; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = g_hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ){ g_driverType = driverTypes[driverTypeIndex]; hr = D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice ); if( SUCCEEDED( hr ) ) break; } if( FAILED( hr ) ) return hr; // cria uma visão de renderização alvo (Render Target) ID3D10Texture2D* pBackBuffer; hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID *) &pBackBuffer ); if( FAILED( hr ) ) return hr; hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView ); pBackBuffer->Release(); if( FAILED( hr ) ) return hr; // Cria textura stencil de profundidade D3D10_TEXTURE2D_DESC descDepth; descDepth.Width = width; descDepth.Height = height; descDepth.MipLevels = 1; descDepth.ArraySize = 1; descDepth.Format = DXGI_FORMAT_D32_FLOAT; descDepth.SampleDesc.Count = 1; descDepth.SampleDesc.Quality = 0; descDepth.Usage = D3D10_USAGE_DEFAULT; descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL; descDepth.CPUAccessFlags = descDepth.MiscFlags = 0; hr = g_pd3dDevice->CreateTexture2D( &descDepth, NULL, &g_pDepthStencil ); if( FAILED( hr ) ) return hr; // Cria a visão stencil de profundidade D3D10_DEPTH_STENCIL_VIEW_DESC descDSV; descDSV.Format = descDepth.Format; descDSV.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D; descDSV.Texture2D.MipSlice = 0; hr = g_pd3dDevice->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView ); pBackBuffer->Release(); if( FAILED( hr ) ) return hr; g_pd3dDevice->OMSetRenderTargets( 1, & g_pRenderTargetView, g_pDepthStencilView ); // Configure o viewport D3D10_VIEWPORT vp; vp.Width = width; vp.Height = height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; g_pd3dDevice->RSSetViewports( 1, &vp ); //Cria o efeito DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configure a opção D3D10_SHADER_DEBUG para embutir informação de debug nos shaders. // Configurar esta opção melhora a debugação do shader, mas ainda permite aos // shaders serem otimizados e executarem da maneira que eles executarão na // configuração release deste programa dwShaderFlags |= D3D10_SHADER_DEBUG; #endif hr = D3DX10CreateEffectFromFile( L"..\\Tutorial06.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, g_pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ); if( FAILED( hr ) ){ MessageBox( g_hWnd, L"O arquivo fx não pôde ser localizado. Por favor execute este executável do diretório que contém o arquivo FX", L"Erro", MB_OK ); return hr; } // Obtem as técnicas g_pTechniqueRender = g_pEffect->GetTechniqueByName( "Render" ); g_pTechniqueRenderLight = g_pEffect->GetTechniqueByName( "RenderLight" ); // Obtém as variáveis g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); g_pLightDirVariable = g_pEffect->GetVariableByName( "vLightDir" )->AsVector(); g_pLightColorVariable = g_pEffect->GetVariableByName( "vLightColor" )->AsVector(); g_pOutputColorVariable = g_pEffect->GetVariableByName( "vOutputColor" )->AsVector(); // Defina o leiaute de entrada D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechniqueRender->GetPassByIndex( 0 )->GetDesc( &PassDesc ); hr = g_pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ); if( FAILED( hr ) ) return hr; // Configure o leiaute de entrada g_pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Crie o buffer de vértice SimpleVertex vertices[] = { { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR3( 0.0f, -1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR3( 0.0f, -1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR3( 0.0f, -1.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR3( 0.0f, -1.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR3( -1.0f, 0.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR3( -1.0f, 0.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR3( -1.0f, 0.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR3( -1.0f, 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR3( 1.0f, 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR3( 1.0f, 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR3( 1.0f, 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR3( 1.0f, 0.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR3( 0.0f, 0.0f, -1.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR3( 0.0f, 0.0f, -1.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR3( 0.0f, 0.0f, -1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR3( 0.0f, 0.0f, -1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR3( 0.0f, 0.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR3( 0.0f, 0.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR3( 0.0f, 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR3( 0.0f, 0.0f, 1.0f ) }, }; D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( SimpleVertex ) * 24; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer ); if( FAILED( hr ) ) return hr; // Configure o buffer de vértice UINT stride = sizeof( SimpleVertex ); UINT offset = 0; g_pd3dDevice->IASetVertexBuffers( 0,1, &g_pVertexBuffer, &stride, &offset ); // Cria o buffer de índice // Cria o buffer de vértice DWORD indices[] = { 3,1,0, 2,1,3, 6,4,5, 7,4,6, 11,9,8, 10,9,11, 14,12,13, 15,12,14, 19,17,16, 18,17,19, 22,20,21, 23,20,22 }; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( DWORD ) * 36; bd.BindFlags = D3D10_BIND_INDEX_BUFFER; bd.CPUAccessFlags = bd.MiscFlags = 0; InitData.pSysMem = indices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ); if( FAILED( hr ) ) return hr; // Configura o buffer de índice g_pd3dDevice->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 ); // Configure a topologia primitiva g_pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); // Inicialize a matriz do mundo D3DXMatrixIdentity( &g_World ); // Inicialize a matriz visão D3DXVECTOR3 Eye( 0.0f, 4.0f, -10.0f ); D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f ); D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up ); // Inicializa a matriz de projeção D3DXMatrixPerspectiveFovLH( &g_Projection, (float) D3DX_PI * 0.25f, width / (FLOAT) height, 0.1f, 100.0f ); return TRUE; } // Renderiza um quadro void Render(){ // Atualize nosso tempo static float t = 0.0f; if( g_driverType == D3D10_DRIVER_TYPE_REFERENCE ){ t += (float) D3DX_PI * 0.0125f; } else { static DWORD dwTimeStart = 0; DWORD dwTimeCur = GetTickCount(); if( dwTimeStart == 0 ) dwTimeStart = dwTimeCur; t = ( dwTimeCur - dwTimeStart ) / 1000.0f; } // Rotacione o cubo ao redor da origem D3DXMatrixRotationY( &g_World, t ); // Configura nossos parâmetros de iluminação D3DXVECTOR4 vLightDirs[2] = { D3DXVECTOR4( -0.577f, 0.577f, -0.577f, 1.0f ), D3DXVECTOR4( 0.0f, 0.0f, -1.0f, 1.0f ), }; D3DXVECTOR4 vLightColors[2] = { D3DXVECTOR4( 0.5f, 0.5f, 0.5f, 1.0f ), D3DXVECTOR4( 0.5f, 0.0f, 0.0f, 1.0f ) }; // Rotaciona a segunda luz ao redor da origem D3DXMATRIX mRotate; D3DXVECTOR4 vOutDir; D3DXMatrixRotationY( &mRotate, -t * 2.0f ); D3DXVec3Transform( &vLightDirs[1], (D3DXVECTOR3*) &vLightDirs[1], &mRotate ); // Limpe o buffer de trás float ClearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f}; // vermelho, verde, azul, alfa g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor ); // limpe o buffer de profundidade para 1.0 (profundidade máxima) g_pd3dDevice->ClearDepthStencilView( g_pDepthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0 ); // Atualiza as variáveis matriz g_pWorldVariable->SetMatrix( (float* )&g_World ); g_pViewVariable->SetMatrix( (float* )&g_View ); g_pProjectionVariable->SetMatrix( (float* )&g_Projection ); // Atualiza as variáveis de iluminação g_pLightDirVariable->SetFloatVectorArray( (float*) vLightDirs, 0, 2 ); g_pLightColorVariable->SetFloatVectorArray( (float*) vLightColors, 0, 2 ); // Renderiza o cubo D3D10_TECHNIQUE_DESC techDesc; g_pTechniqueRender->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ){ g_pTechniqueRender->GetPassByIndex( p )->Apply( 0 ); g_pd3dDevice->DrawIndexed( 36, 0, 0 ); // 36 vértices necessários para 12 triângulos em uma lista de triângulos } // Renderiza cada luz for( int m = 0; m < 2; ++m ){ D3DXMATRIX mLight; D3DXMATRIX mLightScale; D3DXVECTOR3 vLightPos = vLightDirs[m] * 5.0f; D3DXMatrixTranslation( &mLight, vLightPos.x, vLightPos.y, vLightPos.z ); D3DXMatrixScaling( &mLightScale, 0.2f, 0.2f, 0.2f ); mLight = mLightScale * mLight; // Atualiza a variável do mundo para refeltir a luz atual g_pWorldVariable->SetMatrix( (float*) &mLight ); g_pOutputColorVariable->SetFloatVector( (float*) &vLightColors[m] ); g_pTechniqueRender->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ){ g_pTechniqueRenderLight->GetPassByIndex( p )->Apply( 0 ); g_pd3dDevice->DrawIndexed( 36, 0, 0 ); // 36 vértices necessários para 12 triângulos em uma lista de triângulos } } // Apresenta nosso buffer de trás para o buffer da frente g_pSwapChain->Present(0,0); } // Limpa os objetos que nós criamos void CleanupDevice(){ if( g_pd3dDevice ) g_pd3dDevice->ClearState(); if( g_pVertexBuffer ) g_pVertexBuffer->Release(); if( g_pIndexBuffer ) g_pIndexBuffer->Release(); if( g_pVertexLayout ) g_pVertexLayout->Release(); if( g_pEffect ) g_pEffect->Release(); if( g_pRenderTargetView ) g_pRenderTargetView->Release(); if( g_pDepthStencil ) g_pDepthStencil->Release(); if( g_pDepthStencilView ) g_pDepthStencilView->Release(); if( g_pSwapChain ) g_pSwapChain->Release(); if( g_pd3dDevice ) g_pd3dDevice->Release(); }
O shader para este exemplo é o sgeuinte:
//-------------------------------------------------------------------------------------- // File: Tutorial06.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- matrix World; matrix View; matrix Projection; float4 vLightDir[2]; float4 vLightColor[2]; float4 vOutputColor; //-------------------------------------------------------------------------------------- struct VS_INPUT { float4 Pos : POSITION; float3 Norm : NORMAL; }; struct PS_INPUT { float4 Pos : SV_POSITION; float3 Norm : TEXCOORD0; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- PS_INPUT VS( VS_INPUT input ) { PS_INPUT output = (PS_INPUT)0; output.Pos = mul( input.Pos, World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = mul( input.Norm, World ); return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input) : SV_Target { float4 finalColor = 0; //do NdotL lighting for 2 lights for(int i=0; i<2; i++) { finalColor += saturate( dot( (float3)vLightDir[i],input.Norm) * vLightColor[i] ); } finalColor.a = 1; return finalColor; } //-------------------------------------------------------------------------------------- // PSSolid - render a solid color //-------------------------------------------------------------------------------------- float4 PSSolid( PS_INPUT input) : SV_Target { return vOutputColor; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- technique10 RenderLight { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PSSolid() ) ); } }
Tutorial 07 - DXSDK - Mapeamento de textura
// Esta aplicação demonstra animação usando transformações de matriz #include <windows.h> #include <d3d10.h> #include <d3dx10.h> struct SimpleVertex{ D3DXVECTOR3 Pos; D3DXVECTOR2 Tex; }; HINSTANCE g_hInst = NULL; HWND g_hWnd = NULL; D3D10_DRIVER_TYPE g_driverType = D3D10_DRIVER_TYPE_NULL; ID3D10Device* g_pd3dDevice = NULL; IDXGISwapChain* g_pSwapChain = NULL; ID3D10RenderTargetView* g_pRenderTargetView = NULL; ID3D10Effect* g_pEffect = NULL; ID3D10EffectTechnique* g_pTechnique = NULL; ID3D10InputLayout* g_pVertexLayout = NULL; ID3D10Buffer* g_pVertexBuffer = NULL; ID3D10Buffer* g_pIndexBuffer = NULL; ID3D10ShaderResourceView* g_pTextureRV = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; ID3D10EffectVectorVariable* g_pMeshColorVariable = NULL; ID3D10EffectShaderResourceVariable* g_pDiffuseVariable = NULL; D3DXMATRIX g_World; D3DXMATRIX g_View; D3DXMATRIX g_Projection; D3DXVECTOR4 g_vMeshColor( 0.7f, 0.7f, 0.7f, 1.0f ); HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); HRESULT InitDevice(); void CleanupDevice(); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); void Render(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ if( FAILED( InitWindow( hInstance, nCmdShow ) ) ) return 0; if( FAILED( InitDevice() ) ){ CleanupDevice(); return 0; } // Loop principal de mensagens MSG msg = {0}; while( WM_QUIT != msg.message ){ if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); } } return (int) msg.wParam; } // Registra classe e cria janela HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ){ // Registra a classe WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; //wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIcon = NULL; wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"TutorialWindowClass"; //wcex.hIconSm = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hIconSm = NULL; if( !RegisterClassEx( &wcex ) ) return E_FAIL; // Cria a janela g_hInst = hInstance; RECT rc = { 0, 0, 640, 480 }; AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 10 Tutorial 7", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL ); if( !g_hWnd ) return E_FAIL; ShowWindow( g_hWnd, nCmdShow ); return S_OK; } // Chamado toda vez que a aplicação recebe uma mensagem LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){ PAINTSTRUCT ps; HDC hdc; switch( message ){ case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; } // Cria o dispositivo Direct3D e a cadeia de troca HRESULT InitDevice(){ HRESULT hr = S_OK; RECT rc; GetClientRect( g_hWnd, &rc ); UINT width = rc.right - rc.left; UINT height = rc.bottom - rc.top; UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; #endif D3D10_DRIVER_TYPE driverTypes[] = { D3D10_DRIVER_TYPE_HARDWARE, D3D10_DRIVER_TYPE_REFERENCE }; UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof( sd ) ); sd.BufferCount = 1; sd.BufferDesc.Width = width; sd.BufferDesc.Height = height; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = g_hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ){ g_driverType = driverTypes[driverTypeIndex]; hr = D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice ); if( SUCCEEDED( hr ) ) break; } if( FAILED( hr ) ) return hr; // cria uma visão de renderização alvo (Render Target) ID3D10Texture2D* pBackBuffer; hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID *) &pBackBuffer ); if( FAILED( hr ) ) return hr; hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView ); pBackBuffer->Release(); if( FAILED( hr ) ) return hr; g_pd3dDevice->OMSetRenderTargets( 1, & g_pRenderTargetView, NULL ); // Configure o viewport D3D10_VIEWPORT vp; vp.Width = width; vp.Height = height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; g_pd3dDevice->RSSetViewports( 1, &vp ); //Cria o efeito DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configure a opção D3D10_SHADER_DEBUG para embutir informação de debug nos shaders. // Configurar esta opção melhora a debugação do shader, mas ainda permite aos // shaders serem otimizados e executarem da maneira que eles executarão na // configuração release deste programa dwShaderFlags |= D3D10_SHADER_DEBUG; #endif hr = D3DX10CreateEffectFromFile( L"..\\Tutorial07.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, g_pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ); if( FAILED( hr ) ){ MessageBox( g_hWnd, L"O arquivo fx não pôde ser localizado. Por favor execute este executável do diretório que contém o arquivo FX", L"Erro", MB_OK ); return hr; } // Obtem as técnicas g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); // Obtém as variáveis g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); g_pMeshColorVariable = g_pEffect->GetVariableByName( "vMeshColor" )->AsVector(); g_pDiffuseVariable = g_pEffect->GetVariableByName( "txDiffuse" )->AsShaderResource(); // Defina o leiaute de entrada D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA,0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA,0 }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); hr = g_pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ); if( FAILED( hr ) ) return hr; // Configure o leiaute de entrada g_pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Crie o buffer de vértice SimpleVertex vertices[] = { { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, }; D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( SimpleVertex ) * 24; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer ); if( FAILED( hr ) ) return hr; // Configure o buffer de vértice UINT stride = sizeof( SimpleVertex ); UINT offset = 0; g_pd3dDevice->IASetVertexBuffers( 0,1, &g_pVertexBuffer, &stride, &offset ); // Cria o buffer de índice // Cria o buffer de vértice DWORD indices[] = { 3,1,0, 2,1,3, 6,4,5, 7,4,6, 11,9,8, 10,9,11, 14,12,13, 15,12,14, 19,17,16, 18,17,19, 22,20,21, 23,20,22 }; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( DWORD ) * 36; bd.BindFlags = D3D10_BIND_INDEX_BUFFER; bd.CPUAccessFlags = bd.MiscFlags = 0; InitData.pSysMem = indices; hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ); if( FAILED( hr ) ) return hr; // Configura o buffer de índice g_pd3dDevice->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 ); // Configura a topologia primitiva g_pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); // Carrega a textura hr = D3DX10CreateShaderResourceViewFromFile( g_pd3dDevice, L"..\\seafloor.dds", NULL, NULL, &g_pTextureRV, NULL ); if( FAILED( hr ) ) return hr; // Inicializa a matriz do mundo D3DXMatrixIdentity( &g_World ); // Inicializa a matriz visão D3DXVECTOR3 Eye( 0.0f, 3.0f, -6.0f ); D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f ); D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up ); // Inicializa a matriz de projeção D3DXMatrixPerspectiveFovLH( &g_Projection, (float) D3DX_PI * 0.25f, width / (FLOAT) height, 0.1f, 100.0f ); // Atualize variáveis que nunca mudarão g_pViewVariable->SetMatrix( (float*) &g_View ); g_pProjectionVariable->SetMatrix( (float*) &g_Projection ); g_pDiffuseVariable->SetResource( g_pTextureRV ); return S_OK; } // Renderiza um quadro void Render(){ // Atualize nosso tempo static float t = 0.0f; if( g_driverType == D3D10_DRIVER_TYPE_REFERENCE ){ t += (float) D3DX_PI * 0.0125f; } else { static DWORD dwTimeStart = 0; DWORD dwTimeCur = GetTickCount(); if( dwTimeStart == 0 ) dwTimeStart = dwTimeCur; t = ( dwTimeCur - dwTimeStart ) / 1000.0f; } // Rotacione o cubo ao redor da origem D3DXMatrixRotationY( &g_World, t ); // Modifica a cor g_vMeshColor.x = ( sinf( t*1.0f ) + 1.0f ) * 0.5f; g_vMeshColor.y = ( cosf( t*3.0f ) + 1.0f ) * 0.5f; g_vMeshColor.z = ( sinf( t*5.0f ) + 1.0f ) * 0.5f; // Limpa o buffer de trás float ClearColor[4] = {0.0f, 0.125f, 0.3f, 1.0f}; // vermelho, verde, azul, alfa g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor ); // Atualiza as variáveis que mudam uma vez por quadro g_pWorldVariable->SetMatrix( (float* )&g_World ); g_pMeshColorVariable->SetFloatVector( (float*) g_vMeshColor); // Renderiza o cubo D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ){ g_pTechnique->GetPassByIndex( p )->Apply( 0 ); g_pd3dDevice->DrawIndexed( 36, 0, 0 ); // 36 vértices necessários para 12 triângulos em uma lista de triângulos } // Apresenta nosso buffer de trás para o buffer da frente g_pSwapChain->Present(0,0); } // Limpa os objetos que nós criamos void CleanupDevice(){ if( g_pd3dDevice ) g_pd3dDevice->ClearState(); if( g_pVertexBuffer ) g_pVertexBuffer->Release(); if( g_pIndexBuffer ) g_pIndexBuffer->Release(); if( g_pVertexLayout ) g_pVertexLayout->Release(); if( g_pEffect ) g_pEffect->Release(); if( g_pRenderTargetView ) g_pRenderTargetView->Release(); if( g_pSwapChain ) g_pSwapChain->Release(); if( g_pd3dDevice ) g_pd3dDevice->Release(); }
E o código para o arquivo de efeito é:
//-------------------------------------------------------------------------------------- // File: Tutorial07.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- Texture2D txDiffuse; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; cbuffer cbNeverChanges { matrix View; }; cbuffer cbChangeOnResize { matrix Projection; }; cbuffer cbChangesEveryFrame { matrix World; float4 vMeshColor; }; struct VS_INPUT { float4 Pos : POSITION; float2 Tex : TEXCOORD; }; struct PS_INPUT { float4 Pos : SV_POSITION; float2 Tex : TEXCOORD0; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- PS_INPUT VS( VS_INPUT input ) { PS_INPUT output = (PS_INPUT)0; output.Pos = mul( input.Pos, World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Tex = input.Tex; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input) : SV_Target { return txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }
Tutorial 08 - DXSDK - Introdução ao DXUT
Este tutorial aborda uma introdução ao DXUT. Nele são vistos quais as principais funções de callback que devem ser configuradas para que uma aplicação use das facilidades fornecidas por esta biblioteca utilitária. Ps: A funcionalidade é a mesma do tutorial 07.
// Introdução básica ao DXUT #include <windows.h> #include "DXUT\Core\DXUT.h" #include "DXUT\Core\DXUTmisc.h" #define DEG2RAD( a ) ( a * D3DX_PI / 180.0f ) struct SimpleVertex{ D3DXVECTOR3 Pos; D3DXVECTOR2 Tex; }; ID3D10Effect* g_pEffect = NULL; ID3D10InputLayout* g_pVertexLayout = NULL; ID3D10EffectTechnique* g_pTechnique = NULL; ID3D10Buffer* g_pVertexBuffer = NULL; ID3D10Buffer* g_pIndexBuffer = NULL; ID3D10ShaderResourceView* g_pTextureRV = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; ID3D10EffectVectorVariable* g_pMeshColorVariable = NULL; ID3D10EffectShaderResourceVariable* g_pDiffuseVariable = NULL; D3DXMATRIX g_World; D3DXMATRIX g_View; D3DXMATRIX g_Projection; D3DXVECTOR4 g_vMeshColor( 0.7f, 0.7f, 0.7f, 1.0f ); // Protótipos das funções bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ); HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void CALLBACK OnD3D10ReleasingSwapChain( void* pUserContext ); void CALLBACK OnD3D10DestroyDevice( void* pUserContext ); LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void* pUserContext); void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ); void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUserContext ); bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void *pUserContext ); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ #if defined( DEBUG ) | defined( _DEBUG ) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif // DXUT criará e usará o melhor equipamento disponível (ou D3D9 ou D3D10) // isto é dependente do sistema disponível no qual os CALLBACKS do D3D são configurados abaixo // Configure callbacks DXUT DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable ); DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice ); DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizeSwapChain ); DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain ); DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice ); DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( OnKeyboard ); DXUTSetCallbackFrameMove( OnFrameMove ); DXUTSetCallbackDeviceChanging( ModifyDeviceSettings ); DXUTInit( true, true, NULL ); // Parse da linha de comando, mostra caixas de mensagem no erro, sem parâmetros de linha de comando extra DXUTSetCursorSettings(true, true ); // Mostre o cursor e recorte ele (clip) quando em modo de tela cheia DXUTCreateWindow( L"Tutorial08" ); DXUTCreateDevice( true, 640, 480 ); DXUTMainLoop(); // Entra dentro do loop de renderização DXUT return DXUTGetExitCode(); } // Rejeita qualquer equipamento D3D10 que não é aceitável por retornar falso bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ){ return true; } // Crie quaisquer recursos que não são dependentes do buffer de trás HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void *pUserContext ){ HRESULT hr = S_OK; // Lê o arquivo de efeito D3DX DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined(DEBUG) || defined(_DEBUG) // Coloque a opção D3D10_SHADER_DEBUG para embutir informação de debug nos shaders. // Colocar estaopção melhora a experiência de debugação dos shaders, mas ainda permite // os shaders serem otimizados e executarem apropriadamente da maneira que eles // executarão na configuração release deste programa dwShaderFlags |= D3D10_SHADER_DEBUG; #endif hr = D3DX10CreateEffectFromFile( L"..\\Tutorial08.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ); if( FAILED( hr ) ){ MessageBox( NULL, L"O arquivo fx não pôde ser localizado. Por favor execute este executável do diretório que contém o arquivo FX", L"Erro", MB_OK ); V_RETURN( hr ); } // Obtem as técnicas g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); // Obtém as variáveis g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); g_pMeshColorVariable = g_pEffect->GetVariableByName( "vMeshColor" )->AsVector(); g_pDiffuseVariable = g_pEffect->GetVariableByName( "txDiffuse" )->AsShaderResource(); // Defina o leiaute de entrada D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA,0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA,0 }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); hr = pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ); if( FAILED( hr ) ) return hr; // Configure o leiaute de entrada pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Crie o buffer de vértice SimpleVertex vertices[] = { { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 0.0f ) }, { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f ) }, { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f ) }, }; D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( SimpleVertex ) * 24; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; hr = pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer ); if( FAILED( hr ) ) return hr; // Configure o buffer de vértice UINT stride = sizeof( SimpleVertex ); UINT offset = 0; pd3dDevice->IASetVertexBuffers( 0,1, &g_pVertexBuffer, &stride, &offset ); // Cria o buffer de índice // Cria o buffer de vértice DWORD indices[] = { 3,1,0, 2,1,3, 6,4,5, 7,4,6, 11,9,8, 10,9,11, 14,12,13, 15,12,14, 19,17,16, 18,17,19, 22,20,21, 23,20,22 }; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( DWORD ) * 36; bd.BindFlags = D3D10_BIND_INDEX_BUFFER; bd.CPUAccessFlags = bd.MiscFlags = 0; InitData.pSysMem = indices; V_RETURN( pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ) ); // Configura o buffer de índice pd3dDevice->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 ); // Configura a topologia primitiva pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); // Carrega a textura hr = D3DX10CreateShaderResourceViewFromFile( pd3dDevice, L"..\\seafloor.dds", NULL, NULL, &g_pTextureRV, NULL ); // Inicializa a matriz do mundo D3DXMatrixIdentity( &g_World ); // Inicializa a matriz visão D3DXVECTOR3 Eye( 0.0f, 3.0f, -6.0f ); D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f ); D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up ); // Atualize variáveis que nunca mudarão g_pViewVariable->SetMatrix( (float*) &g_View ); g_pDiffuseVariable->SetResource( g_pTextureRV ); return S_OK; } // Crie quaisquer recursos D3D10 que dependam do buffer de trás // Crie e configure a textura stencial de profundidade se necessário HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain *pSwapChain, const DXGI_SURFACE_DESC *pBufferSurfaceDesc, void *pUserContext){ // Configura os parâmetros de projeção de novo float fAspect = static_cast<float>( pBufferSurfaceDesc->Width) / static_cast<float>( pBufferSurfaceDesc->Height ); D3DXMatrixPerspectiveFovLH( &g_Projection, (float) D3DX_PI * 0.25f, fAspect, 0.1f, 100.0f ); g_pProjectionVariable->SetMatrix( (float*) &g_Projection ); return S_OK; } // Renderiza a cena usando o dispositivo D3D10 void CALLBACK OnD3D10FrameRender( ID3D10Device *pd3dDevice, double fTime, float fElapsedTime, void *pUserContext ) { // Limpa o buffer de trás float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // vermelho, verde, azul, alfa ID3D10RenderTargetView *pRTV = DXUTGetD3D10RenderTargetView(); pd3dDevice->ClearRenderTargetView(pRTV, ClearColor ); // limpa o stencil de profundidade ID3D10DepthStencilView *pDSV = DXUTGetD3D10DepthStencilView(); pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 ); // Atualiza as variáveis que mudam uma vez por quadro g_pWorldVariable->SetMatrix( (float* )&g_World ); g_pMeshColorVariable->SetFloatVector( (float*) g_vMeshColor); // Renderiza o cubo D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ){ g_pTechnique->GetPassByIndex( p )->Apply( 0 ); pd3dDevice->DrawIndexed( 36, 0, 0 ); // 36 vértices necessários para 12 triângulos em uma lista de triângulos } } // Libera recursos D3D10 criados em OnD3D10ResizedSwapChain void CALLBACK OnD3D10ReleasingSwapChain( void *pUserContext ){ } // Libera recursos D3D10 criados em OnD3D10CreateDevice void CALLBACK OnD3D10DestroyDevice( void *pUserContext ){ SAFE_RELEASE( g_pVertexBuffer ); SAFE_RELEASE( g_pIndexBuffer ); SAFE_RELEASE( g_pVertexLayout ); SAFE_RELEASE( g_pTextureRV ); SAFE_RELEASE( g_pEffect ); } // Chamado imediatamente antes de criar um dispositivo D3D9 oy D3D10, permitindo o aplicativo modificar // as configurações do dispositivo como necessário bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings *pDeviceSettings, void *pUserContext ){ return true; } // Trata das atualizações na cena. Isto é chamado indiferentemente de qual API D3D é usada void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUsetContex ){ // Rotaciona p cubo ao redor da origem D3DXMatrixRotationY( &g_World, 60.0f * DEG2RAD( (float) fTime ) ); // Modifique a cor g_vMeshColor.x = ( sinf( (float) fTime *1.0f ) + 1.0f) * 0.5f; g_vMeshColor.y = ( cosf( (float) fTime *3.0f ) + 1.0f) * 0.5f; g_vMeshColor.z = ( sinf( (float) fTime *5.0f ) + 1.0f) * 0.5f; } // Manuseia as mensagens para a aplicação LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void *pUserContext ) { return 0; } // Manuseia pressionamentos do teclado void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ){ if( bKeyDown ){ switch( nChar ){ case VK_F1: // Change as needed break; } } }
O shader relacionado (Tutorial08.fx) é igual ao apresentado no Tutorial 07.
//-------------------------------------------------------------------------------------- // File: Tutorial08.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- Texture2D txDiffuse; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; cbuffer cbNeverChanges { matrix View; }; cbuffer cbChangeOnResize { matrix Projection; }; cbuffer cbChangesEveryFrame { matrix World; float4 vMeshColor; }; struct VS_INPUT { float4 Pos : POSITION; float2 Tex : TEXCOORD; }; struct PS_INPUT { float4 Pos : SV_POSITION; float2 Tex : TEXCOORD0; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- PS_INPUT VS( VS_INPUT input ) { PS_INPUT output = (PS_INPUT)0; output.Pos = mul( input.Pos, World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Tex = input.Tex; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input) : SV_Target { return txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }
Tutorial 09 - DXSDK - usando uma malha com DXUT
Este arquivo mostra como renderizar uma malha .x usando DXUT
// Carregamento de malha através do DXUT #include <windows.h> #include "DXUT.h" #include "DXUTmisc.h" #include "SDKmisc.h" #include "SDKmesh.h" #define DEG2RAD( a ) ( a * D3DX_PI / 180.0f ) ID3D10Effect* g_pEffect = NULL; ID3D10InputLayout* g_pVertexLayout = NULL; ID3D10EffectTechnique* g_pTechnique = NULL; CDXUTSDKMesh g_Mesh; ID3D10EffectShaderResourceVariable* g_ptxDiffuseVariable = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; D3DXMATRIX g_World; D3DXMATRIX g_View; D3DXMATRIX g_Projection; // Protótipos das funções bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ); HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void CALLBACK OnD3D10ReleasingSwapChain( void* pUserContext ); void CALLBACK OnD3D10DestroyDevice( void* pUserContext ); LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void* pUserContext); void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ); void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUserContext ); bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void *pUserContext ); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ #if defined( DEBUG ) | defined( _DEBUG ) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif // DXUT criará e usará o melhor equipamento disponível (ou D3D9 ou D3D10) // isto é dependente do sistema disponível no qual os CALLBACKS do D3D são configurados abaixo // Configure callbacks DXUT DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable ); DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice ); DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizeSwapChain ); DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain ); DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice ); DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( OnKeyboard ); DXUTSetCallbackFrameMove( OnFrameMove ); DXUTSetCallbackDeviceChanging( ModifyDeviceSettings ); DXUTInit( true, true, NULL ); // Parse da linha de comando, mostra caixas de mensagem no erro, sem parâmetros de linha de comando extra DXUTSetCursorSettings(true, true ); // Mostre o cursor e recorte ele (clip) quando em modo de tela cheia DXUTCreateWindow( L"Tutorial09" ); DXUTCreateDevice( true, 640, 480 ); DXUTMainLoop(); // Entra dentro do loop de renderização DXUT return DXUTGetExitCode(); } // Rejeita qualquer equipamento D3D10 que não é aceitável por retornar falso bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ){ return true; } // Crie quaisquer recursos que não são dependentes do buffer de trás HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; // Find the D3DX effect file WCHAR str[MAX_PATH]; V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"..\\Tutorial09.fx" ) ); DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Set the D3D10_SHADER_DEBUG flag to embed debug information in the shaders. // Setting this flag improves the shader debugging experience, but still allows // the shaders to be optimized and to run exactly the way they will run in // the release configuration of this program. dwShaderFlags |= D3D10_SHADER_DEBUG; #endif V_RETURN( D3DX10CreateEffectFromFile( str, NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ) ); // Obtain the technique g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); g_ptxDiffuseVariable = g_pEffect->GetVariableByName( "g_txDiffuse" )->AsShaderResource(); g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); // Define the input layout const D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Create the input layout D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); V_RETURN( pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ) ); // Set the input layout pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Load the mesh V_RETURN( g_Mesh.Create( pd3dDevice, L"..\\Media\\Tiny\\tiny.sdkmesh", true ) ); // Initialize the world matrices D3DXMatrixIdentity( &g_World ); // Initialize the view matrix D3DXVECTOR3 Eye( 0.0f, 3.0f, -500.0f ); D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f ); D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up ); // Update Variables that never change g_pViewVariable->SetMatrix( ( float* )&g_View ); return S_OK; } // Crie quaisquer recursos D3D10 que dependam do buffer de trás HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain *pSwapChain, const DXGI_SURFACE_DESC *pBufferSurfaceDesc, void *pUserContext) { // Configura os parâmetros de projeção de novo float fAspect = static_cast<float>( pBufferSurfaceDesc->Width) / static_cast<float>( pBufferSurfaceDesc->Height ); D3DXMatrixPerspectiveFovLH( &g_Projection, (float) D3DX_PI * 0.25f, fAspect, 0.5f, 1000.0f ); g_pProjectionVariable->SetMatrix( (float*) &g_Projection ); return S_OK; } // Renderiza a cena usando o dispositivo D3D10 void CALLBACK OnD3D10FrameRender( ID3D10Device *pd3dDevice, double fTime, float fElapsedTime, void *pUserContext ) { // Limpa o buffer de trás float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // vermelho, verde, azul, alfa ID3D10RenderTargetView *pRTV = DXUTGetD3D10RenderTargetView(); pd3dDevice->ClearRenderTargetView(pRTV, ClearColor ); // limpa o stencil de profundidade ID3D10DepthStencilView *pDSV = DXUTGetD3D10DepthStencilView(); pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 ); // Atualiza as variáveis que mudam uma vez por quadro g_pWorldVariable->SetMatrix( (float* )&g_World ); // Configura o leiaute de vértices pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Renderiza a malha UINT Strides[1]; UINT Offsets[1]; ID3D10Buffer* pVB[1]; pVB[0] = g_Mesh.GetVB10( 0, 0 ); Strides[0] = ( UINT ) g_Mesh.GetVertexStride(0,0); Offsets[0] = 0; pd3dDevice->IASetVertexBuffers(0, 1, pVB, Strides, Offsets); pd3dDevice->IASetIndexBuffer( g_Mesh.GetIB10( 0 ), g_Mesh.GetIBFormat10( 0 ), 0 ); D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); SDKMESH_SUBSET* pSubset = NULL; ID3D10ShaderResourceView* pDiffuseRV = NULL; D3D10_PRIMITIVE_TOPOLOGY PrimType; for( UINT p = 0; p < techDesc.Passes; ++p ){ for( UINT subset = 0; subset < g_Mesh.GetNumSubsets( 0 ); ++subset ){ pSubset = g_Mesh.GetSubset( 0, subset ); PrimType = g_Mesh.GetPrimitiveType10( ( SDKMESH_PRIMITIVE_TYPE ) pSubset->PrimitiveType ); pd3dDevice->IASetPrimitiveTopology( PrimType ); pDiffuseRV = g_Mesh.GetMaterial( pSubset->MaterialID )->pDiffuseRV10; g_ptxDiffuseVariable->SetResource( pDiffuseRV ); g_pTechnique->GetPassByIndex( p )->Apply( 0 ); pd3dDevice->DrawIndexed( ( UINT ) pSubset->IndexCount, 0, ( UINT ) pSubset->VertexStart ); } } // a classe de malha também tinha um método render que permite renderizar a malha com as opções mais comuns // g_pMesh.Render( pd3dDevice, g_pTechnique, g_ptxDiffuseVariable ); } // Libera recursos D3D10 criados em OnD3D10ResizedSwapChain void CALLBACK OnD3D10ReleasingSwapChain( void *pUserContext ){ } // Libera recursos D3D10 criados em OnD3D10CreateDevice void CALLBACK OnD3D10DestroyDevice( void *pUserContext ){ DXUTGetGlobalResourceCache().OnDestroyDevice(); SAFE_RELEASE( g_pVertexLayout ); SAFE_RELEASE( g_pEffect ); g_Mesh.Destroy(); } // Chamado imediatamente antes de criar um dispositivo D3D9 oy D3D10, permitindo o aplicativo modificar // as configurações do dispositivo como necessário bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings *pDeviceSettings, void *pUserContext ){ return true; } // Trata das atualizações na cena. Isto é chamado indiferentemente de qual API D3D é usada void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUsetContex ){ // Rotaciona p cubo ao redor da origem D3DXMatrixRotationY( &g_World, 60.0f * DEG2RAD( (float) fTime ) ); } // Manuseia as mensagens para a aplicação LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void *pUserContext ) { return 0; } // Manuseia pressionamentos do teclado void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ){ if( bKeyDown ){ switch( nChar ){ case VK_F1: // Change as needed break; } } }
O arquivo de efeito que acompanho o exemplo é mostrado logo abaixo
//-------------------------------------------------------------------------------------- // File: Tutorial08.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- Texture2D g_txDiffuse; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; cbuffer cbConstant { float3 vLightDir = float3(-0.577,0.577,-0.577); }; cbuffer cbChangesOnce { matrix View; }; cbuffer cbChangeOnResize { matrix Projection; }; cbuffer cbChangesEveryFrame { matrix World; }; struct VS_INPUT { float3 Pos : POSITION; //position float3 Norm : NORMAL; //normal float2 Tex : TEXCOORD0; //texture coordinate }; struct PS_INPUT { float4 Pos : SV_POSITION; float3 Norm : TEXCOORD0; float2 Tex : TEXCOORD1; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- PS_INPUT VS( VS_INPUT input ) { PS_INPUT output = (PS_INPUT)0; output.Pos = mul( float4(input.Pos,1), World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = mul( input.Norm, World ); output.Tex = input.Tex; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input) : SV_Target { //calculate lighting assuming light color is <1,1,1,1> float fLighting = saturate( dot( input.Norm, vLightDir ) ); float4 outputColor = g_txDiffuse.Sample( samLinear, input.Tex ) * fLighting; outputColor.a = 1; return outputColor; } //-------------------------------------------------------------------------------------- // Technique //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }
Tutorial 10 - DXSDK - DXUT Avançado
Esta amostra foca em características avanãdas do DXUT, mostrando como se pode integrar funcionalidade GUI com DX
// Carregamento de malha através do DXUT #include <windows.h> #include "DXUT.h" #include "DXUTcamera.h" #include "DXUTgui.h" #include "DXUTsettingsDlg.h" #include "DXUTmisc.h" #include "SDKmisc.h" #include "SDKmesh.h" #define DEG2RAD( a ) ( a * D3DX_PI / 180.0f ) CModelViewerCamera g_Camera; // Uma câmera de visualização do modelo CDXUTDialogResourceManager g_DialogResourceManager; // gerente para recursos compartilhados de diálogos CD3DSettingsDlg g_D3DSettingsDialog; // diálogo de configurações do dispositivo CDXUTDialog g_HUD; // gerencia a UI 3D CDXUTDialog g_SampleUI; // diálogo para controles específicos da amostra ID3DX10Font* g_pFont = NULL; // Fonte para desenho de texto ID3DX10Sprite* g_pSprite = NULL; // SPrite para desenho de texto em lote CDXUTTextHelper* g_pTxtHelper = NULL; ID3D10Effect* g_pEffect = NULL; // interface de efeito D3DX ID3D10InputLayout* g_pVertexLayout = NULL; // Leiaute de vértice ID3D10EffectTechnique* g_pTechnique = NULL; CDXUTSDKMesh g_Mesh; ID3D10EffectShaderResourceVariable* g_ptxDiffuseVariable = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; ID3D10EffectScalarVariable* g_pPuffiness = NULL; D3DXMATRIX g_World; float g_fModelPuffiness; bool g_bSpinning = true; // IDs de controle da UI #define IDC_TOGGLEFULLSCREEN 1 #define IDC_TOGGLEREF 2 #define IDC_CHANGEDEVICE 3 #define IDC_TOGGLESPIN 4 #define IDC_PUFF_SCALE 5 #define IDC_PUFF_STATIC 6 #define IDC_TOGGLEWARP 7 // Protótipos das funções bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ); HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void CALLBACK OnD3D10ReleasingSwapChain( void* pUserContext ); void CALLBACK OnD3D10DestroyDevice( void* pUserContext ); void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void *pUserContext ); LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void* pUserContext); void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ); void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUserContext ); bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void *pUserContext ); void RenderText(); void InitApp(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ #if defined( DEBUG ) | defined( _DEBUG ) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif // DXUT criará e usará o melhor equipamento disponível (ou D3D9 ou D3D10) // isto é dependente do sistema disponível no qual os CALLBACKS do D3D são configurados abaixo // Configure callbacks DXUT DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable ); DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice ); DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizeSwapChain ); DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain ); DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice ); DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( OnKeyboard ); DXUTSetCallbackFrameMove( OnFrameMove ); DXUTSetCallbackDeviceChanging( ModifyDeviceSettings ); DXUTInit( true, true, NULL ); // Parse da linha de comando, mostra caixas de mensagem no erro, sem parâmetros de linha de comando extra DXUTSetCursorSettings(true, true ); // Mostre o cursor e recorte ele (clip) quando em modo de tela cheia InitApp(); DXUTCreateWindow( L"Tutorial10" ); DXUTCreateDevice( true, 640, 480 ); DXUTMainLoop(); // Entra dentro do loop de renderização DXUT return DXUTGetExitCode(); } // Inicializa a aplicação void InitApp() { g_fModelPuffiness = 0.0f; g_bSpinning = true; g_D3DSettingsDialog.Init( &g_DialogResourceManager ); g_HUD.Init( &g_DialogResourceManager ); g_SampleUI.Init( &g_DialogResourceManager ); g_HUD.SetCallback( OnGUIEvent ); int iY = 10; g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Mudar para tela cheia", 35, iY, 125, 22 ); g_HUD.AddButton( IDC_CHANGEDEVICE, L"Mudar dispositivo (F2)", 35, iY += 24, 125, 22, VK_F2 ); g_HUD.AddButton( IDC_TOGGLEREF, L"Mudar para REF (F3)", 35, iY += 24, 125, 22, VK_F3 ); g_HUD.AddButton( IDC_TOGGLEWARP, L"Mudar para WARP( F4 )", 35, iY+= 24, 125, 22, VK_F4 ); g_SampleUI.SetCallback( OnGUIEvent); iY = 10; WCHAR sz[100]; iY += 24; swprintf_s( sz, 100, L"Inchaço: %0.2f", g_fModelPuffiness ); g_SampleUI.AddStatic( IDC_PUFF_STATIC, sz, 35, iY += 24, 125, 22 ); g_SampleUI.AddSlider( IDC_PUFF_SCALE, 50, iY += 24, 100, 22, 0, 2000, ( int ) ( g_fModelPuffiness * 100.0f ) ); iY += 24; g_SampleUI.AddCheckBox( IDC_TOGGLESPIN, L"Girar", 35, iY += 24, 125, 22, g_bSpinning ); } // Rejeita qualquer equipamento D3D10 que não é aceitável por retornar falso bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ){ return true; } // Crie quaisquer recursos que não são dependentes do buffer de trás HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( D3DX10CreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont ) ); V_RETURN( D3DX10CreateSprite( pd3dDevice, 512, &g_pSprite ) ); g_pTxtHelper = new CDXUTTextHelper( NULL, NULL, g_pFont, g_pSprite, 15 ); DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configura a opção D3D10_SHADER_DEBUG para embutir informãção de debug nos shaders. // Configurar esta opção melhora a experiência de debugação do shader, mas ainda permite // que os shaders sejam otimizados para executar à maneira que eles executarão na // configuração release deste programa. dwShaderFlags |= D3D10_SHADER_DEBUG; #endif // Leia o arquivo de efeito D3DX WCHAR str[MAX_PATH]; V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"..\\Tutorial10.fx" ) ); V_RETURN( D3DX10CreateEffectFromFile( str, NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ) ); // Obtém a técnica g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); g_ptxDiffuseVariable = g_pEffect->GetVariableByName( "g_txDiffuse" )->AsShaderResource(); g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); g_pPuffiness = g_pEffect->GetVariableByName( "Puffiness" )->AsScalar(); // Configura o inchaço g_pPuffiness->SetFloat( g_fModelPuffiness ); // Define o leiaute de entrada const D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); V_RETURN( pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ) ); // Configura o leiaute de entrada pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Carrega a malha V_RETURN( g_Mesh.Create( pd3dDevice, L"..\\Media\\Tiny\\tiny.sdkmesh", true ) ); // Initializa as matrizes do mundo D3DXMatrixIdentity( &g_World ); // Initializa a câmera D3DXVECTOR3 Eye( 0.0f, 0.0f, -800.0f ); D3DXVECTOR3 At( 0.0f, 0.0f, 0.0f ); g_Camera.SetViewParams( &Eye, &At ); return S_OK; } // Crie quaisquer recursos D3D10 que dependam do buffer de trás HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain *pSwapChain, const DXGI_SURFACE_DESC *pBufferSurfaceDesc, void *pUserContext) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); // Configura os parâmetros de projeção da câmera float fAspect = static_cast<float>( pBufferSurfaceDesc->Width) / static_cast<float>( pBufferSurfaceDesc->Height ); g_Camera.SetProjParams( D3DX_PI / 4, fAspect, 0.1f, 5000.0f ); g_Camera.SetWindow( pBufferSurfaceDesc->Width, pBufferSurfaceDesc->Height ); g_Camera.SetButtonMasks( MOUSE_MIDDLE_BUTTON, MOUSE_WHEEL, MOUSE_LEFT_BUTTON ); g_HUD.SetLocation( pBufferSurfaceDesc->Width -170, 0 ); g_HUD.SetSize( 170, 170 ); g_SampleUI.SetLocation( pBufferSurfaceDesc->Width - 170, pBufferSurfaceDesc->Height - 300 ); g_SampleUI.SetSize( 170, 300 ); return S_OK; } // Renderiza a cena usando o dispositivo D3D10 void CALLBACK OnD3D10FrameRender( ID3D10Device *pd3dDevice, double fTime, float fElapsedTime, void *pUserContext ) { // Limpa o buffer de trás float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // vermelho, verde, azul, alfa ID3D10RenderTargetView *pRTV = DXUTGetD3D10RenderTargetView(); pd3dDevice->ClearRenderTargetView(pRTV, ClearColor ); // Se o diálogo de configurações está sendo mostrado, então // renderiza ele ao invés de renderizar a cena da aplicação if( g_D3DSettingsDialog.IsActive() ) { g_D3DSettingsDialog.OnRender( fElapsedTime ); return; } // limpa o stencil de profundidade ID3D10DepthStencilView *pDSV = DXUTGetD3D10DepthStencilView(); pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 ); // Atualiza as variáveis que mudam uma vez por quadro g_pWorldVariable->SetMatrix( (float* )&g_World ); g_pViewVariable->SetMatrix( (float*) g_Camera.GetViewMatrix() ); g_pProjectionVariable->SetMatrix( (float*) g_Camera.GetProjMatrix() ); // Configura o leiaute de vértices pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Renderiza a malha UINT Strides[1]; UINT Offsets[1]; ID3D10Buffer* pVB[1]; pVB[0] = g_Mesh.GetVB10( 0, 0 ); Strides[0] = ( UINT ) g_Mesh.GetVertexStride(0,0); Offsets[0] = 0; pd3dDevice->IASetVertexBuffers(0, 1, pVB, Strides, Offsets); pd3dDevice->IASetIndexBuffer( g_Mesh.GetIB10( 0 ), g_Mesh.GetIBFormat10( 0 ), 0 ); D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); SDKMESH_SUBSET* pSubset = NULL; ID3D10ShaderResourceView* pDiffuseRV = NULL; D3D10_PRIMITIVE_TOPOLOGY PrimType; for( UINT p = 0; p < techDesc.Passes; ++p ){ for( UINT subset = 0; subset < g_Mesh.GetNumSubsets( 0 ); ++subset ){ pSubset = g_Mesh.GetSubset( 0, subset ); PrimType = g_Mesh.GetPrimitiveType10( ( SDKMESH_PRIMITIVE_TYPE ) pSubset->PrimitiveType ); pd3dDevice->IASetPrimitiveTopology( PrimType ); pDiffuseRV = g_Mesh.GetMaterial( pSubset->MaterialID )->pDiffuseRV10; g_ptxDiffuseVariable->SetResource( pDiffuseRV ); g_pTechnique->GetPassByIndex( p )->Apply( 0 ); pd3dDevice->DrawIndexed( ( UINT ) pSubset->IndexCount, 0, ( UINT ) pSubset->VertexStart ); } } // a classe de malha também tinha um método render que permite renderizar a malha com as opções mais comuns // g_pMesh.Render( pd3dDevice, g_pTechnique, g_ptxDiffuseVariable ); // Renderiza a UI g_HUD.OnRender( fElapsedTime ); g_SampleUI.OnRender( fElapsedTime ); RenderText(); } // Renderiza a ajuda e o texto das estatísticas void RenderText() { g_pTxtHelper->Begin(); g_pTxtHelper->SetInsertionPos( 2, 0 ); g_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); g_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) ); g_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() ); g_pTxtHelper->End(); } // Libera recursos D3D10 criados em OnD3D10ResizedSwapChain void CALLBACK OnD3D10ReleasingSwapChain( void *pUserContext ){ g_DialogResourceManager.OnD3D10ReleasingSwapChain(); } // Libera recursos D3D10 criados em OnD3D10CreateDevice void CALLBACK OnD3D10DestroyDevice( void *pUserContext ){ g_DialogResourceManager.OnD3D10DestroyDevice(); g_D3DSettingsDialog.OnD3D10DestroyDevice(); DXUTGetGlobalResourceCache().OnDestroyDevice(); SAFE_RELEASE( g_pFont ); SAFE_RELEASE( g_pSprite ); SAFE_DELETE( g_pTxtHelper ); SAFE_RELEASE( g_pVertexLayout ); SAFE_RELEASE( g_pEffect ); g_Mesh.Destroy(); } // Chamado imediatamente antes de criar um dispositivo D3D9 oy D3D10, permitindo o aplicativo modificar // as configurações do dispositivo como necessário bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings *pDeviceSettings, void *pUserContext ){ return true; } // Esta função de callback será chamada uma vez no início de todo quadro. Isto é o melhor // local para sua aplicação manusear atualizações para a cena, mas sua intenção não é // conter chamadas de renderização verdadeiras, que deveriam ser colocadas por sua vez // no callback OnFrameRender void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUsetContex ){ // Atualiza a posição da câmera baseada na entrada do usuário g_Camera.FrameMove( fElapsedTime ); if( g_bSpinning ){ D3DXMatrixRotationY( &g_World, 60.0f * DEG2RAD( (float) fTime ) ); } else { D3DXMatrixRotationY( &g_World, DEG2RAD( 180.0f ) ); } D3DXMATRIX mRot; D3DXMatrixRotationX( &mRot, DEG2RAD( -90.0f ) ); g_World = mRot *= g_World; } // Manuseia as mensagens para a aplicação LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void *pUserContext ) { // Passa as mensagens para as chamadas do gerenciador de recurso de diálogo para que // o estado da GUI seja atualizado corretamente *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe as mensagens para a configuração de diálogo se ela ainda estiver ativa if( g_D3DSettingsDialog.IsActive() ){ g_D3DSettingsDialog.MsgProc( hWnd, uMsg, wParam, lParam ); return 0; } // Dê aos diálogos uma chance de manusear a mensagem primeiro *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe todas as mensagens de janela restantes para a cãmera para que ela possa respodner à entrada do usuário g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam ); return 0; } // Manuseia pressionamentos do teclado void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ){ if( bKeyDown ){ switch( nChar ){ case VK_F1: // Change as needed break; } } } // Manuseia os eventos da GUI void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl *pControl, void *pUserContext ) { switch( nControlID ){ case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break; case IDC_TOGGLEREF: DXUTToggleREF(); break; case IDC_CHANGEDEVICE: g_D3DSettingsDialog.SetActive( !g_D3DSettingsDialog.IsActive() ); break; case IDC_TOGGLEWARP: DXUTToggleWARP(); break; case IDC_TOGGLESPIN:{ g_bSpinning = g_SampleUI.GetCheckBox( IDC_TOGGLESPIN )->GetChecked(); break; } case IDC_PUFF_SCALE: { WCHAR sz[100]; g_fModelPuffiness = (float) (g_SampleUI.GetSlider( IDC_PUFF_SCALE )->GetValue() * 0.01f ); swprintf_s( sz, 100, L"Inchaço: %0.2f", g_fModelPuffiness ); g_SampleUI.GetStatic( IDC_PUFF_STATIC )->SetText( sz ); g_pPuffiness->SetFloat( g_fModelPuffiness ); break; } } }
E o shader acompanhante que é responsável pelo efeito de inchaço da malha:
//-------------------------------------------------------------------------------------- // File: Tutorial10.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- Texture2D g_txDiffuse; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; cbuffer cbConstant { float3 vLightDir = float3(-0.577,0.577,-0.577); }; cbuffer cbChangesEveryFrame { matrix World; matrix View; matrix Projection; }; cbuffer cbUserChanges { float Puffiness; }; struct VS_INPUT { float3 Pos : POSITION; //position float3 Norm : NORMAL; //normal float2 Tex : TEXCOORD0; //texture coordinate }; struct PS_INPUT { float4 Pos : SV_POSITION; float3 Norm : TEXCOORD0; float2 Tex : TEXCOORD1; }; //-------------------------------------------------------------------------------------- // DepthStates //-------------------------------------------------------------------------------------- DepthStencilState EnableDepth { DepthEnable = TRUE; DepthWriteMask = ALL; DepthFunc = LESS_EQUAL; }; BlendState NoBlending { AlphaToCoverageEnable = FALSE; BlendEnable[0] = FALSE; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- PS_INPUT VS( VS_INPUT input ) { PS_INPUT output = (PS_INPUT)0; input.Pos += input.Norm*Puffiness; output.Pos = mul( float4(input.Pos,1), World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = mul( input.Norm, World ); output.Tex = input.Tex; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input) : SV_Target { // Calculate lighting assuming light color is <1,1,1,1> float fLighting = saturate( dot( input.Norm, vLightDir ) ); float4 outputColor = g_txDiffuse.Sample( samLinear, input.Tex ) * fLighting; outputColor.a = 1; return outputColor; } //-------------------------------------------------------------------------------------- // Technique //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); SetDepthStencilState( EnableDepth, 0 ); SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } }
Tutorial 11 - DXSDK - Vertex Shader
Mesma aplicação que o Tutorial 10. A única mudança é o Vertex shader, usado para fazer um efeito de ondulação no espaço da tela.
// Carregamento de malha através do DXUT #include "DXUT.h" #include "DXUTcamera.h" #include "DXUTgui.h" #include "DXUTsettingsDlg.h" #include "DXUTmisc.h" #include "SDKmisc.h" #include "SDKmesh.h" #define DEG2RAD( a ) ( a * D3DX_PI / 180.0f ) // Variáveis globais específicas do DXUT CModelViewerCamera g_Camera; // Uma câmera de visualização do modelo CDXUTDialogResourceManager g_DialogResourceManager; // gerente para recursos compartilhados de diálogos CD3DSettingsDlg g_D3DSettingsDialog; // diálogo de configurações do dispositivo CDXUTDialog g_HUD; // gerencia a UI 3D CDXUTDialog g_SampleUI; // diálogo para controles específicos da amostra // Variáveis globais específicas da aplicação ID3DX10Font* g_pFont = NULL; // Fonte para desenho de texto ID3DX10Sprite* g_pSprite = NULL; // SPrite para desenho de texto em lote CDXUTTextHelper* g_pTxtHelper = NULL; ID3D10Effect* g_pEffect = NULL; // interface de efeito D3DX ID3D10InputLayout* g_pVertexLayout = NULL; // Leiaute de vértice ID3D10EffectTechnique* g_pTechnique = NULL; CDXUTSDKMesh g_Mesh; ID3D10EffectShaderResourceVariable* g_ptxDiffuseVariable = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; ID3D10EffectScalarVariable* g_pWavinessVariable = NULL; ID3D10EffectScalarVariable* g_pTimeVariable = NULL; D3DXMATRIX g_World; float g_fModelWaviness; bool g_bSpinning = true; // IDs de controle da UI #define IDC_TOGGLEFULLSCREEN 1 #define IDC_TOGGLEREF 2 #define IDC_CHANGEDEVICE 3 #define IDC_TOGGLESPIN 4 #define IDC_PUFF_SCALE 5 #define IDC_PUFF_STATIC 6 #define IDC_TOGGLEWARP 7 // Protótipos das funções bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ); HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void CALLBACK OnD3D10ReleasingSwapChain( void* pUserContext ); void CALLBACK OnD3D10DestroyDevice( void* pUserContext ); void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void *pUserContext ); LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void* pUserContext); void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ); void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUserContext ); bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void *pUserContext ); void RenderText(); void InitApp(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ // Habilita checagem de memória em tempo de execução para construções debug. #if defined( DEBUG ) | defined( _DEBUG ) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif // DXUT criará e usará o melhor equipamento disponível (ou D3D9 ou D3D10) // isto é dependente do sistema disponível no qual os CALLBACKS do D3D são configurados abaixo // Configure callbacks DXUT DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable ); DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice ); DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizeSwapChain ); DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain ); DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice ); DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( OnKeyboard ); DXUTSetCallbackFrameMove( OnFrameMove ); DXUTSetCallbackDeviceChanging( ModifyDeviceSettings ); InitApp(); DXUTInit( true, true, NULL ); // Parse da linha de comando, mostra caixas de mensagem no erro, sem parâmetros de linha de comando extra DXUTSetCursorSettings(true, true ); // Mostre o cursor e recorte ele (clip) quando em modo de tela cheia DXUTCreateWindow( L"Tutorial11" ); DXUTCreateDevice( true, 640, 480 ); DXUTMainLoop(); // Entra dentro do loop de renderização DXUT return DXUTGetExitCode(); } // Inicializa a aplicação void InitApp() { g_fModelWaviness = 0.0f; g_bSpinning = true; g_D3DSettingsDialog.Init( &g_DialogResourceManager ); g_HUD.Init( &g_DialogResourceManager ); g_SampleUI.Init( &g_DialogResourceManager ); g_HUD.SetCallback( OnGUIEvent ); int iY = 10; g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Mudar para tela cheia", 35, iY, 125, 22 ); g_HUD.AddButton( IDC_CHANGEDEVICE, L"Mudar dispositivo (F2)", 35, iY += 24, 125, 22, VK_F2 ); g_HUD.AddButton( IDC_TOGGLEREF, L"Mudar para REF (F3)", 35, iY += 24, 125, 22, VK_F3 ); g_HUD.AddButton( IDC_TOGGLEWARP, L"Mudar para WARP( F4 )", 35, iY+= 24, 125, 22, VK_F4 ); g_SampleUI.SetCallback( OnGUIEvent); iY = 10; WCHAR sz[100]; iY += 24; swprintf_s( sz, 100, L"Ondulação: %0.2f", g_fModelWaviness ); g_SampleUI.AddStatic( IDC_PUFF_STATIC, sz, 35, iY += 24, 125, 22 ); g_SampleUI.AddSlider( IDC_PUFF_SCALE, 50, iY += 24, 100, 22, 0, 2000, ( int ) ( g_fModelWaviness * 100.0f ) ); iY += 24; g_SampleUI.AddCheckBox( IDC_TOGGLESPIN, L"Girar", 35, iY += 24, 125, 22, g_bSpinning ); } // Rejeita qualquer equipamento D3D10 que não é aceitável por retornar falso bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ){ return true; } // Crie quaisquer recursos que não são dependentes do buffer de trás HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( D3DX10CreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont ) ); V_RETURN( D3DX10CreateSprite( pd3dDevice, 512, &g_pSprite ) ); g_pTxtHelper = new CDXUTTextHelper( NULL, NULL, g_pFont, g_pSprite, 15 ); DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configura a opção D3D10_SHADER_DEBUG para embutir informãção de debug nos shaders. // Configurar esta opção melhora a experiência de debugação do shader, mas ainda permite // que os shaders sejam otimizados para executar à maneira que eles executarão na // configuração release deste programa. dwShaderFlags |= D3D10_SHADER_DEBUG; #endif // Ache o arquivo de efeito D3DX WCHAR str[MAX_PATH]; V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"..\\Tutorial11.fx" ) ); V_RETURN( D3DX10CreateEffectFromFile( str, NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ) ); // Obtém a técnica g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); // Obtém as variáveis g_ptxDiffuseVariable = g_pEffect->GetVariableByName( "g_txDiffuse" )->AsShaderResource(); g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); g_pWavinessVariable = g_pEffect->GetVariableByName( "Waviness" )->AsScalar(); g_pTimeVariable = g_pEffect->GetVariableByName( "Time" )->AsScalar(); // Configura a ondulação g_pWavinessVariable->SetFloat( g_fModelWaviness ); // Define o leiaute de entrada const D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); V_RETURN( pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ) ); // Configura o leiaute de entrada pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Carrega a malha V_RETURN( g_Mesh.Create( pd3dDevice, L"..\\Media\\Tiny\\tiny.sdkmesh", true ) ); // Initializa as matrizes do mundo D3DXMatrixIdentity( &g_World ); // Initializa a câmera D3DXVECTOR3 Eye( 0.0f, 0.0f, -800.0f ); D3DXVECTOR3 At( 0.0f, 0.0f, 0.0f ); g_Camera.SetViewParams( &Eye, &At ); return S_OK; } // Crie quaisquer recursos D3D10 que dependam do buffer de trás HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain *pSwapChain, const DXGI_SURFACE_DESC *pBufferSurfaceDesc, void *pUserContext) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); // Configura os parâmetros de projeção da câmera float fAspect = static_cast<float>( pBufferSurfaceDesc->Width) / static_cast<float>( pBufferSurfaceDesc->Height ); g_Camera.SetProjParams( D3DX_PI / 4, fAspect, 0.1f, 5000.0f ); g_Camera.SetWindow( pBufferSurfaceDesc->Width, pBufferSurfaceDesc->Height ); g_Camera.SetButtonMasks( MOUSE_MIDDLE_BUTTON, MOUSE_WHEEL, MOUSE_LEFT_BUTTON ); g_HUD.SetLocation( pBufferSurfaceDesc->Width -170, 0 ); g_HUD.SetSize( 170, 170 ); g_SampleUI.SetLocation( pBufferSurfaceDesc->Width - 170, pBufferSurfaceDesc->Height - 300 ); g_SampleUI.SetSize( 170, 300 ); return S_OK; } // Renderiza a cena usando o dispositivo D3D10 void CALLBACK OnD3D10FrameRender( ID3D10Device *pd3dDevice, double fTime, float fElapsedTime, void *pUserContext ) { // Se o diálogo de configurações está sendo mostrado, então // renderiza ele ao invés de renderizar a cena da aplicação if( g_D3DSettingsDialog.IsActive() ) { g_D3DSettingsDialog.OnRender( fElapsedTime ); return; } // Limpa o buffer de trás float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // vermelho, verde, azul, alfa ID3D10RenderTargetView *pRTV = DXUTGetD3D10RenderTargetView(); pd3dDevice->ClearRenderTargetView(pRTV, ClearColor ); // limpa o stencil de profundidade ID3D10DepthStencilView *pDSV = DXUTGetD3D10DepthStencilView(); pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 ); // Atualiza as variáveis que mudam uma vez por quadro g_pWorldVariable->SetMatrix( (float* )&g_World ); g_pViewVariable->SetMatrix( (float*) g_Camera.GetViewMatrix() ); g_pProjectionVariable->SetMatrix( (float*) g_Camera.GetProjMatrix() ); g_pTimeVariable->SetFloat( ( float ) fTime ); // Configura o leiaute de vértices pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Renderiza a malha UINT Strides[1]; UINT Offsets[1]; ID3D10Buffer* pVB[1]; pVB[0] = g_Mesh.GetVB10( 0, 0 ); Strides[0] = ( UINT ) g_Mesh.GetVertexStride(0,0); Offsets[0] = 0; pd3dDevice->IASetVertexBuffers(0, 1, pVB, Strides, Offsets); pd3dDevice->IASetIndexBuffer( g_Mesh.GetIB10( 0 ), g_Mesh.GetIBFormat10( 0 ), 0 ); D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); SDKMESH_SUBSET* pSubset = NULL; ID3D10ShaderResourceView* pDiffuseRV = NULL; D3D10_PRIMITIVE_TOPOLOGY PrimType; for( UINT p = 0; p < techDesc.Passes; ++p ){ for( UINT subset = 0; subset < g_Mesh.GetNumSubsets( 0 ); ++subset ){ pSubset = g_Mesh.GetSubset( 0, subset ); PrimType = g_Mesh.GetPrimitiveType10( ( SDKMESH_PRIMITIVE_TYPE ) pSubset->PrimitiveType ); pd3dDevice->IASetPrimitiveTopology( PrimType ); pDiffuseRV = g_Mesh.GetMaterial( pSubset->MaterialID )->pDiffuseRV10; g_ptxDiffuseVariable->SetResource( pDiffuseRV ); g_pTechnique->GetPassByIndex( p )->Apply( 0 ); pd3dDevice->DrawIndexed( ( UINT ) pSubset->IndexCount, 0, ( UINT ) pSubset->VertexStart ); } } // a classe de malha também tinha um método render que permite renderizar a malha com as opções mais comuns // g_pMesh.Render( pd3dDevice, g_pTechnique, g_ptxDiffuseVariable ); // Renderiza a UI g_HUD.OnRender( fElapsedTime ); g_SampleUI.OnRender( fElapsedTime ); RenderText(); } // Renderiza a ajuda e o texto das estatísticas void RenderText() { g_pTxtHelper->Begin(); g_pTxtHelper->SetInsertionPos( 2, 0 ); g_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); g_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) ); g_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() ); g_pTxtHelper->End(); } // Libera recursos D3D10 criados em OnD3D10ResizedSwapChain void CALLBACK OnD3D10ReleasingSwapChain( void *pUserContext ){ g_DialogResourceManager.OnD3D10ReleasingSwapChain(); } // Libera recursos D3D10 criados em OnD3D10CreateDevice void CALLBACK OnD3D10DestroyDevice( void *pUserContext ){ g_DialogResourceManager.OnD3D10DestroyDevice(); g_D3DSettingsDialog.OnD3D10DestroyDevice(); DXUTGetGlobalResourceCache().OnDestroyDevice(); SAFE_RELEASE( g_pFont ); SAFE_RELEASE( g_pSprite ); SAFE_DELETE( g_pTxtHelper ); SAFE_RELEASE( g_pVertexLayout ); SAFE_RELEASE( g_pEffect ); g_Mesh.Destroy(); } // Chamado imediatamente antes de criar um dispositivo D3D9 oy D3D10, permitindo o aplicativo modificar // as configurações do dispositivo como necessário bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings *pDeviceSettings, void *pUserContext ){ return true; } // Esta função de callback será chamada uma vez no início de todo quadro. Isto é o melhor // local para sua aplicação manusear atualizações para a cena, mas sua intenção não é // conter chamadas de renderização verdadeiras, que deveriam ser colocadas por sua vez // no callback OnFrameRender void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUsetContex ){ // Atualiza a posição da câmera baseada na entrada do usuário g_Camera.FrameMove( fElapsedTime ); if( g_bSpinning ){ D3DXMatrixRotationY( &g_World, 60.0f * DEG2RAD( (float) fTime ) ); } else { D3DXMatrixRotationY( &g_World, DEG2RAD( 180.0f ) ); } D3DXMATRIX mRot; D3DXMatrixRotationX( &mRot, DEG2RAD( -90.0f ) ); g_World = mRot * g_World; } // Manuseia as mensagens para a aplicação LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void *pUserContext ) { // Passa as mensagens para as chamadas do gerenciador de recurso de diálogo para que // o estado da GUI seja atualizado corretamente *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe as mensagens para a configuração de diálogo se ela ainda estiver ativa if( g_D3DSettingsDialog.IsActive() ){ g_D3DSettingsDialog.MsgProc( hWnd, uMsg, wParam, lParam ); return 0; } // Dê aos diálogos uma chance de manusear a mensagem primeiro *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe todas as mensagens de janela restantes para a cãmera para que ela possa respodner à entrada do usuário g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam ); return 0; } // Manuseia pressionamentos do teclado void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ){ } // Manuseia os eventos da GUI void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl *pControl, void *pUserContext ) { switch( nControlID ){ case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break; case IDC_TOGGLEREF: DXUTToggleREF(); break; case IDC_CHANGEDEVICE: g_D3DSettingsDialog.SetActive( !g_D3DSettingsDialog.IsActive() ); break; case IDC_TOGGLEWARP: DXUTToggleWARP(); break; case IDC_TOGGLESPIN:{ g_bSpinning = g_SampleUI.GetCheckBox( IDC_TOGGLESPIN )->GetChecked(); break; } case IDC_PUFF_SCALE: { WCHAR sz[100]; g_fModelWaviness = (float) (g_SampleUI.GetSlider( IDC_PUFF_SCALE )->GetValue() * 0.01f ); swprintf_s( sz, 100, L"Ondulação: %0.2f", g_fModelWaviness ); g_SampleUI.GetStatic( IDC_PUFF_STATIC )->SetText( sz ); g_pWavinessVariable->SetFloat( g_fModelWaviness ); break; } } }
E o arquivo de efeito responsável pela ondulação:
//-------------------------------------------------------------------------------------- // File: Tutorial11.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- Texture2D g_txDiffuse; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; cbuffer cbConstant { float3 vLightDir = float3(-0.577,0.577,-0.577); }; cbuffer cbChangesEveryFrame { matrix World; matrix View; matrix Projection; float Time; }; cbuffer cbUserChanges { float Waviness; }; struct VS_INPUT { float3 Pos : POSITION; float3 Norm : NORMAL; float2 Tex : TEXCOORD0; }; struct PS_INPUT { float4 Pos : SV_POSITION; float3 Norm : TEXCOORD0; float2 Tex : TEXCOORD1; }; //-------------------------------------------------------------------------------------- // DepthStates //-------------------------------------------------------------------------------------- DepthStencilState EnableDepth { DepthEnable = TRUE; DepthWriteMask = ALL; DepthFunc = LESS_EQUAL; }; BlendState NoBlending { AlphaToCoverageEnable = FALSE; BlendEnable[0] = FALSE; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- PS_INPUT VS( VS_INPUT input ) { PS_INPUT output = (PS_INPUT)0; output.Pos = mul( float4(input.Pos,1), World ); output.Pos.x += sin( output.Pos.y*0.1f + Time )*Waviness; output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = mul( input.Norm, World ); output.Tex = input.Tex; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input) : SV_Target { // Calculate lighting assuming light color is <1,1,1,1> float fLighting = saturate( dot( input.Norm, vLightDir ) ); float4 outputColor = g_txDiffuse.Sample( samLinear, input.Tex ) * fLighting; outputColor.a = 1; return outputColor; } //-------------------------------------------------------------------------------------- // Technique //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); SetDepthStencilState( EnableDepth, 0 ); SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } }
Tutorial 12 - DXSDK - Pixel Shader
Este tutorial tem código muito similar aos outros dois anteriores, diferenciando-se principalmente em relação ao efeito aplicado. O efeito deste tutorial usa um mapa ambiente (Environment Map) para simular reflexões.
// Carregamento de malha através do DXUT #include "DXUT.h" #include "DXUTcamera.h" #include "DXUTgui.h" #include "DXUTsettingsDlg.h" #include "DXUTmisc.h" #include "SDKmisc.h" #include "SDKmesh.h" #define DEG2RAD( a ) ( a * D3DX_PI / 180.0f ) // Variáveis globais específicas do DXUT CModelViewerCamera g_Camera; // Uma câmera de visualização do modelo CDXUTDialogResourceManager g_DialogResourceManager; // gerente para recursos compartilhados de diálogos CD3DSettingsDlg g_D3DSettingsDialog; // diálogo de configurações do dispositivo CDXUTDialog g_HUD; // gerencia a UI 3D CDXUTDialog g_SampleUI; // diálogo para controles específicos da amostra // Variáveis globais específicas da aplicação ID3DX10Font* g_pFont = NULL; // Fonte para desenho de texto ID3DX10Sprite* g_pSprite = NULL; // SPrite para desenho de texto em lote CDXUTTextHelper* g_pTxtHelper = NULL; ID3D10Effect* g_pEffect = NULL; // interface de efeito D3DX ID3D10InputLayout* g_pVertexLayout = NULL; // Leiaute de vértice ID3D10EffectTechnique* g_pTechnique = NULL; CDXUTSDKMesh g_Mesh; ID3D10ShaderResourceView* g_pEnvMapSRV; ID3D10EffectShaderResourceVariable* g_ptxDiffuseVariable = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; ID3D10EffectShaderResourceVariable* g_pEnvMapVariable = NULL; D3DXMATRIX g_World; bool g_bSpinning = true; // IDs de controle da UI #define IDC_TOGGLEFULLSCREEN 1 #define IDC_TOGGLEREF 2 #define IDC_CHANGEDEVICE 3 #define IDC_TOGGLESPIN 4 #define IDC_TOGGLEWARP 5 // Protótipos das funções bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ); HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void CALLBACK OnD3D10ReleasingSwapChain( void* pUserContext ); void CALLBACK OnD3D10DestroyDevice( void* pUserContext ); void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void *pUserContext ); LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void* pUserContext); void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ); void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUserContext ); bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void *pUserContext ); void RenderText(); void InitApp(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ // Habilita checagem de memória em tempo de execução para construções debug. #if defined( DEBUG ) | defined( _DEBUG ) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif // DXUT criará e usará o melhor equipamento disponível (ou D3D9 ou D3D10) // isto é dependente do sistema disponível no qual os CALLBACKS do D3D são configurados abaixo // Configure callbacks DXUT DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable ); DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice ); DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizeSwapChain ); DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain ); DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice ); DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( OnKeyboard ); DXUTSetCallbackFrameMove( OnFrameMove ); DXUTSetCallbackDeviceChanging( ModifyDeviceSettings ); InitApp(); DXUTInit( true, true, NULL ); // Parse da linha de comando, mostra caixas de mensagem no erro, sem parâmetros de linha de comando extra DXUTSetCursorSettings(true, true ); // Mostre o cursor e recorte ele (clip) quando em modo de tela cheia DXUTCreateWindow( L"Tutorial12" ); DXUTCreateDevice( true, 640, 480 ); DXUTMainLoop(); // Entra dentro do loop de renderização DXUT return DXUTGetExitCode(); } // Inicializa a aplicação void InitApp() { g_bSpinning = true; g_D3DSettingsDialog.Init( &g_DialogResourceManager ); g_HUD.Init( &g_DialogResourceManager ); g_SampleUI.Init( &g_DialogResourceManager ); g_HUD.SetCallback( OnGUIEvent ); int iY = 10; g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Mudar para tela cheia", 35, iY, 125, 22 ); g_HUD.AddButton( IDC_CHANGEDEVICE, L"Mudar dispositivo (F2)", 35, iY += 24, 125, 22, VK_F2 ); g_HUD.AddButton( IDC_TOGGLEREF, L"Mudar para REF (F3)", 35, iY += 24, 125, 22, VK_F3 ); g_HUD.AddButton( IDC_TOGGLEWARP, L"Mudar para WARP( F4 )", 35, iY+= 24, 125, 22, VK_F4 ); g_SampleUI.SetCallback( OnGUIEvent); iY = 10; iY += 24; g_SampleUI.AddCheckBox( IDC_TOGGLESPIN, L"Girar", 35, iY += 24, 125, 22, g_bSpinning ); } // Rejeita qualquer equipamento D3D10 que não é aceitável por retornar falso bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ){ return true; } // Crie quaisquer recursos que não são dependentes do buffer de trás HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( D3DX10CreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont ) ); V_RETURN( D3DX10CreateSprite( pd3dDevice, 512, &g_pSprite ) ); g_pTxtHelper = new CDXUTTextHelper( NULL, NULL, g_pFont, g_pSprite, 15 ); DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configura a opção D3D10_SHADER_DEBUG para embutir informãção de debug nos shaders. // Configurar esta opção melhora a experiência de debugação do shader, mas ainda permite // que os shaders sejam otimizados para executar à maneira que eles executarão na // configuração release deste programa. dwShaderFlags |= D3D10_SHADER_DEBUG; #endif // Ache o arquivo de efeito D3DX WCHAR str[MAX_PATH]; V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"..\\Tutorial12.fx" ) ); V_RETURN( D3DX10CreateEffectFromFile( str, NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ) ); // Obtém a técnica g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); // Obtém as variáveis g_ptxDiffuseVariable = g_pEffect->GetVariableByName( "g_txDiffuse" )->AsShaderResource(); g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); g_pEnvMapVariable = g_pEffect->GetVariableByName( "g_txEnvMap" )->AsShaderResource(); // Define o leiaute de entrada const D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); V_RETURN( pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ) ); // Configura o leiaute de entrada pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Carrega a malha V_RETURN( g_Mesh.Create( pd3dDevice, L"..\\Media\\Tiny\\tiny.sdkmesh", true ) ); // Initializa as matrizes do mundo D3DXMatrixIdentity( &g_World ); // Carrega o Mapa ambiente (Environment map) V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"..\\Media\\Lobby\\LobbyCube.dds" ) ); hr = D3DX10CreateShaderResourceViewFromFile( pd3dDevice, str, NULL, NULL, &g_pEnvMapSRV, NULL ); // Configura o mapa ambiente g_pEnvMapVariable->SetResource( g_pEnvMapSRV ); // Initializa a câmera D3DXVECTOR3 Eye( 0.0f, 0.0f, -800.0f ); D3DXVECTOR3 At( 0.0f, 0.0f, 0.0f ); g_Camera.SetViewParams( &Eye, &At ); return S_OK; } // Esta função de callback será chamada imediatamente quando a swapchain foi redimensionada. // Isto é normalmente em resposta a janela ser redimensionada ou às configurações de exibição // serem modificadas enquanto no modo de tela cheia. Isto dá a aplicação uma chance de criar // objetos que são dependentes da swap chain. HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain *pSwapChain, const DXGI_SURFACE_DESC *pBufferSurfaceDesc, void *pUserContext) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); // Configura os parâmetros de projeção da câmera float fAspect = static_cast<float>( pBufferSurfaceDesc->Width) / static_cast<float>( pBufferSurfaceDesc->Height ); g_Camera.SetProjParams( D3DX_PI / 4, fAspect, 0.1f, 5000.0f ); g_Camera.SetWindow( pBufferSurfaceDesc->Width, pBufferSurfaceDesc->Height ); g_Camera.SetButtonMasks( MOUSE_MIDDLE_BUTTON, MOUSE_WHEEL, MOUSE_LEFT_BUTTON ); g_HUD.SetLocation( pBufferSurfaceDesc->Width -170, 0 ); g_HUD.SetSize( 170, 170 ); g_SampleUI.SetLocation( pBufferSurfaceDesc->Width - 170, pBufferSurfaceDesc->Height - 300 ); g_SampleUI.SetSize( 170, 300 ); return S_OK; } // Esta função de callback servirá para renderizar um quadro. A apresentação é tomada conta por // DXUT agora, então não há chamada present nesta função void CALLBACK OnD3D10FrameRender( ID3D10Device *pd3dDevice, double fTime, float fElapsedTime, void *pUserContext ) { // Se o diálogo de configurações está sendo mostrado, então // renderiza ele ao invés de renderizar a cena da aplicação if( g_D3DSettingsDialog.IsActive() ) { g_D3DSettingsDialog.OnRender( fElapsedTime ); return; } // Limpa o buffer de trás float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // vermelho, verde, azul, alfa ID3D10RenderTargetView *pRTV = DXUTGetD3D10RenderTargetView(); pd3dDevice->ClearRenderTargetView(pRTV, ClearColor ); // limpa o stencil de profundidade ID3D10DepthStencilView *pDSV = DXUTGetD3D10DepthStencilView(); pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 ); // Atualiza as variáveis que mudam uma vez por quadro g_pWorldVariable->SetMatrix( (float* )&g_World ); g_pViewVariable->SetMatrix( (float*) g_Camera.GetViewMatrix() ); g_pProjectionVariable->SetMatrix( (float*) g_Camera.GetProjMatrix() ); // Configura o leiaute de vértices pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Renderiza a malha UINT Strides[1]; UINT Offsets[1]; ID3D10Buffer* pVB[1]; pVB[0] = g_Mesh.GetVB10( 0, 0 ); Strides[0] = ( UINT ) g_Mesh.GetVertexStride(0,0); Offsets[0] = 0; pd3dDevice->IASetVertexBuffers(0, 1, pVB, Strides, Offsets); pd3dDevice->IASetIndexBuffer( g_Mesh.GetIB10( 0 ), g_Mesh.GetIBFormat10( 0 ), 0 ); D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); SDKMESH_SUBSET* pSubset = NULL; ID3D10ShaderResourceView* pDiffuseRV = NULL; D3D10_PRIMITIVE_TOPOLOGY PrimType; for( UINT p = 0; p < techDesc.Passes; ++p ){ for( UINT subset = 0; subset < g_Mesh.GetNumSubsets( 0 ); ++subset ){ pSubset = g_Mesh.GetSubset( 0, subset ); PrimType = g_Mesh.GetPrimitiveType10( ( SDKMESH_PRIMITIVE_TYPE ) pSubset->PrimitiveType ); pd3dDevice->IASetPrimitiveTopology( PrimType ); pDiffuseRV = g_Mesh.GetMaterial( pSubset->MaterialID )->pDiffuseRV10; g_ptxDiffuseVariable->SetResource( pDiffuseRV ); g_pTechnique->GetPassByIndex( p )->Apply( 0 ); pd3dDevice->DrawIndexed( ( UINT ) pSubset->IndexCount, 0, ( UINT ) pSubset->VertexStart ); } } // a classe de malha também tinha um método render que permite renderizar a malha com as opções mais comuns // g_pMesh.Render( pd3dDevice, g_pTechnique, g_ptxDiffuseVariable ); // Renderiza a UI g_HUD.OnRender( fElapsedTime ); g_SampleUI.OnRender( fElapsedTime ); RenderText(); } // Renderiza a ajuda e o texto das estatísticas void RenderText() { g_pTxtHelper->Begin(); g_pTxtHelper->SetInsertionPos( 2, 0 ); g_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); g_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) ); g_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() ); g_pTxtHelper->End(); } // Libera recursos D3D10 criados em OnD3D10ResizedSwapChain void CALLBACK OnD3D10ReleasingSwapChain( void *pUserContext ){ g_DialogResourceManager.OnD3D10ReleasingSwapChain(); } // Libera recursos D3D10 criados em OnD3D10CreateDevice void CALLBACK OnD3D10DestroyDevice( void *pUserContext ){ g_DialogResourceManager.OnD3D10DestroyDevice(); g_D3DSettingsDialog.OnD3D10DestroyDevice(); DXUTGetGlobalResourceCache().OnDestroyDevice(); SAFE_RELEASE( g_pFont ); SAFE_RELEASE( g_pSprite ); SAFE_DELETE( g_pTxtHelper ); SAFE_RELEASE( g_pVertexLayout ); SAFE_RELEASE( g_pEffect ); SAFE_RELEASE( g_pEnvMapSRV ); g_Mesh.Destroy(); } // Chamado imediatamente antes de criar um dispositivo D3D9 oy D3D10, permitindo o aplicativo modificar // as configurações do dispositivo como necessário bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings *pDeviceSettings, void *pUserContext ){ return true; } // Manuseia atualizações para a cena. Isto é chamado indiferentemente de qual API D3D é usada void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUsetContex ){ // Atualiza a posição da câmera baseada na entrada do usuário g_Camera.FrameMove( fElapsedTime ); if( g_bSpinning ){ D3DXMatrixRotationY( &g_World, 60.0f * DEG2RAD( (float) fTime ) ); } else { D3DXMatrixRotationY( &g_World, DEG2RAD( 180.0f ) ); } D3DXMATRIX mRot; D3DXMatrixRotationX( &mRot, DEG2RAD( -90.0f ) ); g_World = mRot * g_World; } // Manuseia as mensagens para a aplicação LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void *pUserContext ) { // Passa as mensagens para as chamadas do gerenciador de recurso de diálogo para que // o estado da GUI seja atualizado corretamente *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe as mensagens para a configuração de diálogo se ela ainda estiver ativa if( g_D3DSettingsDialog.IsActive() ){ g_D3DSettingsDialog.MsgProc( hWnd, uMsg, wParam, lParam ); return 0; } // Dê aos diálogos uma chance de manusear a mensagem primeiro *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe todas as mensagens de janela restantes para a cãmera para que ela possa respodner à entrada do usuário g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam ); return 0; } // Manuseia pressionamentos do teclado void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ){ } // Manuseia os eventos da GUI void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl *pControl, void *pUserContext ) { switch( nControlID ){ case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break; case IDC_TOGGLEREF: DXUTToggleREF(); break; case IDC_CHANGEDEVICE: g_D3DSettingsDialog.SetActive( !g_D3DSettingsDialog.IsActive() ); break; case IDC_TOGGLEWARP: DXUTToggleWARP(); break; case IDC_TOGGLESPIN:{ g_bSpinning = g_SampleUI.GetCheckBox( IDC_TOGGLESPIN )->GetChecked(); break; } } }
E o shader ligado a ele
// // Constant Buffer Variables // Texture2D g_txDiffuse; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; TextureCube g_txEnvMap; SamplerState samLinearClamp { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; cbuffer cbConstant { float3 vLightDir = float3(-0.577,0.577,-0.577); }; cbuffer cbChangesEveryFrame { matrix World; matrix View; matrix Projection; float Time; }; cbuffer cbUserChanges { float Waviness; }; struct VS_INPUT { float3 Pos : POSITION; //position float3 Norm : NORMAL; //normal float2 Tex : TEXCOORD0; //texture coordinate }; struct PS_INPUT { float4 Pos : SV_POSITION; float3 Norm : TEXCOORD0; float2 Tex : TEXCOORD1; float3 ViewR : TEXCOORD2; }; //-------------------------------------------------------------------------------------- // DepthStates //-------------------------------------------------------------------------------------- DepthStencilState EnableDepth { DepthEnable = TRUE; DepthWriteMask = ALL; DepthFunc = LESS_EQUAL; }; BlendState NoBlending { AlphaToCoverageEnable = FALSE; BlendEnable[0] = FALSE; }; // // Vertex Shader // PS_INPUT VS( VS_INPUT input ) { PS_INPUT output = (PS_INPUT)0; output.Pos = mul( float4(input.Pos,1), World ); output.Pos.x += sin( output.Pos.y*0.1f + Time )*Waviness; output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = mul( input.Norm, (float3x3)World ); output.Tex = input.Tex; // Calculate the reflection vector float3 viewNorm = mul( output.Norm, (float3x3)View ); output.ViewR = reflect( viewNorm, float3(0,0,-1.0) ); return output; } // // Pixel Shader // float4 PS( PS_INPUT input) : SV_Target { // Calculate lighting assuming light color is <1,1,1,1> float fLighting = saturate( dot( input.Norm, vLightDir ) ); // Load the environment map texture float4 cReflect = g_txEnvMap.Sample( samLinearClamp, input.ViewR ); // Load the diffuse texture and multiply by the lighting amount float4 cDiffuse = g_txDiffuse.Sample( samLinear, input.Tex ) * fLighting; // Add diffuse to reflection and go float4 cTotal = cDiffuse + cReflect; cTotal.a = 1; return cTotal; } // // Technique // technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); SetDepthStencilState( EnableDepth, 0 ); SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } }
Tutorial 13 - DXSDK - Geometry Shader
Este tutorial é parecido com os outros três anteriores, diferenciando-se principalmente quanto ao arquivo de efeito que agora adiciona um Geometry Shader (Shader Geometria) para o pipeline para implementar um efeito de "explosão"
// Introdução para o Geometry Shader (Shader Geometria) #include "DXUT.h" #include "DXUTcamera.h" #include "DXUTgui.h" #include "DXUTsettingsDlg.h" #include "DXUTmisc.h" #include "SDKmisc.h" #include "SDKmesh.h" #define DEG2RAD( a ) ( a * D3DX_PI / 180.0f ) // Variáveis globais específicas do DXUT CModelViewerCamera g_Camera; // Uma câmera de visualização do modelo CDXUTDialogResourceManager g_DialogResourceManager; // gerente para recursos compartilhados de diálogos CD3DSettingsDlg g_D3DSettingsDialog; // diálogo de configurações do dispositivo CDXUTDialog g_HUD; // gerencia a UI 3D CDXUTDialog g_SampleUI; // diálogo para controles específicos da amostra // Variáveis globais específicas da aplicação ID3DX10Font* g_pFont = NULL; // Fonte para desenho de texto ID3DX10Sprite* g_pSprite = NULL; // SPrite para desenho de texto em lote CDXUTTextHelper* g_pTxtHelper = NULL; ID3D10Effect* g_pEffect = NULL; // interface de efeito D3DX ID3D10InputLayout* g_pVertexLayout = NULL; // Leiaute de vértice ID3D10EffectTechnique* g_pTechnique = NULL; CDXUTSDKMesh g_Mesh; ID3D10EffectShaderResourceVariable* g_ptxDiffuseVariable = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; ID3D10EffectScalarVariable* g_pExplodeVariable = NULL; D3DXMATRIX g_World; bool g_bSpinning = true; float g_fExplode = 0.0f; // IDs de controle da UI #define IDC_TOGGLEFULLSCREEN 1 #define IDC_TOGGLEREF 2 #define IDC_CHANGEDEVICE 3 #define IDC_TOGGLESPIN 4 #define IDC_EXPLODE_SCALE 5 #define IDC_EXPLODE_STATIC 6 #define IDC_TOGGLEWARP 7 // Protótipos das funções bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ); HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void CALLBACK OnD3D10ReleasingSwapChain( void* pUserContext ); void CALLBACK OnD3D10DestroyDevice( void* pUserContext ); void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void *pUserContext ); LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void* pUserContext); void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ); void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUserContext ); bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void *pUserContext ); void RenderText(); void InitApp(); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ // Habilita checagem de memória em tempo de execução para construções debug. #if defined( DEBUG ) | defined( _DEBUG ) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif // DXUT criará e usará o melhor equipamento disponível (ou D3D9 ou D3D10) // isto é dependente do sistema disponível no qual os CALLBACKS do D3D são configurados abaixo // Configure callbacks DXUT DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable ); DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice ); DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizeSwapChain ); DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain ); DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice ); DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( OnKeyboard ); DXUTSetCallbackFrameMove( OnFrameMove ); DXUTSetCallbackDeviceChanging( ModifyDeviceSettings ); InitApp(); DXUTInit( true, true, NULL ); // Parse da linha de comando, mostra caixas de mensagem no erro, sem parâmetros de linha de comando extra DXUTSetCursorSettings(true, true ); // Mostre o cursor e recorte ele (clip) quando em modo de tela cheia DXUTCreateWindow( L"Tutorial13" ); DXUTCreateDevice( true, 640, 480 ); DXUTMainLoop(); // Entra dentro do loop de renderização DXUT return DXUTGetExitCode(); } // Inicializa a aplicação void InitApp() { g_bSpinning = true; g_D3DSettingsDialog.Init( &g_DialogResourceManager ); g_HUD.Init( &g_DialogResourceManager ); g_SampleUI.Init( &g_DialogResourceManager ); g_HUD.SetCallback( OnGUIEvent ); int iY = 10; g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Mudar para tela cheia", 35, iY, 125, 22 ); g_HUD.AddButton( IDC_CHANGEDEVICE, L"Mudar dispositivo (F2)", 35, iY += 24, 125, 22, VK_F2 ); g_HUD.AddButton( IDC_TOGGLEREF, L"Mudar para REF (F3)", 35, iY += 24, 125, 22, VK_F3 ); g_HUD.AddButton( IDC_TOGGLEWARP, L"Mudar para WARP( F4 )", 35, iY+= 24, 125, 22, VK_F4 ); g_SampleUI.SetCallback( OnGUIEvent); iY = 10; WCHAR sz[100]; iY += 24; swprintf_s( sz, 100, L"Quantia para explosão: %0.2f", g_fExplode ); g_SampleUI.AddStatic( IDC_EXPLODE_STATIC, sz, 35, iY += 24, 125, 22 ); g_SampleUI.AddSlider( IDC_EXPLODE_SCALE, 50, iY += 24, 100, 22, 0, 3000, ( int )( g_fExplode * 100.0f ) ); iY += 24; g_SampleUI.AddCheckBox( IDC_TOGGLESPIN, L"Girar", 35, iY += 24, 125, 22, g_bSpinning ); } // Rejeita qualquer equipamento D3D10 que não é aceitável por retornar falso bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ){ return true; } // Crie quaisquer recursos que não são dependentes do buffer de trás HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( D3DX10CreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont ) ); V_RETURN( D3DX10CreateSprite( pd3dDevice, 512, &g_pSprite ) ); g_pTxtHelper = new CDXUTTextHelper( NULL, NULL, g_pFont, g_pSprite, 15 ); DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configura a opção D3D10_SHADER_DEBUG para embutir informãção de debug nos shaders. // Configurar esta opção melhora a experiência de debugação do shader, mas ainda permite // que os shaders sejam otimizados para executar à maneira que eles executarão na // configuração release deste programa. dwShaderFlags |= D3D10_SHADER_DEBUG; #endif // Ache o arquivo de efeito D3DX WCHAR str[MAX_PATH]; V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"..\\Tutorial13.fx" ) ); V_RETURN( D3DX10CreateEffectFromFile( str, NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ) ); // Obtém a técnica g_pTechnique = g_pEffect->GetTechniqueByName( "Render" ); // Obtém as variáveis g_ptxDiffuseVariable = g_pEffect->GetVariableByName( "g_txDiffuse" )->AsShaderResource(); g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); g_pExplodeVariable = g_pEffect->GetVariableByName( "Explode" )->AsScalar(); // Define o leiaute de entrada const D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); V_RETURN( pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pVertexLayout ) ); // Configura o leiaute de entrada pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Carrega a malha V_RETURN( g_Mesh.Create( pd3dDevice, L"..\\Media\\Tiny\\tiny.sdkmesh", true ) ); // Initializa as matrizes do mundo D3DXMatrixIdentity( &g_World ); // Initializa a câmera D3DXVECTOR3 Eye( 0.0f, 0.0f, -800.0f ); D3DXVECTOR3 At( 0.0f, 0.0f, 0.0f ); g_Camera.SetViewParams( &Eye, &At ); return S_OK; } // Cria quaisquer recursos D3D10 que dependam do buffer de trás HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain *pSwapChain, const DXGI_SURFACE_DESC *pBufferSurfaceDesc, void *pUserContext) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); // Configura os parâmetros de projeção da câmera float fAspect = static_cast<float>( pBufferSurfaceDesc->Width) / static_cast<float>( pBufferSurfaceDesc->Height ); g_Camera.SetProjParams( D3DX_PI / 4, fAspect, 0.1f, 5000.0f ); g_Camera.SetWindow( pBufferSurfaceDesc->Width, pBufferSurfaceDesc->Height ); g_Camera.SetButtonMasks( MOUSE_MIDDLE_BUTTON, MOUSE_WHEEL, MOUSE_LEFT_BUTTON ); g_HUD.SetLocation( pBufferSurfaceDesc->Width -170, 0 ); g_HUD.SetSize( 170, 170 ); g_SampleUI.SetLocation( pBufferSurfaceDesc->Width - 170, pBufferSurfaceDesc->Height - 300 ); g_SampleUI.SetSize( 170, 300 ); return S_OK; } // Renderiza a cena usando o dispositivo D3D10 void CALLBACK OnD3D10FrameRender( ID3D10Device *pd3dDevice, double fTime, float fElapsedTime, void *pUserContext ) { // Se o diálogo de configurações está sendo mostrado, então // renderiza ele ao invés de renderizar a cena da aplicação if( g_D3DSettingsDialog.IsActive() ) { g_D3DSettingsDialog.OnRender( fElapsedTime ); return; } // Limpa o buffer de trás float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // vermelho, verde, azul, alfa ID3D10RenderTargetView *pRTV = DXUTGetD3D10RenderTargetView(); pd3dDevice->ClearRenderTargetView(pRTV, ClearColor ); // limpa o stencil de profundidade ID3D10DepthStencilView *pDSV = DXUTGetD3D10DepthStencilView(); pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 ); // Atualiza as variáveis que mudam uma vez por quadro g_pWorldVariable->SetMatrix( (float* )&g_World ); g_pViewVariable->SetMatrix( (float*) g_Camera.GetViewMatrix() ); g_pProjectionVariable->SetMatrix( (float*) g_Camera.GetProjMatrix() ); // Configura o leiaute de vértices pd3dDevice->IASetInputLayout( g_pVertexLayout ); // Renderiza a malha UINT Strides[1]; UINT Offsets[1]; ID3D10Buffer* pVB[1]; pVB[0] = g_Mesh.GetVB10( 0, 0 ); Strides[0] = ( UINT ) g_Mesh.GetVertexStride(0,0); Offsets[0] = 0; pd3dDevice->IASetVertexBuffers(0, 1, pVB, Strides, Offsets); pd3dDevice->IASetIndexBuffer( g_Mesh.GetIB10( 0 ), g_Mesh.GetIBFormat10( 0 ), 0 ); D3D10_TECHNIQUE_DESC techDesc; g_pTechnique->GetDesc( &techDesc ); SDKMESH_SUBSET* pSubset = NULL; ID3D10ShaderResourceView* pDiffuseRV = NULL; D3D10_PRIMITIVE_TOPOLOGY PrimType; for( UINT p = 0; p < techDesc.Passes; ++p ){ for( UINT subset = 0; subset < g_Mesh.GetNumSubsets( 0 ); ++subset ){ pSubset = g_Mesh.GetSubset( 0, subset ); PrimType = g_Mesh.GetPrimitiveType10( ( SDKMESH_PRIMITIVE_TYPE ) pSubset->PrimitiveType ); pd3dDevice->IASetPrimitiveTopology( PrimType ); pDiffuseRV = g_Mesh.GetMaterial( pSubset->MaterialID )->pDiffuseRV10; g_ptxDiffuseVariable->SetResource( pDiffuseRV ); g_pTechnique->GetPassByIndex( p )->Apply( 0 ); pd3dDevice->DrawIndexed( ( UINT ) pSubset->IndexCount, 0, ( UINT ) pSubset->VertexStart ); } } // a classe de malha também tinha um método render que permite renderizar a malha com as opções mais comuns // g_pMesh.Render( pd3dDevice, g_pTechnique, g_ptxDiffuseVariable ); // Renderiza a UI g_HUD.OnRender( fElapsedTime ); g_SampleUI.OnRender( fElapsedTime ); RenderText(); } // Renderiza a ajuda e o texto das estatísticas void RenderText() { g_pTxtHelper->Begin(); g_pTxtHelper->SetInsertionPos( 2, 0 ); g_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); g_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) ); g_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() ); g_pTxtHelper->End(); } // Libera recursos D3D10 criados em OnD3D10ResizedSwapChain void CALLBACK OnD3D10ReleasingSwapChain( void *pUserContext ){ g_DialogResourceManager.OnD3D10ReleasingSwapChain(); } // Libera recursos D3D10 criados em OnD3D10CreateDevice void CALLBACK OnD3D10DestroyDevice( void *pUserContext ){ g_DialogResourceManager.OnD3D10DestroyDevice(); g_D3DSettingsDialog.OnD3D10DestroyDevice(); DXUTGetGlobalResourceCache().OnDestroyDevice(); SAFE_RELEASE( g_pFont ); SAFE_RELEASE( g_pSprite ); SAFE_DELETE( g_pTxtHelper ); SAFE_RELEASE( g_pVertexLayout ); SAFE_RELEASE( g_pEffect ); g_Mesh.Destroy(); } // Chamado imediatamente antes de criar um dispositivo D3D9 oy D3D10, permitindo o aplicativo modificar // as configurações do dispositivo como necessário bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings *pDeviceSettings, void *pUserContext ){ return true; } // Manuseia atualizações para a cena. Isto é chamado indiferentemente de qual API D3D é usada void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUsetContex ){ // Atualiza a posição da câmera baseada na entrada do usuário g_Camera.FrameMove( fElapsedTime ); if( g_bSpinning ){ D3DXMatrixRotationY( &g_World, 60.0f * DEG2RAD( (float) fTime ) ); } else { D3DXMatrixRotationY( &g_World, DEG2RAD( 180.0f ) ); } D3DXMATRIX mRot; D3DXMatrixRotationX( &mRot, DEG2RAD( -90.0f ) ); g_World = mRot * g_World; } // Manuseia as mensagens para a aplicação LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void *pUserContext ) { // Passa as mensagens para as chamadas do gerenciador de recurso de diálogo para que // o estado da GUI seja atualizado corretamente *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe as mensagens para a configuração de diálogo se ela ainda estiver ativa if( g_D3DSettingsDialog.IsActive() ){ g_D3DSettingsDialog.MsgProc( hWnd, uMsg, wParam, lParam ); return 0; } // Dê aos diálogos uma chance de manusear a mensagem primeiro *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe todas as mensagens de janela restantes para a cãmera para que ela possa respodner à entrada do usuário g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam ); return 0; } // Manuseia pressionamentos do teclado void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ){ } // Manuseia os eventos da GUI void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl *pControl, void *pUserContext ) { switch( nControlID ){ case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break; case IDC_TOGGLEREF: DXUTToggleREF(); break; case IDC_CHANGEDEVICE: g_D3DSettingsDialog.SetActive( !g_D3DSettingsDialog.IsActive() ); break; case IDC_TOGGLEWARP: DXUTToggleWARP(); break; case IDC_TOGGLESPIN:{ g_bSpinning = g_SampleUI.GetCheckBox( IDC_TOGGLESPIN )->GetChecked(); break; } case IDC_EXPLODE_SCALE: { WCHAR sz[100]; g_fExplode = (float) (g_SampleUI.GetSlider( IDC_EXPLODE_SCALE )->GetValue() * 0.01f ); swprintf_s( sz, 100, L"Quantia a explodir: %0.2f", g_fExplode ); g_SampleUI.GetStatic( IDC_EXPLODE_STATIC )->SetText( sz ); g_pExplodeVariable->SetFloat( g_fExplode ); break; } } }
O arquivo de efeito dele é:
//-------------------------------------------------------------------------------------- // File: Tutorial13.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- Texture2D g_txDiffuse; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; TextureCube g_txEnvMap; SamplerState samLinearClamp { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; cbuffer cbConstant { float3 vLightDir = float3(-0.577,0.577,-0.577); }; cbuffer cbChangesEveryFrame { matrix World; matrix View; matrix Projection; float Time; }; cbuffer cbUserChanges { float Explode; }; struct VS_INPUT { float3 Pos : POSITION; float3 Norm : NORMAL; float2 Tex : TEXCOORD0; }; struct GSPS_INPUT { float4 Pos : SV_POSITION; float3 Norm : TEXCOORD0; float2 Tex : TEXCOORD1; }; //-------------------------------------------------------------------------------------- // DepthStates //-------------------------------------------------------------------------------------- DepthStencilState EnableDepth { DepthEnable = TRUE; DepthWriteMask = ALL; DepthFunc = LESS_EQUAL; }; BlendState NoBlending { AlphaToCoverageEnable = FALSE; BlendEnable[0] = FALSE; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- GSPS_INPUT VS( VS_INPUT input ) { GSPS_INPUT output = (GSPS_INPUT)0; output.Pos = mul( float4(input.Pos,1), World ); output.Norm = mul( input.Norm, (float3x3)World ); output.Tex = input.Tex; return output; } //-------------------------------------------------------------------------------------- // Geometry Shader //-------------------------------------------------------------------------------------- [maxvertexcount(12)] void GS( triangle GSPS_INPUT input[3], inout TriangleStream<GSPS_INPUT> TriStream ) { GSPS_INPUT output; // // Calculate the face normal // float3 faceEdgeA = input[1].Pos - input[0].Pos; float3 faceEdgeB = input[2].Pos - input[0].Pos; float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) ); float3 ExplodeAmt = faceNormal*Explode; // // Calculate the face center // float3 centerPos = (input[0].Pos.xyz + input[1].Pos.xyz + input[2].Pos.xyz)/3.0; float2 centerTex = (input[0].Tex + input[1].Tex + input[2].Tex)/3.0; centerPos += faceNormal*Explode; // // Output the pyramid // for( int i=0; i<3; i++ ) { output.Pos = input[i].Pos + float4(ExplodeAmt,0); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = input[i].Norm; output.Tex = input[i].Tex; TriStream.Append( output ); int iNext = (i+1)%3; output.Pos = input[iNext].Pos + float4(ExplodeAmt,0); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = input[iNext].Norm; output.Tex = input[iNext].Tex; TriStream.Append( output ); output.Pos = float4(centerPos,1) + float4(ExplodeAmt,0); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = faceNormal; output.Tex = centerTex; TriStream.Append( output ); TriStream.RestartStrip(); } for( int i=2; i>=0; i-- ) { output.Pos = input[i].Pos + float4(ExplodeAmt,0); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = -input[i].Norm; output.Tex = input[i].Tex; TriStream.Append( output ); } TriStream.RestartStrip(); } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( GSPS_INPUT input) : SV_Target { // Calculate lighting assuming light color is <1,1,1,1> float fLighting = saturate( dot( input.Norm, vLightDir ) ); // Load the diffuse texture and multiply by the lighting amount float4 cDiffuse = g_txDiffuse.Sample( samLinear, input.Tex ) * fLighting; cDiffuse.a = 1; // return diffuse return cDiffuse; } //-------------------------------------------------------------------------------------- // Technique //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( CompileShader( gs_4_0, GS() ) ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); SetDepthStencilState( EnableDepth, 0 ); } }
Tutorial 14 - DXSDK - Gerenciamento de estados
Este tutorial demonstra como lidar com os estados do pipeline, os quais interagem com o buffer de profundidade, o buffer stencil e mudam a maneira como os primitivos da cena são renderizados
// Gerenciamento de estado de Render #include "DXUT.h" #include "DXUTcamera.h" #include "DXUTgui.h" #include "DXUTsettingsDlg.h" #include "DXUTmisc.h" #include "SDKmisc.h" #include "SDKmesh.h" #define DEG2RAD( a ) ( a * D3DX_PI / 180.0f ) WCHAR* g_szQuadTechniques[] = { L"RenderQuadSolid", L"RenderQuadSrcAlphaAdd", L"RenderQuadSrcAlphaSub", L"RenderQuadSrcColorAdd", L"RenderQuadSrcColorSub", }; #define MAX_QUAD_TECHNIQUES 5 WCHAR* g_szDepthStencilModes[] = { L"DepthOff/StencilOff", L"DepthLess/StencilOff", L"DepthGreater/StencilOff", L"DepthOff/StencilOnFail", L"DepthLess/StencilOnFail", L"DepthGreater/StencilOnFail", L"DepthOff/StencilOnPass", L"DepthOff/StencilOnPass", L"DepthOff/StencilOnPass", }; #define MAX_DEPTH_STENCIL_MODES 9 WCHAR* g_szRasterizerModes[] = { L"CullOff/FillSolid", L"CullFront/FillSolid", L"CullBack/FillSolid", L"CullOff/FillWire", L"CullFront/FillWire", L"CullBack/FillWire", }; #define MAX_RASTERIZER_MODES 6 /* Estaria incluso no Resource.h */ #define IDS_APP_TITLE 103 #define IDR_MAINFRAME 128 #define IDD_TUTORIAL1_DIALOG 102 #define IDD_ABOUTBOX 103 #define IDM_ABOUT 104 #define IDM_EXIT 105 #define IDI_TUTORIAL1 107 #define IDI_SMALL 108 #define IDC_TUTORIAL1 109 #define IDC_MYICON 2 #define IDC_STATIC -1 // Variáveis globais CModelViewerCamera g_Camera; // Uma câmera de visualização do modelo CDXUTDialogResourceManager g_DialogResourceManager; // gerente para recursos compartilhados de diálogos CD3DSettingsDlg g_D3DSettingsDialog; // diálogo de configurações do dispositivo CDXUTDialog g_HUD; // gerencia a UI 3D CDXUTDialog g_SampleUI; // diálogo para controles específicos da amostra ID3DX10Font* g_pFont = NULL; // Fonte para desenho de texto ID3DX10Sprite* g_pSprite = NULL; // SPrite para desenho de texto em lote CDXUTTextHelper* g_pTxtHelper = NULL; ID3D10Effect* g_pEffect = NULL; // interface de efeito D3DX ID3D10InputLayout* g_pSceneLayout = NULL; // Leiaute de vértice da cena ID3D10InputLayout* g_pQuadLayout = NULL; // Leiaute de vértice do Quad ID3D10Buffer* g_pScreenQuadVB = NULL; // Quad da tela CDXUTSDKMesh g_Mesh; ID3D10ShaderResourceView* g_pScreenRV[2] = {NULL}; UINT g_eSceneDepthStencilMode = 0; ID3D10DepthStencilState* g_pDepthStencilStates[MAX_DEPTH_STENCIL_MODES]; // estados de profundidade estêncil para não FX // gerenciamento de estado do estêncil de profundidade UINT g_eSceneRasterizerMode = 0; ID3D10RasterizerState* g_pRasterStates[MAX_RASTERIZER_MODES]; // estados do rasterizador para não FX // gerenciamento de estado do rasterizador UINT g_eQuadRenderMode = 0; ID3D10EffectTechnique* g_pTechniqueQuad[MAX_QUAD_TECHNIQUES]; // para técnicas de Quad do arquivo FX // gerenciamento de estado de mistura alfa baseado em FX ID3D10EffectTechnique* g_pTechniqueScene = NULL; // técnica FX para renderizar a cena ID3D10EffectTechnique* g_pTechniqueRenderWithStencil = NULL; // técnica FX para renderizar usando profundidade baseada em FX // gerenciamento de estado estêncil ID3D10EffectShaderResourceVariable* g_ptxDiffuseVariable = NULL; ID3D10EffectMatrixVariable* g_pWorldVariable = NULL; ID3D10EffectMatrixVariable* g_pViewVariable = NULL; ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL; ID3D10EffectScalarVariable* g_pPuffiness = NULL; D3DXMATRIX g_World; bool g_bSpinning = true; float g_fModelPuffiness = 0.0f; // estrutura descrevendo nosso vértice no espaço da tela struct SCREEN_VERTEX { D3DXVECTOR4 pos; D3DXVECTOR2 tex; }; // IDs de controle da UI #define IDC_TOGGLEFULLSCREEN 1 #define IDC_TOGGLEREF 2 #define IDC_CHANGEDEVICE 3 #define IDC_TOGGLESPIN 4 #define IDC_QUADRENDER_MODE 5 #define IDC_SCENEDEPTHSTENCIL_MODE 6 #define IDC_SCENERASTERIZER_MODE 7 #define IDC_TOGGLEWARP 8 // Protótipos das funções bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ); HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext); void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void CALLBACK OnD3D10ReleasingSwapChain( void* pUserContext ); void CALLBACK OnD3D10DestroyDevice( void* pUserContext ); void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void *pUserContext ); LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void* pUserContext); void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ); void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUserContext ); bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void *pUserContext ); void RenderText(); void InitApp(); void LoadQuadTechniques(); void LoadDepthStencilStates( ID3D10Device *pd3dDevice ); void LoadRasterizerStates( ID3D10Device *pd3dDevice ); // Ponto de entrada para o programa. Inicializa tudo e entra em um loop de processamento de // mensagem. Tempo ocioso é usado para renderizar a cena int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ){ // Habilita checagem de memória em tempo de execução para construções debug. #if defined( DEBUG ) | defined( _DEBUG ) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif // DXUT criará e usará o melhor equipamento disponível (ou D3D9 ou D3D10) // que está disponível no sistema dependendo de quais // CALLBACKS D3D são configurados abaixo // Configure callbacks DXUT DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable ); DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice ); DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizeSwapChain ); DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain ); DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice ); DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( OnKeyboard ); DXUTSetCallbackFrameMove( OnFrameMove ); DXUTSetCallbackDeviceChanging( ModifyDeviceSettings ); DXUTInit( true, true, NULL ); // Parse da linha de comando, mostra caixas de mensagem no erro, sem parâmetros de linha de comando extra DXUTSetCursorSettings(true, true ); // Mostre o cursor e recorte ele (clip) quando em modo de tela cheia InitApp(); DXUTCreateWindow( L"Tutorial14" ); DXUTCreateDevice( true, 640, 480 ); DXUTMainLoop(); // Entra dentro do loop de renderização DXUT return DXUTGetExitCode(); } // Inicializa a aplicação void InitApp() { g_fModelPuffiness = 0.0f; g_bSpinning = true; g_D3DSettingsDialog.Init( &g_DialogResourceManager ); g_HUD.Init( &g_DialogResourceManager ); g_SampleUI.Init( &g_DialogResourceManager ); g_HUD.SetCallback( OnGUIEvent ); int iY = 10; g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Mudar para tela cheia", 35, iY, 125, 22 ); g_HUD.AddButton( IDC_CHANGEDEVICE, L"Mudar dispositivo (F2)", 35, iY += 24, 125, 22, VK_F2 ); g_HUD.AddButton( IDC_TOGGLEREF, L"Mudar para REF (F3)", 35, iY += 24, 125, 22, VK_F3 ); g_HUD.AddButton( IDC_TOGGLEWARP, L"Mudar para WARP( F4 )", 35, iY+= 24, 125, 22, VK_F4 ); g_SampleUI.SetCallback( OnGUIEvent); CDXUTComboBox* pComboBox = NULL; iY = 0; g_SampleUI.AddStatic( IDC_STATIC, L"Modo de Rederizar (Q)uad", 0, iY, 200, 25 ); iY += 25; g_SampleUI.AddComboBox( IDC_QUADRENDER_MODE, 0, iY, 220, 24, 'Q', false, &pComboBox ); if( pComboBox ) pComboBox->SetDropHeight( 150 ); iY += 40; g_SampleUI.AddStatic( IDC_STATIC, L"Modo de(R)asterizador da cena", 0, iY, 200, 25 ); iY += 25; g_SampleUI.AddComboBox( IDC_SCENERASTERIZER_MODE, 0, iY, 220, 24, 'R', false, &pComboBox ); if( pComboBox ) pComboBox->SetDropHeight( 150 ); iY += 40; g_SampleUI.AddStatic( IDC_STATIC, L"Profundidade da cena/ Modo e(S)têncil", 0, iY, 200, 25 ); iY += 25; g_SampleUI.AddComboBox( IDC_SCENEDEPTHSTENCIL_MODE, 0, iY, 220, 24, 'S', false, &pComboBox ); if( pComboBox ) pComboBox->SetDropHeight( 150 ); iY += 24; g_SampleUI.AddCheckBox( IDC_TOGGLESPIN, L"Girar", 35, iY += 24, 125, 22, g_bSpinning ); } // Rejeita quaisquer dispositivos D3D10 que não são aceitáveis por retornar falso bool CALLBACK IsD3D10DeviceAcceptable( UINT adapter, UINT output, D3D10_DRIVER_TYPE DeviceType, DXGI_FORMAT BufferFormat, bool bWindowed, void *pUserContext ){ return true; } // Crie quaisquer recursos que não são dependentes do buffer de trás HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10CreateDevice( pd3dDevice ) ); V_RETURN( D3DX10CreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont ) ); V_RETURN( D3DX10CreateSprite( pd3dDevice, 512, &g_pSprite ) ); g_pTxtHelper = new CDXUTTextHelper( NULL, NULL, g_pFont, g_pSprite, 15 ); DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // Configura a opção D3D10_SHADER_DEBUG para embutir informãção de debug nos shaders. // Configurar esta opção melhora a experiência de debugação do shader, mas ainda permite // que os shaders sejam otimizados para executar à maneira que eles executarão na // configuração release deste programa. dwShaderFlags |= D3D10_SHADER_DEBUG; #endif // Ache o arquivo de efeito D3DX WCHAR str[MAX_PATH]; V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"..\\Tutorial14.fx" ) ); V_RETURN( D3DX10CreateEffectFromFile( str, NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL ) ); // Obtém os manipuladores das técnicas g_pTechniqueScene = g_pEffect->GetTechniqueByName( "RenderScene" ); g_pTechniqueRenderWithStencil = g_pEffect->GetTechniqueByName( "RenderWithStencil" ); LoadQuadTechniques(); LoadDepthStencilStates( pd3dDevice ); LoadRasterizerStates( pd3dDevice ); // Obtém as variáveis g_ptxDiffuseVariable = g_pEffect->GetVariableByName( "g_txDiffuse" )->AsShaderResource(); g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix(); g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix(); g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix(); g_pPuffiness = g_pEffect->GetVariableByName( "Puffiness" )->AsScalar(); // Configura o inchaço g_pPuffiness->SetFloat( g_fModelPuffiness ); // Define o leiaute de entrada const D3D10_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = sizeof( layout ) / sizeof( layout[0] ); // Cria o leiaute de entrada D3D10_PASS_DESC PassDesc; g_pTechniqueScene->GetPassByIndex( 0 )->GetDesc( &PassDesc ); V_RETURN( pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pSceneLayout ) ); // Carrega a malha V_RETURN( g_Mesh.Create( pd3dDevice, L"..\\Media\\Tiny\\tiny.sdkmesh", true ) ); // Initializa as matrizes do mundo D3DXMatrixIdentity( &g_World ); // Cria um quad de tela const D3D10_INPUT_ELEMENT_DESC quadLayout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; g_pTechniqueQuad[0]->GetPassByIndex(0)->GetDesc( &PassDesc ); V_RETURN( pd3dDevice->CreateInputLayout( quadLayout, 2, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pQuadLayout ) ); SCREEN_VERTEX svQuad[4]; float fSize = 1.0f; svQuad[0].pos = D3DXVECTOR4( -fSize, fSize, 0.0f, 1.0f ); svQuad[0].tex = D3DXVECTOR2( 0.0f, 0.0f ); svQuad[1].pos = D3DXVECTOR4( fSize, fSize, 0.0f, 1.0f ); svQuad[1].tex = D3DXVECTOR2( 1.0f, 0.0f ); svQuad[2].pos = D3DXVECTOR4( -fSize, -fSize, 0.0f, 1.0f ); svQuad[2].tex = D3DXVECTOR2( 0.0f, 1.0f ); svQuad[3].pos = D3DXVECTOR4( fSize, -fSize, 0.0f, 1.0f ); svQuad[3].tex = D3DXVECTOR2( 1.0f, 1.0f ); D3D10_BUFFER_DESC vbdesc = { 4 * sizeof( SCREEN_VERTEX ), D3D10_USAGE_DEFAULT, D3D10_BIND_VERTEX_BUFFER, 0, 0 }; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = svQuad; InitData.SysMemPitch = 0; InitData.SysMemSlicePitch = 0; V_RETURN( pd3dDevice->CreateBuffer( &vbdesc, &InitData, &g_pScreenQuadVB ) ); // Carrega a txetura para o quad de tela WCHAR* szScreenTextures[] = { L"..\\Media\\misc\\MarbleClouds.dds", L"..\\Media\\misc\\NormTest.dds" }; for( int i = 0; i < 2; i++ ){ V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, szScreenTextures[i] ) ); V_RETURN( D3DX10CreateShaderResourceViewFromFile( pd3dDevice, str, NULL, NULL, &g_pScreenRV[i], NULL ) ); } // Inicializa a câmera D3DXVECTOR3 Eye( 0.0f, 0.0f, -800.0f ); D3DXVECTOR3 At( 0.0f, 0.0f, 0.0f ); g_Camera.SetViewParams( &Eye, &At ); return S_OK; } // Cria quaisquer recursos D3D10 que dependam do buffer de trás HRESULT CALLBACK OnD3D10ResizeSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain *pSwapChain, const DXGI_SURFACE_DESC *pBufferSurfaceDesc, void *pUserContext) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); V_RETURN( g_D3DSettingsDialog.OnD3D10ResizedSwapChain( pd3dDevice, pBufferSurfaceDesc ) ); // Configura os parâmetros de projeção da câmera float fAspect = static_cast<float>( pBufferSurfaceDesc->Width) / static_cast<float>( pBufferSurfaceDesc->Height ); g_Camera.SetProjParams( D3DX_PI / 4, fAspect, 0.1f, 5000.0f ); g_Camera.SetWindow( pBufferSurfaceDesc->Width, pBufferSurfaceDesc->Height ); g_Camera.SetButtonMasks( MOUSE_MIDDLE_BUTTON, MOUSE_WHEEL, MOUSE_LEFT_BUTTON ); g_HUD.SetLocation( pBufferSurfaceDesc->Width -170, 0 ); g_HUD.SetSize( 170, 170 ); g_SampleUI.SetLocation( pBufferSurfaceDesc->Width - 170, pBufferSurfaceDesc->Height - 300 ); g_SampleUI.SetSize( 170, 300 ); return S_OK; } // Renderiza a cena usando o dispositivo D3D10 void CALLBACK OnD3D10FrameRender( ID3D10Device *pd3dDevice, double fTime, float fElapsedTime, void *pUserContext ) { // Se o diálogo de configurações está sendo mostrado, então // renderiza ele ao invés de renderizar a cena da aplicação if( g_D3DSettingsDialog.IsActive() ) { g_D3DSettingsDialog.OnRender( fElapsedTime ); return; } // Limpa o buffer de trás float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // vermelho, verde, azul, alfa ID3D10RenderTargetView *pRTV = DXUTGetD3D10RenderTargetView(); pd3dDevice->ClearRenderTargetView(pRTV, ClearColor ); // limpa o stencil de profundidade ID3D10DepthStencilView *pDSV = DXUTGetD3D10DepthStencilView(); pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH | D3D10_CLEAR_STENCIL, 1.0, 0 ); // Atualiza as variáveis que mudam uma vez por quadro g_pWorldVariable->SetMatrix( (float* )&g_World ); g_pViewVariable->SetMatrix( (float*) g_Camera.GetViewMatrix() ); g_pProjectionVariable->SetMatrix( (float*) g_Camera.GetProjMatrix() ); // Atualize o modo de seleção (Cull mode) (método não FX) pd3dDevice->RSSetState( g_pRasterStates[ g_eSceneRasterizerMode ] ); // Atualiza os estados de profundidade estêncil (método não FX) pd3dDevice->OMSetDepthStencilState( g_pDepthStencilStates[ g_eSceneDepthStencilMode ], 0 ); // Renderiza a malha pd3dDevice->IASetInputLayout( g_pSceneLayout ); UINT Strides[1]; UINT Offsets[1]; ID3D10Buffer* pVB[1]; pVB[0] = g_Mesh.GetVB10( 0, 0 ); Strides[0] = ( UINT ) g_Mesh.GetVertexStride(0,0); Offsets[0] = 0; pd3dDevice->IASetVertexBuffers(0, 1, pVB, Strides, Offsets); pd3dDevice->IASetIndexBuffer( g_Mesh.GetIB10( 0 ), g_Mesh.GetIBFormat10( 0 ), 0 ); D3D10_TECHNIQUE_DESC techDesc; g_pTechniqueScene->GetDesc( &techDesc ); SDKMESH_SUBSET* pSubset = NULL; ID3D10ShaderResourceView* pDiffuseRV = NULL; D3D10_PRIMITIVE_TOPOLOGY PrimType; for( UINT p = 0; p < techDesc.Passes; ++p ){ for( UINT subset = 0; subset < g_Mesh.GetNumSubsets( 0 ); ++subset ){ pSubset = g_Mesh.GetSubset( 0, subset ); PrimType = g_Mesh.GetPrimitiveType10( ( SDKMESH_PRIMITIVE_TYPE ) pSubset->PrimitiveType ); pd3dDevice->IASetPrimitiveTopology( PrimType ); pDiffuseRV = g_Mesh.GetMaterial( pSubset->MaterialID )->pDiffuseRV10; g_ptxDiffuseVariable->SetResource( pDiffuseRV ); g_pTechniqueScene->GetPassByIndex( p )->Apply( 0 ); pd3dDevice->DrawIndexed( ( UINT ) pSubset->IndexCount, 0, ( UINT ) pSubset->VertexStart ); } } // a classe de malha também tinha um método render que permite renderizar a malha com as opções mais comuns // g_pMesh.Render( pd3dDevice, g_pTechnique, g_ptxDiffuseVariable ); // Reseta a transformação do Mundo D3DXMATRIX mWorld; D3DXMatrixScaling( &mWorld, 150.0f, 150.0f, 1.0f ); g_pWorldVariable->SetMatrix( (float*) &mWorld ); // Renderiza o quadrado no espaço da tela ID3D10EffectTechnique* pTech = g_pTechniqueQuad[ g_eQuadRenderMode ]; g_ptxDiffuseVariable->SetResource( g_pScreenRV[0] ); UINT strides = sizeof( SCREEN_VERTEX ); UINT offsets = 0; ID3D10Buffer* pBuffers[1] = { g_pScreenQuadVB }; pd3dDevice->IASetInputLayout( g_pQuadLayout ); pd3dDevice->IASetVertexBuffers( 0, 1, pBuffers, &strides, &offsets ); pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ); pTech->GetDesc( &techDesc ); for( UINT uiPass = 0; uiPass < techDesc.Passes; uiPass++ ){ pTech->GetPassByIndex( 0 )->Apply( 0 ); pd3dDevice->Draw( 4, 0 ); } // renderiza o quadrado no espaço da tela de novo, mas desta vez com uma // textura diferente e somente renderize onde o buffer stencil é diferente de 0 // Olhe no arquivo FX para as configurações de estado pTech = g_pTechniqueRenderWithStencil; g_ptxDiffuseVariable->SetResource( g_pScreenRV[1] ); pd3dDevice->IASetInputLayout( g_pQuadLayout ); pd3dDevice->IASetVertexBuffers( 0, 1, pBuffers, &strides, &offsets ); pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ); pTech->GetDesc( &techDesc ); for( UINT uiPass = 0; uiPass < techDesc.Passes; uiPass++ ){ pTech->GetPassByIndex( 0 )->Apply( 0 ); pd3dDevice->Draw( 4, 0 ); } // Reconfigure nosso modo de seleção (método não FX) pd3dDevice->RSSetState( g_pRasterStates[ 0 ] ); // Reconfigure o Estado de Profundidade Estêncil pd3dDevice->OMSetDepthStencilState( g_pDepthStencilStates[ 1 ], 0 ); // Renderiza a UI g_HUD.OnRender( fElapsedTime ); g_SampleUI.OnRender( fElapsedTime ); RenderText(); } // Renderiza a ajuda e o texto das estatísticas void RenderText() { g_pTxtHelper->Begin(); g_pTxtHelper->SetInsertionPos( 2, 0 ); g_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); g_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) ); g_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() ); g_pTxtHelper->End(); } // Libera recursos D3D10 criados em OnD3D10ResizedSwapChain void CALLBACK OnD3D10ReleasingSwapChain( void *pUserContext ){ g_DialogResourceManager.OnD3D10ReleasingSwapChain(); } // Libera recursos D3D10 criados em OnD3D10CreateDevice void CALLBACK OnD3D10DestroyDevice( void *pUserContext ){ g_DialogResourceManager.OnD3D10DestroyDevice(); g_D3DSettingsDialog.OnD3D10DestroyDevice(); DXUTGetGlobalResourceCache().OnDestroyDevice(); SAFE_RELEASE( g_pFont ); SAFE_RELEASE( g_pSprite ); SAFE_DELETE( g_pTxtHelper ); SAFE_RELEASE( g_pSceneLayout ); SAFE_RELEASE( g_pQuadLayout ); SAFE_RELEASE( g_pEffect ); SAFE_RELEASE( g_pScreenQuadVB ); for( int i = 0; i < 2; i++ ){ SAFE_RELEASE( g_pScreenRV[i] ); } g_Mesh.Destroy(); for( UINT i = 0; i < MAX_DEPTH_STENCIL_MODES; i++ ){ SAFE_RELEASE( g_pDepthStencilStates[i] ); } for( UINT i = 0; i < MAX_RASTERIZER_MODES; i++ ){ SAFE_RELEASE( g_pRasterStates[i] ); } } // Chamado imediatamente antes de criar um dispositivo D3D9 oy D3D10, permitindo o aplicativo modificar // as configurações do dispositivo como necessário bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings *pDeviceSettings, void *pUserContext ){ pDeviceSettings->d3d10.AutoDepthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; return true; } // Manuseia atualizações para a cena. Isto é chamado indiferentemente de qual API D3D é usada void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void *pUsetContex ){ // Atualiza a posição da câmera baseada na entrada do usuário g_Camera.FrameMove( fElapsedTime ); if( g_bSpinning ){ D3DXMatrixRotationY( &g_World, 60.0f * DEG2RAD( (float) fTime ) ); } else { D3DXMatrixRotationY( &g_World, DEG2RAD( 180.0f ) ); } D3DXMATRIX mRot; D3DXMatrixRotationX( &mRot, DEG2RAD( -90.0f ) ); g_World = mRot * g_World; } // Manuseia as mensagens para a aplicação LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool *pbNoFurtherProcessing, void *pUserContext ) { // Passa as mensagens para as chamadas do gerenciador de recurso de diálogo para que // o estado da GUI seja atualizado corretamente *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe as mensagens para a configuração de diálogo se ela ainda estiver ativa if( g_D3DSettingsDialog.IsActive() ){ g_D3DSettingsDialog.MsgProc( hWnd, uMsg, wParam, lParam ); return 0; } // Dê aos diálogos uma chance de manusear a mensagem primeiro *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; // Passe todas as mensagens de janela restantes para a cãmera para que ela possa respodner à entrada do usuário g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam ); return 0; } // Manuseia pressionamentos do teclado void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void *pUserContext ){ if( bKeyDown ) { switch( nChar ) { case VK_F1: break; } } } // Manuseia os eventos da GUI void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl *pControl, void *pUserContext ) { switch( nControlID ){ case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break; case IDC_TOGGLEREF: DXUTToggleREF(); break; case IDC_CHANGEDEVICE: g_D3DSettingsDialog.SetActive( !g_D3DSettingsDialog.IsActive() ); break; case IDC_TOGGLEWARP: DXUTToggleWARP(); break; case IDC_TOGGLESPIN:{ g_bSpinning = g_SampleUI.GetCheckBox( IDC_TOGGLESPIN )->GetChecked(); break; } case IDC_QUADRENDER_MODE: { CDXUTComboBox* pComboBox = NULL; pComboBox = ( CDXUTComboBox* )pControl; g_eQuadRenderMode = (UINT) PtrToInt( pComboBox->GetSelectedData() ); break; } case IDC_SCENEDEPTHSTENCIL_MODE: { CDXUTComboBox* pComboBox = NULL; pComboBox = ( CDXUTComboBox* )pControl; g_eSceneDepthStencilMode = (UINT) PtrToInt( pComboBox->GetSelectedData() ); break; } case IDC_SCENERASTERIZER_MODE: { CDXUTComboBox* pComboBox = NULL; pComboBox = ( CDXUTComboBox* )pControl; g_eSceneRasterizerMode = (UINT) PtrToInt( pComboBox->GetSelectedData() ); break; } } } // LoadQuadTechniques // Carrega as técnicas para renderizar o quad do arquivo FX. As técnicas no // arquivo FX contêm a configuração de estado de mistura alfa void LoadQuadTechniques() { for( UINT i = 0; i < MAX_QUAD_TECHNIQUES; i++ ){ char mbstr[MAX_PATH]; WideCharToMultiByte( CP_ACP, 0, g_szQuadTechniques[i], -1, mbstr, MAX_PATH, 0, 0 ); g_pTechniqueQuad[i] = g_pEffect->GetTechniqueByName( mbstr ); g_SampleUI.GetComboBox( IDC_QUADRENDER_MODE )->AddItem( g_szQuadTechniques[i], (void*) (UINT64) i ); } } // LoadDepthStencilStates // Cria um conjunto de estados de profundidade estêncil para gerenciamento de estado não-FX. Estes estados // mais tarde serão configurados usando OMSetDepthStencilState em OnD3D10FrameRender. void LoadDepthStencilStates( ID3D10Device* pd3dDevice ){ BOOL bDepthEnable[ MAX_DEPTH_STENCIL_MODES ] = { FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE }; BOOL bStencilEnable[ MAX_DEPTH_STENCIL_MODES ] = { FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }; D3D10_COMPARISON_FUNC compFunc[ MAX_DEPTH_STENCIL_MODES ] = { D3D10_COMPARISON_LESS, D3D10_COMPARISON_LESS, D3D10_COMPARISON_GREATER, D3D10_COMPARISON_LESS, D3D10_COMPARISON_LESS, D3D10_COMPARISON_GREATER, D3D10_COMPARISON_LESS, D3D10_COMPARISON_LESS, D3D10_COMPARISON_GREATER, }; D3D10_STENCIL_OP FailOp[ MAX_DEPTH_STENCIL_MODES ] = { D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_INCR, D3D10_STENCIL_OP_INCR, D3D10_STENCIL_OP_INCR, D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_KEEP, }; D3D10_STENCIL_OP PassOp[ MAX_DEPTH_STENCIL_MODES ] = { D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_KEEP, D3D10_STENCIL_OP_INCR, D3D10_STENCIL_OP_INCR, D3D10_STENCIL_OP_INCR, }; for( UINT i = 0; i < MAX_DEPTH_STENCIL_MODES; i++ ) { D3D10_DEPTH_STENCIL_DESC dsDesc; dsDesc.DepthEnable = bDepthEnable[i]; dsDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL; dsDesc.DepthFunc = compFunc[i]; // parâmetros de teste do estêncil dsDesc.StencilEnable = bStencilEnable[i]; dsDesc.StencilReadMask = 0xFF; dsDesc.StencilWriteMask = 0xFF; // operações estêncil se pixel está encarando de frente dsDesc.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; dsDesc.FrontFace.StencilDepthFailOp = FailOp[i]; dsDesc.FrontFace.StencilPassOp = PassOp[i]; dsDesc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS; // operações estêncil se pixel está encarando de trás dsDesc.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; dsDesc.BackFace.StencilDepthFailOp = FailOp[i]; dsDesc.BackFace.StencilPassOp = PassOp[i]; dsDesc.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS; // Cria o estado de profundidade estêncil pd3dDevice->CreateDepthStencilState( &dsDesc, &g_pDepthStencilStates[i] ); g_SampleUI.GetComboBox( IDC_SCENEDEPTHSTENCIL_MODE )->AddItem( g_szDepthStencilModes[i], ( void* ) (UINT64 ) i ); } } // LoadRasterizerStates // Crie um conjunto de estados de rasterizador para gerenciamento de estado não-FX. Estes // estados serão configurados mais tarde por usar RSSetState em OND3DFrameRender. void LoadRasterizerStates( ID3D10Device* pd3dDevice ){ D3D10_FILL_MODE fill[MAX_RASTERIZER_MODES] = { D3D10_FILL_SOLID, D3D10_FILL_SOLID, D3D10_FILL_SOLID, D3D10_FILL_WIREFRAME, D3D10_FILL_WIREFRAME, D3D10_FILL_WIREFRAME }; D3D10_CULL_MODE cull[MAX_RASTERIZER_MODES]= { D3D10_CULL_NONE, D3D10_CULL_FRONT, D3D10_CULL_BACK, D3D10_CULL_NONE, D3D10_CULL_FRONT, D3D10_CULL_BACK }; for( UINT i = 0; i < MAX_RASTERIZER_MODES; i++ ){ D3D10_RASTERIZER_DESC rasterizerState; rasterizerState.FillMode = fill[i]; rasterizerState.CullMode = cull[i]; rasterizerState.FrontCounterClockwise = false; rasterizerState.DepthBias = false; rasterizerState.DepthBiasClamp = 0; rasterizerState.SlopeScaledDepthBias = 0; rasterizerState.DepthClipEnable = true; rasterizerState.ScissorEnable = false; rasterizerState.MultisampleEnable = false; rasterizerState.AntialiasedLineEnable = false; pd3dDevice->CreateRasterizerState( &rasterizerState, &g_pRasterStates[i] ); g_SampleUI.GetComboBox( IDC_SCENERASTERIZER_MODE )->AddItem( g_szRasterizerModes[i] , (void *) (UINT64) i ); } }
E o shader acompanhante
//-------------------------------------------------------------------------------------- // File: Tutorial14.fx // // Copyright (c) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- Texture2D g_txDiffuse; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; cbuffer cbConstant { float3 vLightDir = float3(-0.577,0.577,-0.577); }; cbuffer cbChangesEveryFrame { matrix World; matrix View; matrix Projection; }; struct VS_INPUT { float3 Pos : POSITION; //position float3 Norm : NORMAL; //normal float2 Tex : TEXCOORD0; //texture coordinate }; struct PS_INPUT { float4 Pos : SV_POSITION; float3 Norm : TEXCOORD0; float2 Tex : TEXCOORD1; }; struct QUADVS_INPUT { float4 Pos : POSITION; float2 Tex : TEXCOORD0; }; struct QUADVS_OUTPUT { float4 Pos : SV_POSITION; // Transformed position float2 Tex : TEXCOORD0; }; //-------------------------------------------------------------------------------------- // Blending States //-------------------------------------------------------------------------------------- BlendState NoBlending { BlendEnable[0] = FALSE; }; BlendState SrcAlphaBlendingAdd { BlendEnable[0] = TRUE; SrcBlend = SRC_ALPHA; DestBlend = ONE; BlendOp = ADD; SrcBlendAlpha = ZERO; DestBlendAlpha = ZERO; BlendOpAlpha = ADD; RenderTargetWriteMask[0] = 0x0F; }; BlendState SrcAlphaBlendingSub { BlendEnable[0] = TRUE; SrcBlend = SRC_ALPHA; DestBlend = ONE; BlendOp = SUBTRACT; SrcBlendAlpha = ZERO; DestBlendAlpha = ZERO; BlendOpAlpha = ADD; RenderTargetWriteMask[0] = 0x0F; }; BlendState SrcColorBlendingAdd { BlendEnable[0] = TRUE; SrcBlend = SRC_COLOR; DestBlend = ONE; BlendOp = ADD; SrcBlendAlpha = ZERO; DestBlendAlpha = ZERO; BlendOpAlpha = ADD; RenderTargetWriteMask[0] = 0x0F; }; BlendState SrcColorBlendingSub { BlendEnable[0] = TRUE; SrcBlend = SRC_COLOR; DestBlend = ONE; BlendOp = SUBTRACT; SrcBlendAlpha = ZERO; DestBlendAlpha = ZERO; BlendOpAlpha = ADD; RenderTargetWriteMask[0] = 0x0F; }; //-------------------------------------------------------------------------------------- // Depth/Stencil States //-------------------------------------------------------------------------------------- DepthStencilState RenderWithStencilState { DepthEnable = false; DepthWriteMask = ZERO; DepthFunc = Less; // Setup stencil states StencilEnable = true; StencilReadMask = 0xFF; StencilWriteMask = 0x00; FrontFaceStencilFunc = Not_Equal; FrontFaceStencilPass = Keep; FrontFaceStencilFail = Zero; BackFaceStencilFunc = Not_Equal; BackFaceStencilPass = Keep; BackFaceStencilFail = Zero; }; //-------------------------------------------------------------------------------------- // Scene Vertex Shader //-------------------------------------------------------------------------------------- PS_INPUT VS( VS_INPUT input ) { PS_INPUT output = (PS_INPUT)0; output.Pos = mul( float4(input.Pos,1), World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); output.Norm = mul( input.Norm, World ); output.Tex = input.Tex; return output; } //----------------------------------------------------------------------------- // Quad Vertex Shaders //----------------------------------------------------------------------------- QUADVS_OUTPUT QuadVS( QUADVS_INPUT Input ) { QUADVS_OUTPUT Output; Output.Pos = mul( Input.Pos, World ); Output.Pos = mul( Output.Pos, View ); Output.Pos = mul( Output.Pos, Projection ); Output.Tex = Input.Tex; return Output; } QUADVS_OUTPUT ScreenQuadVS( QUADVS_INPUT Input ) { QUADVS_OUTPUT Output; Output.Pos = Input.Pos; Output.Tex = Input.Tex; return Output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input) : SV_Target { // Calculate lighting assuming light color is <1,1,1,1> float fLighting = saturate( dot( input.Norm, vLightDir ) ); float4 outputColor = g_txDiffuse.Sample( samLinear, input.Tex ) * fLighting; outputColor.a = 1; return outputColor; } //-------------------------------------------------------------------------------------- // Quad Pixel Shader //-------------------------------------------------------------------------------------- float4 QuadPS( QUADVS_OUTPUT input) : SV_Target { return g_txDiffuse.Sample( samLinear, input.Tex ); } //-------------------------------------------------------------------------------------- // Scene Techniques //-------------------------------------------------------------------------------------- technique10 RenderScene { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } } //-------------------------------------------------------------------------------------- // RenderWithStencil - set the depth stencil state inside of the technique //-------------------------------------------------------------------------------------- technique10 RenderWithStencil { pass P0 { SetVertexShader( CompileShader( vs_4_0, ScreenQuadVS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, QuadPS() ) ); SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); SetDepthStencilState( RenderWithStencilState, 0 ); } } //-------------------------------------------------------------------------------------- // Quad Techniques: Alpha blending state is set inside the technique //-------------------------------------------------------------------------------------- technique10 RenderQuadSolid { pass P0 { SetVertexShader( CompileShader( vs_4_0, QuadVS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, QuadPS() ) ); SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } } //-------------------------------------------------------------------------------------- technique10 RenderQuadSrcAlphaAdd { pass P0 { SetVertexShader( CompileShader( vs_4_0, QuadVS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, QuadPS() ) ); SetBlendState( SrcAlphaBlendingAdd, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } } //-------------------------------------------------------------------------------------- technique10 RenderQuadSrcAlphaSub { pass P0 { SetVertexShader( CompileShader( vs_4_0, QuadVS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, QuadPS() ) ); SetBlendState( SrcAlphaBlendingSub, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } } //-------------------------------------------------------------------------------------- technique10 RenderQuadSrcColorAdd { pass P0 { SetVertexShader( CompileShader( vs_4_0, QuadVS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, QuadPS() ) ); SetBlendState( SrcColorBlendingAdd, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } } //-------------------------------------------------------------------------------------- technique10 RenderQuadSrcColorSub { pass P0 { SetVertexShader( CompileShader( vs_4_0, QuadVS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, QuadPS() ) ); SetBlendState( SrcColorBlendingSub, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); } }