• 12
• 12
• 9
• 10
• 13
• ### Similar Content

• By elect
Hi,
ok, so, we are having problems with our current mirror reflection implementation.
At the moment we are doing it very simple, so for the i-th frame, we calculate the reflection vectors given the viewPoint and some predefined points on the mirror surface (position and normal).
Then, using the least squared algorithm, we find the point that has the minimum distance from all these reflections vectors. This is going to be our virtual viewPoint (with the right orientation).
After that, we render offscreen to a texture by setting the OpenGL camera on the virtual viewPoint.
And finally we use the rendered texture on the mirror surface.
So far this has always been fine, but now we are having some more strong constraints on accuracy.
What are our best options given that:
- we have a dynamic scene, the mirror and parts of the scene can change continuously from frame to frame
- we have about 3k points (with normals) per mirror, calculated offline using some cad program (such as Catia)
- all the mirror are always perfectly spherical (with different radius vertically and horizontally) and they are always convex
- a scene can have up to 10 mirror
- it should be fast enough also for vr (Htc Vive) on fastest gpus (only desktops)

Looking around, some papers talk about calculating some caustic surface derivation offline, but I don't know if this suits my case
Also, another paper, used some acceleration structures to detect the intersection between the reflection vectors and the scene, and then adjust the corresponding texture coordinate. This looks the most accurate but also very heavy from a computational point of view.

Other than that, I couldn't find anything updated/exhaustive around, can you help me?

• Hello all,
I am currently working on a game engine for use with my game development that I would like to be as flexible as possible.  As such the exact requirements for how things should work can't be nailed down to a specific implementation and I am looking for, at least now, a default good average case scenario design.
Here is what I have implemented:
Deferred rendering using OpenGL Arbitrary number of lights and shadow mapping Each rendered object, as defined by a set of geometry, textures, animation data, and a model matrix is rendered with its own draw call Skeletal animations implemented on the GPU.   Model matrix transformation implemented on the GPU Frustum and octree culling for optimization Here are my questions and concerns:
Doing the skeletal animation on the GPU, currently, requires doing the skinning for each object multiple times per frame: once for the initial geometry rendering and once for the shadow map rendering for each light for which it is not culled.  This seems very inefficient.  Is there a way to do skeletal animation on the GPU only once across these render calls? Without doing the model matrix transformation on the CPU, I fail to see how I can easily batch objects with the same textures and shaders in a single draw call without passing a ton of matrix data to the GPU (an array of model matrices then an index for each vertex into that array for transformation purposes?) If I do the matrix transformations on the CPU, It seems I can't really do the skinning on the GPU as the pre-transformed vertexes will wreck havoc with the calculations, so this seems not viable unless I am missing something Overall it seems like simplest solution is to just do all of the vertex manipulation on the CPU and pass the pre-transformed data to the GPU, using vertex shaders that do basically nothing.  This doesn't seem the most efficient use of the graphics hardware, but could potentially reduce the number of draw calls needed.

Really, I am looking for some advice on how to proceed with this, how something like this is typically handled.  Are the multiple draw calls and skinning calculations not a huge deal?  I would LIKE to save as much of the CPU's time per frame so it can be tasked with other things, as to keep CPU resources open to the implementation of the engine.  However, that becomes a moot point if the GPU becomes a bottleneck.

• Hello!
I would like to introduce Diligent Engine, a project that I've been recently working on. Diligent Engine is a light-weight cross-platform abstraction layer between the application and the platform-specific graphics API. Its main goal is to take advantages of the next-generation APIs such as Direct3D12 and Vulkan, but at the same time provide support for older platforms via Direct3D11, OpenGL and OpenGLES. Diligent Engine exposes common front-end for all supported platforms and provides interoperability with underlying native API. Shader source code converter allows shaders authored in HLSL to be translated to GLSL and used on all platforms. Diligent Engine supports integration with Unity and is designed to be used as a graphics subsystem in a standalone game engine, Unity native plugin or any other 3D application. It is distributed under Apache 2.0 license and is free to use. Full source code is available for download on GitHub.
Features:
True cross-platform Exact same client code for all supported platforms and rendering backends No #if defined(_WIN32) ... #elif defined(LINUX) ... #elif defined(ANDROID) ... No #if defined(D3D11) ... #elif defined(D3D12) ... #elif defined(OPENGL) ... Exact same HLSL shaders run on all platforms and all backends Modular design Components are clearly separated logically and physically and can be used as needed Only take what you need for your project (do not want to keep samples and tutorials in your codebase? Simply remove Samples submodule. Only need core functionality? Use only Core submodule) No 15000 lines-of-code files Clear object-based interface No global states Key graphics features: Automatic shader resource binding designed to leverage the next-generation rendering APIs Multithreaded command buffer generation 50,000 draw calls at 300 fps with D3D12 backend Descriptor, memory and resource state management Modern c++ features to make code fast and reliable The following platforms and low-level APIs are currently supported:
Windows Desktop: Direct3D11, Direct3D12, OpenGL Universal Windows: Direct3D11, Direct3D12 Linux: OpenGL Android: OpenGLES MacOS: OpenGL iOS: OpenGLES API Basics
Initialization
The engine can perform initialization of the API or attach to already existing D3D11/D3D12 device or OpenGL/GLES context. For instance, the following code shows how the engine can be initialized in D3D12 mode:
#include "RenderDeviceFactoryD3D12.h" using namespace Diligent; // ...  GetEngineFactoryD3D12Type GetEngineFactoryD3D12 = nullptr; // Load the dll and import GetEngineFactoryD3D12() function LoadGraphicsEngineD3D12(GetEngineFactoryD3D12); auto *pFactoryD3D11 = GetEngineFactoryD3D12(); EngineD3D12Attribs EngD3D12Attribs; EngD3D12Attribs.CPUDescriptorHeapAllocationSize[0] = 1024; EngD3D12Attribs.CPUDescriptorHeapAllocationSize[1] = 32; EngD3D12Attribs.CPUDescriptorHeapAllocationSize[2] = 16; EngD3D12Attribs.CPUDescriptorHeapAllocationSize[3] = 16; EngD3D12Attribs.NumCommandsToFlushCmdList = 64; RefCntAutoPtr<IRenderDevice> pRenderDevice; RefCntAutoPtr<IDeviceContext> pImmediateContext; SwapChainDesc SwapChainDesc; RefCntAutoPtr<ISwapChain> pSwapChain; pFactoryD3D11->CreateDeviceAndContextsD3D12( EngD3D12Attribs, &pRenderDevice, &pImmediateContext, 0 ); pFactoryD3D11->CreateSwapChainD3D12( pRenderDevice, pImmediateContext, SwapChainDesc, hWnd, &pSwapChain ); Creating Resources
Device resources are created by the render device. The two main resource types are buffers, which represent linear memory, and textures, which use memory layouts optimized for fast filtering. To create a buffer, you need to populate BufferDesc structure and call IRenderDevice::CreateBuffer(). The following code creates a uniform (constant) buffer:
BufferDesc BuffDesc; BufferDesc.Name = "Uniform buffer"; BuffDesc.BindFlags = BIND_UNIFORM_BUFFER; BuffDesc.Usage = USAGE_DYNAMIC; BuffDesc.uiSizeInBytes = sizeof(ShaderConstants); BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE; m_pDevice->CreateBuffer( BuffDesc, BufferData(), &m_pConstantBuffer ); Similar, to create a texture, populate TextureDesc structure and call IRenderDevice::CreateTexture() as in the following example:
TextureDesc TexDesc; TexDesc.Name = "My texture 2D"; TexDesc.Type = TEXTURE_TYPE_2D; TexDesc.Width = 1024; TexDesc.Height = 1024; TexDesc.Format = TEX_FORMAT_RGBA8_UNORM; TexDesc.Usage = USAGE_DEFAULT; TexDesc.BindFlags = BIND_SHADER_RESOURCE | BIND_RENDER_TARGET | BIND_UNORDERED_ACCESS; TexDesc.Name = "Sample 2D Texture"; m_pRenderDevice->CreateTexture( TexDesc, TextureData(), &m_pTestTex ); Initializing Pipeline State
Diligent Engine follows Direct3D12 style to configure the graphics/compute pipeline. One big Pipelines State Object (PSO) encompasses all required states (all shader stages, input layout description, depth stencil, rasterizer and blend state descriptions etc.)
To create a shader, populate ShaderCreationAttribs structure. An important member is ShaderCreationAttribs::SourceLanguage. The following are valid values for this member:
SHADER_SOURCE_LANGUAGE_DEFAULT  - The shader source format matches the underlying graphics API: HLSL for D3D11 or D3D12 mode, and GLSL for OpenGL and OpenGLES modes. SHADER_SOURCE_LANGUAGE_HLSL  - The shader source is in HLSL. For OpenGL and OpenGLES modes, the source code will be converted to GLSL. See shader converter for details. SHADER_SOURCE_LANGUAGE_GLSL  - The shader source is in GLSL. There is currently no GLSL to HLSL converter. To allow grouping of resources based on the frequency of expected change, Diligent Engine introduces classification of shader variables:
Static variables (SHADER_VARIABLE_TYPE_STATIC) are variables that are expected to be set only once. They may not be changed once a resource is bound to the variable. Such variables are intended to hold global constants such as camera attributes or global light attributes constant buffers. Mutable variables (SHADER_VARIABLE_TYPE_MUTABLE) define resources that are expected to change on a per-material frequency. Examples may include diffuse textures, normal maps etc. Dynamic variables (SHADER_VARIABLE_TYPE_DYNAMIC) are expected to change frequently and randomly. This post describes the resource binding model in Diligent Engine.
The following is an example of shader initialization:
To create a pipeline state object, define instance of PipelineStateDesc structure. The structure defines the pipeline specifics such as if the pipeline is a compute pipeline, number and format of render targets as well as depth-stencil format:
// This is a graphics pipeline PSODesc.IsComputePipeline = false; PSODesc.GraphicsPipeline.NumRenderTargets = 1; PSODesc.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_RGBA8_UNORM_SRGB; PSODesc.GraphicsPipeline.DSVFormat = TEX_FORMAT_D32_FLOAT; The structure also defines depth-stencil, rasterizer, blend state, input layout and other parameters. For instance, rasterizer state can be defined as in the code snippet below:
// Init rasterizer state RasterizerStateDesc &RasterizerDesc = PSODesc.GraphicsPipeline.RasterizerDesc; RasterizerDesc.FillMode = FILL_MODE_SOLID; RasterizerDesc.CullMode = CULL_MODE_NONE; RasterizerDesc.FrontCounterClockwise = True; RasterizerDesc.ScissorEnable = True; //RSDesc.MultisampleEnable = false; // do not allow msaa (fonts would be degraded) RasterizerDesc.AntialiasedLineEnable = False; When all fields are populated, call IRenderDevice::CreatePipelineState() to create the PSO:
Shader resource binding in Diligent Engine is based on grouping variables in 3 different groups (static, mutable and dynamic). Static variables are variables that are expected to be set only once. They may not be changed once a resource is bound to the variable. Such variables are intended to hold global constants such as camera attributes or global light attributes constant buffers. They are bound directly to the shader object:

m_pPSO->CreateShaderResourceBinding(&m_pSRB); Dynamic and mutable resources are then bound through SRB object:
m_pSRB->GetVariable(SHADER_TYPE_VERTEX, "tex2DDiffuse")->Set(pDiffuseTexSRV); m_pSRB->GetVariable(SHADER_TYPE_VERTEX, "cbRandomAttribs")->Set(pRandomAttrsCB); The difference between mutable and dynamic resources is that mutable ones can only be set once for every instance of a shader resource binding. Dynamic resources can be set multiple times. It is important to properly set the variable type as this may affect performance. Static variables are generally most efficient, followed by mutable. Dynamic variables are most expensive from performance point of view. This post explains shader resource binding in more details.
Setting the Pipeline State and Invoking Draw Command
Before any draw command can be invoked, all required vertex and index buffers as well as the pipeline state should be bound to the device context:
// Clear render target const float zero[4] = {0, 0, 0, 0}; m_pContext->ClearRenderTarget(nullptr, zero); // Set vertex and index buffers IBuffer *buffer[] = {m_pVertexBuffer}; Uint32 offsets[] = {0}; Uint32 strides[] = {sizeof(MyVertex)}; m_pContext->SetVertexBuffers(0, 1, buffer, strides, offsets, SET_VERTEX_BUFFERS_FLAG_RESET); m_pContext->SetIndexBuffer(m_pIndexBuffer, 0); m_pContext->SetPipelineState(m_pPSO); Also, all shader resources must be committed to the device context:
m_pContext->CommitShaderResources(m_pSRB, COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES); When all required states and resources are bound, IDeviceContext::Draw() can be used to execute draw command or IDeviceContext::DispatchCompute() can be used to execute compute command. Note that for a draw command, graphics pipeline must be bound, and for dispatch command, compute pipeline must be bound. Draw() takes DrawAttribs structure as an argument. The structure members define all attributes required to perform the command (primitive topology, number of vertices or indices, if draw call is indexed or not, if draw call is instanced or not, if draw call is indirect or not, etc.). For example:
DrawAttribs attrs; attrs.IsIndexed = true; attrs.IndexType = VT_UINT16; attrs.NumIndices = 36; attrs.Topology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; pContext->Draw(attrs); Tutorials and Samples
The GitHub repository contains a number of tutorials and sample applications that demonstrate the API usage.

AntTweakBar sample demonstrates how to use AntTweakBar library to create simple user interface.

Atmospheric scattering sample is a more advanced example. It demonstrates how Diligent Engine can be used to implement various rendering tasks: loading textures from files, using complex shaders, rendering to textures, using compute shaders and unordered access views, etc.

The repository includes Asteroids performance benchmark based on this demo developed by Intel. It renders 50,000 unique textured asteroids and lets compare performance of D3D11 and D3D12 implementations. Every asteroid is a combination of one of 1000 unique meshes and one of 10 unique textures.

Integration with Unity
Diligent Engine supports integration with Unity through Unity low-level native plugin interface. The engine relies on Native API Interoperability to attach to the graphics API initialized by Unity. After Diligent Engine device and context are created, they can be used us usual to create resources and issue rendering commands. GhostCubePlugin shows an example how Diligent Engine can be used to render a ghost cube only visible as a reflection in a mirror.

• By Yxjmir
I'm trying to load data from a .gltf file into a struct to use to load a .bin file. I don't think there is a problem with how the vertex positions are loaded, but with the indices. This is what I get when drawing with glDrawArrays(GL_LINES, ...):

Also, using glDrawElements gives a similar result. Since it looks like its drawing triangles using the wrong vertices for each face, I'm assuming it needs an index buffer/element buffer. (I'm not sure why there is a line going through part of it, it doesn't look like it belongs to a side, re-exported it without texture coordinates checked, and its not there)
I'm using jsoncpp to load the GLTF file, its format is based on JSON. Here is the gltf struct I'm using, and how I parse the file:
glBindVertexArray(g_pGame->m_VAO);
glDrawElements(GL_LINES, g_pGame->m_indices.size(), GL_UNSIGNED_BYTE, (void*)0); // Only shows with GL_UNSIGNED_BYTE
glDrawArrays(GL_LINES, 0, g_pGame->m_vertexCount);
So, I'm asking what type should I use for the indices? it doesn't seem to be unsigned short, which is what I selected with the Khronos Group Exporter for blender. Also, am I reading part or all of the .bin file wrong?
Test.gltf
Test.bin

• That means how do I use base DirectX or OpenGL api's to make a physics based destruction simulation?
Will it be just smart rendering or something else is required?

This topic is 4588 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I've downloaded some of the tutorials from : http://triplebuffer.devmaster.net/tutorials/stepping1.php (Tutorial 2 - Creating a triangle) And I'm having trouble compiling them. I've downloaded and installed the directx 9.0 sdk, and linked to the includes and libs, but I get the following errors. Oh and by the way, I've just finished learning c++ and this is my first time trying out directx, so I'd appreciate it if I could have the dumbed down explanation :) Anyway, the errors are: [Linker error] undefined reference to _Z20MainMessageProcedureP6HWND__jjl@16' [Linker error] undefined reference to Direct3DCreate9@4' [Linker error] undefined reference to `WinMain@16' And the errors are in MyApplication.h Incase they're needed, here are the files: MyApplication.cpp: ----- #include "MyApplication.h" LRESULT WINAPI MainMessageProcedure(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam); CMyApplication::CMyApplication() { // Initialize all the member variables m_hWnd = NULL; m_bPaused = FALSE; m_bAlive = TRUE; m_bActive = TRUE; m_bWindowed = FALSE; m_iWndWidth = 500; m_iWndHeight = 400; strcpy(m_strTitle, "Triple Buffer FVFs, Vertex Buffers"); strcpy(m_strClass, "TripleBuffer"); m_pD3D = NULL; m_pD3DDevice = NULL; ZeroMemory(&m_d3dpp, sizeof(D3DPRESENT_PARAMETERS)); ZeroMemory(&m_d3ddcp, sizeof(D3DDEVICE_CREATION_PARAMETERS)); } CMyApplication::~CMyApplication() { SAFE_RELEASE(m_pD3DDevice); SAFE_RELEASE(m_pD3D); if(m_hWnd) DestroyWindow(m_hWnd); UnregisterClass(m_strClass, GetModuleHandle(NULL)); } BOOL CMyApplication::InitializeWindow(int iWidth, int iHeight, BOOL bWindowed) { WNDCLASSEX wc; // Fill in the members wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_CLASSDC; wc.lpfnWndProc = MainMessageProcedure; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandle(NULL); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wc.lpszClassName = m_strClass; wc.lpszMenuName = NULL; RegisterClassEx(&wc); if(!bWindowed) { iWidth = GetSystemMetrics(SM_CXFULLSCREEN); iHeight = GetSystemMetrics(SM_CYFULLSCREEN); } m_hWnd = CreateWindow(m_strClass, m_strTitle, ((bWindowed)?WS_OVERLAPPEDWINDOW:WS_POPUPWINDOW), 0, 0, iWidth, iHeight, NULL, NULL, wc.hInstance, NULL); if(m_hWnd == NULL) return FALSE; ShowWindow(m_hWnd, SW_SHOW); UpdateWindow(m_hWnd); ShowCursor(TRUE); return TRUE; } BOOL CMyApplication::InitializeD3D(D3DDEVICE_CREATION_PARAMETERS dcp, BOOL bWindowed, int iWidth, int iHeight) { D3DDISPLAYMODE d3ddm; m_bWindowed = bWindowed; m_d3ddcp.hFocusWindow = dcp.hFocusWindow; m_d3ddcp.AdapterOrdinal = dcp.AdapterOrdinal; m_d3ddcp.DeviceType = dcp.DeviceType; m_d3ddcp.BehaviorFlags = dcp.BehaviorFlags; m_pD3D = Direct3DCreate9(D3D_SDK_VERSION); if(m_pD3D == NULL) return FALSE; if(FAILED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))) return FALSE; m_d3dpp.BackBufferCount = 1; m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; m_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; m_d3dpp.EnableAutoDepthStencil = TRUE; m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // If we are windowed if(m_bWindowed) { m_d3dpp.BackBufferWidth = iWidth; m_d3dpp.BackBufferHeight = iHeight; m_d3dpp.BackBufferFormat = d3ddm.Format; m_d3dpp.Windowed = TRUE; } else {// We are not in windowed mode m_d3dpp.BackBufferWidth = d3ddm.Width; m_d3dpp.BackBufferHeight = d3ddm.Height; m_d3dpp.BackBufferFormat = d3ddm.Format; m_d3dpp.Windowed = FALSE; m_d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; } // Store the official window width and height now, cause // we are not going to change it after this point m_iWndWidth = m_d3dpp.BackBufferWidth; m_iWndHeight = m_d3dpp.BackBufferHeight; if(FAILED(m_pD3D->CreateDevice(dcp.AdapterOrdinal, dcp.DeviceType, dcp.hFocusWindow, dcp.BehaviorFlags, &m_d3dpp, &m_pD3DDevice))) return FALSE; return TRUE; } BOOL CMyApplication::IsDeviceThere() { HRESULT hr; hr = m_pD3DDevice->TestCooperativeLevel(); if(FAILED(hr)) return FALSE; return TRUE; } BOOL CMyApplication::ResetDevice() { if(FAILED(m_pD3DDevice->Reset(&m_d3dpp))) return FALSE; return TRUE; } BOOL CMyApplication::CanReset() { HRESULT hr; hr = m_pD3DDevice->TestCooperativeLevel(); if(hr == D3DERR_DEVICENOTRESET) return TRUE; return FALSE; } void CMyApplication::Run() { if(!InitializeWindow(m_iWndWidth, m_iWndHeight, FULLSCREEN?FALSE:TRUE)) return; D3DDEVICE_CREATION_PARAMETERS dcp; dcp.AdapterOrdinal = D3DADAPTER_DEFAULT; dcp.DeviceType = D3DDEVTYPE_HAL; dcp.hFocusWindow = m_hWnd; dcp.BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING; if(!InitializeD3D(dcp, FULLSCREEN?FALSE:TRUE, m_iWndWidth, m_iWndHeight)) return; if(!FirstInitialize()) return; MyGameLoop(); FinalCleanup(); } void CMyApplication::MyGameLoop() { MSG msg; ZeroMemory(&msg, sizeof(MSG)); while(msg.message != WM_QUIT && m_bAlive != FALSE) { if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { if(m_bActive) { if(IsDeviceThere()) { if(!m_bPaused) { if(!PreRender()) break; if(!Render()) break; } } else { if(CanReset()) { InvalidateObjects(); ResetDevice(); RestoreObjects(); } } } } } } LRESULT WINAPI CMyApplication::MessageProcedure(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch(iMsg) { case WM_ACTIVATE: switch(wParam) { case WA_ACTIVE: m_bActive = TRUE; break; case WA_CLICKACTIVE: m_bActive = TRUE; break; case WA_INACTIVE: m_bActive = FALSE; break; } return 0; break; case WM_DESTROY: PostQuitMessage(0); return 0; break; case WM_SIZE: switch(wParam) { case SIZE_MINIMIZED: m_bActive = FALSE; break; case SIZE_RESTORED: m_bActive = TRUE; break; case SIZE_MAXIMIZED: m_bActive = TRUE; break; } return 0; break; case WM_KEYDOWN: switch(wParam) { case VK_ESCAPE: PostQuitMessage(0); break; case VK_PAUSE: m_bPaused = !m_bPaused; break; } return 0; break; default: return DefWindowProc(hWnd, iMsg, wParam, lParam); } } ////////////////////////////////////////////////////////////////////////////////////////////// // This file is copyright © Triple Buffer Software. // // Terms and conditions of code usage are specified at: // http://triplebuffer.devmaster.net/license.php // // Send any questions/comments to triplebuffer@devmaster.net, or visit the forums. // // Written by: Ali Fareed - k9eks@hotmail.com ///////////////////////////////////////////////////////////////////////////////////////////// ---- My Application.h //------------------------------------------------------------------------------------- // This stuff is generated by MS Visual C++ when you go to Menu->Insert->New Class #if !defined(AFX_MYAPPLICATION_H__143B0E6B_546C_4B77_BF3C_4B5797349D77__INCLUDED_) #define AFX_MYAPPLICATION_H__143B0E6B_546C_4B77_BF3C_4B5797349D77__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif //------------------------------------------------------------------------------------- // Link in the required libraries #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") // We link this so we can use the function timeGetTime() #pragma comment(lib, "winmm.lib") // include necessary headers #include <windows.h> #include <d3dx9.h> #define SAFE_RELEASE(i) if(i != NULL) { i->Release(); i = NULL; } class CMyApplication { public: CMyApplication(); virtual ~CMyApplication(); void Run(); virtual LRESULT WINAPI MessageProcedure(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam); protected: BOOL InitializeD3D(D3DDEVICE_CREATION_PARAMETERS dcp, BOOL bWindowed, int iWidth, int iHeight); BOOL IsDeviceThere(); BOOL CanReset(); BOOL ResetDevice(); BOOL InitializeWindow(int iWidth, int iHeight, BOOL bWindowed); void MyGameLoop(); virtual BOOL FirstInitialize() { return TRUE; } virtual BOOL FinalCleanup() { return TRUE; } virtual BOOL InvalidateObjects() { return TRUE; } virtual BOOL RestoreObjects() { return TRUE; } virtual BOOL PreRender() { return TRUE; } virtual BOOL Render() { return TRUE; } HWND m_hWnd; BOOL m_bPaused; BOOL m_bActive; BOOL m_bAlive; BOOL m_bWindowed; UINT m_iWndWidth; UINT m_iWndHeight; char m_strTitle[128]; char m_strClass[128]; IDirect3D9* m_pD3D; IDirect3DDevice9* m_pD3DDevice; D3DPRESENT_PARAMETERS m_d3dpp; D3DDEVICE_CREATION_PARAMETERS m_d3ddcp; }; #endif // !defined(AFX_MYAPPLICATION_H__143B0E6B_546C_4B77_BF3C_4B5797349D77__INCLUDED_) ////////////////////////////////////////////////////////////////////////////////////////////// // This file is copyright © Triple Buffer Software. // // Terms and conditions of code usage are specified at: // http://triplebuffer.devmaster.net/license.php // // Send any questions/comments to triplebuffer@devmaster.net, or visit the forums. // // Written by: Ali Fareed - k9eks@hotmail.com ///////////////////////////////////////////////////////////////////////////////////////////// -- Game.cpp /*-------------------------------------------------------------------- This is where all the magic is going to take place. This is our main file, and everything is going to happen through here Tutorial #2.5 Changes - Added vertex buffer creation and deletion function - functions to set the camera position, the objects' position, and the projection (perspective/non-perpective) - Added the vertex buffer object that holds the vertex data - A structure that is used for each vertex - An FVF that will be used by DirectX to know what kind of vertex you're giving it - RestoreObjects() and InvalidateObjects() are being used for the first time, and so is FirstInitialize() ---------------------------------------------------------------------*/ #include "Game.h" // The CGame class definition CGame::CGame() { // Initialize the pointer to NULL m_pVertexBuffer = NULL; } CGame::~CGame() { KillTriangle(); } BOOL CGame::KillTriangle() { // This is a macro defined in the base class that // safely releases an interface. MS uses it so we'll // use it too :P SAFE_RELEASE(m_pVertexBuffer); return TRUE; } BOOL CGame::CustomSetup() { // Turn off lighting cause we arent using any lights // and we made th vertex buffer without normals, so if // you turned lighting on, everything would be black // or just unlit if(FAILED(m_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE))) return FALSE; // We set teh CULLMODE to NONE because if we leave itr at default // DirectX will get rid of all the polygons that are not stored // in a counter-clock-wise order. We store our vertices in a ransom // order, because we are drawing flat quad, and we dont need any // polygons to be hidden. But say that we were drawing a cube, Then // you would want the inside polygons of the cube (the polygons that // no one can see) gotten rid of. In that kind of situation Setting // the cull mode is good for optimizations. When you are in your // program press F1 and see what happens. I turn Culling back on // after you press F1 if(FAILED(m_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE))) return FALSE; // Now you can set the projection matrix. The projection matrix // is like a your eye's pupil, you can focus your eye, to see close // objects, or you can focus your eye to see farther away objects. It would // be better to compare the projection to a camera lens. you can zoom in // and zoom out. You can do the same thig with the projection. Go into your // DirectX folder and go to the Direct3D Samples, go into the bin folder // and click on FishEye.exe. That is the effect a projection matrix can have. // We will use the perspective matrix. You can also use the orthogonal // function. If you use Ortho, you get rid of 3D effects, When you are running // The program, press F2 when your object is on the far left or right, and see // what happens. Also try moving the quads back a bit, and they reach a point where // they just dissapear. This is because we set our last parameter to 100.0. so anything // that goes past 100 units in the positive z direction (away from you) will // dissapear. make the value higher, say 1000, and you can go much farther before // the object dissapears, but then you get other problems as you go farther. // try it and you'll notive the problem, and then you can ask me why it happens :) if(FAILED(D3DXMatrixPerspectiveFovLH(&m_matProjection, D3DX_PI/4.0f, (float)(m_iWndWidth/m_iWndHeight), 1.0f, 1000.0f))) return FALSE; // On FAIL // Now set our created projection matrix as the projection // matrix that DirectX should use. You set all matrices ie: // world, projection and view with a call to SetTransform(); if(FAILED(m_pD3DDevice->SetTransform(D3DTS_PROJECTION, &m_matProjection))) return FALSE; // On FAIL // Now we can set the view matrix. The view matrix is where yuor camera // is. We can just set to to an identity matrix so that its at origin, // but I want to show you a function that's very useful for setting the view matrix. // The following function is just one call and it will set up the // - Position of your camera // - The position of what the camera is looking at // - And, Which direction is considered UP in this scene // So our setting are if(FAILED(D3DXMatrixLookAtLH(&m_matView, &D3DXVECTOR3(0.0f, 00.0f, -50.0f), //Position 50 units back. &D3DXVECTOR3(0.0f, 0.0f, 0.0f), //Look at the origin &D3DXVECTOR3(0.0f, 1.0f, .0f)))) //Up is the positive Y-Axis return FALSE; // On FAIL // Now set the view matrix just like you set the projection matrix if(FAILED(m_pD3DDevice->SetTransform(D3DTS_VIEW, &m_matView))) return FALSE; // On FAIL return TRUE; } BOOL CGame::FirstInitialize() { // Set all the matrices to identity matrices // this is just like setting a number to 0 ... starting fresh D3DXMatrixIdentity(&m_matWorld); D3DXMatrixIdentity(&m_matView); D3DXMatrixIdentity(&m_matProjection); // Set up all our custom device setup stuff if(!CustomSetup()) return FALSE; // Now create our vertex buffer if(!CreateTriangle()) return FALSE; return TRUE; } BOOL CGame::CreateTriangle() { // Declare a pointer to a MY_CUSTOM_VERTEX structure. We are going to do stuff // to this pointer that will have it pointing to our vertex buffer that will // eventually be stored somewhere in memory. pVertices will eventually point to // that area in memory. Once pVertices points to our vertex buffer, we can change // stuff in our vertex buffer. The stuff we can change in the vertex buffer depends // on the type of vertex buffer we make. We are going to make a vertex buffer that // will store 8 vertices, and each of the vertices will be of the type // MY_CUSTOM_VERTEX. MY_CUSTOM_VERTEX *pVertices = NULL; // This function is used to initialize our vertex buffer // interface. It is a straight forward function, which gives // you back a pointer to your initialized vertex buffer if(FAILED(m_pD3DDevice->CreateVertexBuffer( 3*(sizeof(MY_CUSTOM_VERTEX)), // The first parameter wants the size of the vertex // buffer that you want to create. We are going to be // storing 3 verices in our vertex buffer. and each // vertex is of type 'MY_CUSTOM_VERTEX', so the total // size of the vertex buffer is the number of vertices // times the size of their type (and they are of type // MY_CUSTOM_VERTEX). 3 vertices for 3 points in a // triangle D3DUSAGE_WRITEONLY, // This second param, is used to tel DirectX how you are // going to use your vertex buffer. All we are going to // do is write to it, so we specify the flag D3DUSGAE_WRITEONLY. // Also this vertex buffer will be a static one. Meaning // that we are not going to be changing it's contents. If // you wanted it to be a dynamic buffer, all you'd do is // specify D3DUSAGE_DYNAMIC. The difference is that static // buffers will be placed in video memory (directly accessible) // and dynamic buffers will be placed in AGP memory. If you // dont specify D3DUSAGE_DYNAMIC, DirectX automatically // assumes that the buffer is static (and that's what we want) MY_CUSTOM_VERTEX_FVF, // This is the Flexible Vertex Format that we give to // DirectX, to let it know what type of structure we are // using to store our vertices. We are using a structure // with x,y,z position, and a color. So that's what our // FVF says, and that's what we pass to CreateVertexBuffer() D3DPOOL_DEFAULT, // This parameter tells DirectX where to place the vertex // buffer. DEFAULT tells DirectX to choose the most efficiet // place for it. This is usually your 3D cards memory. but // not necessarily. It could be place in SYSTEMMEM or in // MANAGED. DEFAULT should be used with VertexBuffers, but // when you're using textures, it's advisable to place them // in the MANAGED POOL (D3DPOOL_MANAGAED). Also anything // you place in D3DPOOL_DEFAULT must be released before // resetting the device, and then reinitialized after the // device is reset. &m_pVertexBuffer, // The initialized vertex buffer NULL ))) // Last parameter has to be NULL cause it's reserved. return FALSE; //FAIL // Now we have to fill in the vertex buffer. To do that we have to // lock the vertex buffer, then we fill in the vertex buffer, then we // unlock it, so ... if(FAILED(m_pVertexBuffer->Lock(0, // This is where we want to start locking. // Meaning that the vertex buffer will be // locked starting from '0' (so from the // beginning). 0, // This is how much of the vertex buffer you // want to lock, (starting from the first // parameter). 0 tells DiretcX that you want // the whole thing. Alternatively you can give // it the size by telling that you want to lock // number of vertices * sizeof(MY_CUSTOM_VERTEX) // but specifying 0 is easier and just the same. (void**)&pVertices, // This is a pointer to our vertices in the // vertex buffer. After teh Lock() function // returns. This pointer will point to our // vertex buffer (wherever it is). And we can // use it to chenge stuff. 0))) // This parameter takes a few flags that could // enable optimization. For example if you were // only going to read from the vertex buffer // you could specify D3DLOCK_READONLY, to say // that you only want to read. But when we // created our vertex buffer we specified // D3DUSAGE_WRITEONLY, so we're going to be // writing to it. If we specified D3DLOCK_READONLY // this function would FAIL because there would be // a conflict in DirectX return FALSE; // Now we use pVertices to access our vertex buffer, and change it // Set our 3 vertices pVertices[0].position = D3DXVECTOR3(0.0f, 5.0f, 0.0f); pVertices[1].position = D3DXVECTOR3(-2.0f, -2.0f, 0.0f); pVertices[2].position = D3DXVECTOR3(2.0f, -2.0f, 0.0f); // Ok we finished fixing the vertices' positions // now we'll give them color pVertices[0].color = D3DCOLOR_XRGB(255,255,255); // White pVertices[1].color = D3DCOLOR_XRGB(255,255,0); // Yellow pVertices[2].color = D3DCOLOR_XRGB(0,0,255); // Blue // Ok, we are done with the vertex buffer. now unlock it m_pVertexBuffer->Unlock(); return TRUE; } BOOL CGame::Render() { // This function will tell direct3D what part of the Fixed Function Pipeline // you are going to be using. Our FVF has XYZ, and DIFFUSE, so DirectX knows // that you are using vertices that have position and color. m_pD3DDevice->SetFVF(MY_CUSTOM_VERTEX_FVF); // This function binds a vertex buffer to a stream. in this call we are // binding m_pVertexBuffer to stream 0, and telling the function that all // the vertices are of the 'MY_CUSTOM_VERTEX' size. The second 0 tells direct3D // how far forward it must move from the start of the stream to out vertex data. // We specified stream 0, and we want to start sending vertices from our first vertex // so we put 0 in the third param too m_pD3DDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(MY_CUSTOM_VERTEX)); m_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,30), 1.0f, 0); m_pD3DDevice->BeginScene(); // Set the world matrix. This decides where the tri wil be draw // we havn't done anything so just set it to an identity that we // made in the CustomSetup function m_pD3DDevice->SetTransform(D3DTS_WORLD, &m_matWorld); m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, // Type of stuff we're drawing // we are drawing a triangle list. // triangle lists are made up of 3 // vertices each. So we have 1 // triangle list 0, // From where to start drawing in the VB 1); // How many D3DPTs will we draw? m_pD3DDevice->EndScene(); m_pD3DDevice->Present(NULL, NULL, NULL, NULL); // Setting the StreamSource back to NULL after you use it is good // practice. If you dont set it back to NULL. It's possible // that when you exit the program, the vertex buffer isnt totally // released and you will get a memory leak. This is highly unlikely // but it's possible, so just play it safe. m_pD3DDevice->SetStreamSource(0, NULL, 0, sizeof(MY_CUSTOM_VERTEX)); return TRUE; } BOOL CGame::FinalCleanup() { return KillTriangle(); } // When the device is lost this function is called // before the device is reset, and RestoreObjects() // is called after teh device is reset. You have to // release stuff that you created with D3DPOOL_DEFAULT // before resetting the device. andwe just happened to // create our vertex buffer using D3DPOOL_DEFAULT, so // we release it before trying to reset the device. // Then we reinitialize our vertex buffer from the // RestoreObjects() function BOOL CGame::InvalidateObjects() { return KillTriangle(); } BOOL CGame::RestoreObjects() { // Call CustomSetup() to customize the // way teh direct3D device behaves; CustomSetup(); return CreateTriangle(); } LRESULT WINAPI CGame::MessageProcedure(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { return CMyApplication::MessageProcedure(hWnd, iMsg, wParam, lParam); } //------------------------------------------------------------------------------// // Application execution starts here // //------------------------------------------------------------------------------// CGame *g_pGame = NULL; int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pstrCmdLine, int iShowCmd) { g_pGame = new CGame; g_pGame->Run(); delete g_pGame; return 0; } LRESULT WINAPI MainMessageProcedure(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { return g_pGame->MessageProcedure(hWnd, iMsg, wParam, lParam); } /* **Culling** (a render state is exactly what it says, it is the state in which DirectX will) (render objects to the screen. You can change many things with render states. ) In the CustomSetup() function we set the renderstate called CULLMODE to NONE. We set it to NONE so that DirectX does not do any back-face culling. When it's on, DirectX will cull out any polygons that are facing away from the user. This is one of the optimization techniques that DirectX uses. But we just rendered some flat squares. So there are'nt any polygons that are not possible to see. If we were rendering a cube, then all the polygons inside the cube are unseeable by the user, and should therefor be culled. If you want the back of a polygon culled, you have to define the polygon in a certain direction. Meaning that the order that the verices are stored in matter. So if we wanted a triange with it's back culled we would define the vertices in a counter-clock wise direction. (I think it's clock wise for OpenGL) here... 1 see how the vertices go in a counter clock wise direction around |\ the polygon. If we were to define it like this | \ 1 | \ |\ then the fron of our polygon 2---3 | \ would never be seen. Granted | \ we turned culling on. 3---2 **Transformations** Before a vertex is shown on the screen it has to go through 3 transformations. We set 2 of the transformations in the CustomSetup() function, and we set the last transformation is in the Render() function. They are -The Projection -The View -The World You can think of the first 2 transformations as a camera. The first one is the camera's lense. It sets the perspective, and the field of view. You can make things appear farther and closer. You know that effect in games with a sniper?! you can do that with the projection. The second transformation is the view, which can be compared to the rest of the camera. It has a position, it has a "look at" point (the point it's looking at). And it has an "up" direction, which tells the camera which way is up in the world. The 3rd transformation is the world. We use the world to place objects in different positions. So if you wanted to move an object to an area in you world, you would set the world matrix to that area, then draw your object. Also because of the nature of matices, the order in which you multiply your transformations in make a different. the order for matrix multiplication is S*R*T (scaling x rotations x translations). In our Render() function, try changing the order to S*T*R, and you'll get an orbiting effect. ************************************RECAP*************************************** To draw something on screen we have to 1: Create the d3d device 2: Set a few default render states 3: Set the view and projection matrices 4: Fill a vertex bufer with vertex data 5: Set the world matrix 6: Draw what's in the vertex buffer 7: Destroy all our interfaces, and delete any memory we created 7 steps to drawing a quad on the screen with directx! */ ////////////////////////////////////////////////////////////////////////////////////////////// // This file is copyright © Triple Buffer Software. // // Terms and conditions of code usage are specified at: // http://triplebuffer.devmaster.net/license.php // // Send any questions/comments to triplebuffer@devmaster.net, or visit the forums. // // Written by: Ali Fareed - k9eks@hotmail.com ///////////////////////////////////////////////////////////////////////////////////////////// --- Game.h #if !defined(AFX_GAME_H__5E41AB7E_7E69_406D_B870_7BC766BE96C0__INCLUDED_) #define AFX_GAME_H__5E41AB7E_7E69_406D_B870_7BC766BE96C0__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif #include "MyApplication.h" // This structure will hold our data for each vertex. We want to have a position // and a color for each vertex so I made this structure to hold that information // After our structure we have to tell DirectX what our structure is made up of // That is where the Flexible Vertex Format (FVF) comes in. Our FVF is defined // under the structure struct MY_CUSTOM_VERTEX { D3DXVECTOR3 position; D3DCOLOR color; }; // This is our FVF. For a complete list of valid FVFs check teh sdk docs // But here we are using XYZ, which tells DX we have position, and we are // using DIFFUSE, which tells DX that we have color. #define MY_CUSTOM_VERTEX_FVF (D3DFVF_XYZ|D3DFVF_DIFFUSE) class CGame : public CMyApplication { public: CGame(); ~CGame(); // These are all the virtual functions in the base class. LRESULT WINAPI MessageProcedure(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam); BOOL FirstInitialize(); BOOL FinalCleanup(); // These two function will be used for // resetting the vertex buffers when device // is lost BOOL InvalidateObjects(); BOOL RestoreObjects(); BOOL Render(); // These two functions explain themselves :) BOOL CreateTriangle(); BOOL KillTriangle(); // This function sets stuff up. namely the view and projection matices BOOL CustomSetup(); private: // This variable will hold our vertex buffer IDirect3DVertexBuffer9 *m_pVertexBuffer; // These three variables will be used to // set the vertices in their final position D3DXMATRIX m_matWorld; D3DXMATRIX m_matView; D3DXMATRIX m_matProjection; }; #endif ////////////////////////////////////////////////////////////////////////////////////////////// // This file is copyright © Triple Buffer Software. // // Terms and conditions of code usage are specified at: // http://triplebuffer.devmaster.net/license.php // // Send any questions/comments to triplebuffer@devmaster.net, or visit the forums. // // Written by: Ali Fareed - k9eks@hotmail.com ///////////////////////////////////////////////////////////

##### Share on other sites
And if it makes a difference I'm using Dev C++

##### Share on other sites
From what I've heard DexC++ and DirectX don't mesh well. Haven't tried myself so I don't have any solutions beyond getting Visual Studio instead.

Also, for large chunks of code like that, try to use the 'source' tags.

Matt Hughson