First of all you need to create a rendering window, and then to initialize Direct3D. This is done in 3 lines only.
#include <AED3D11RenderingEngine.hpp> AED3D11RenderingEngine *pEngine = new AED3D11RenderingEngine(); pEngine->CreateWindow(nullptr, 800, 600); pEngine->Initialize();
To visualize the objects in the scene you will also need a camera. Two types of cameras are implemented in the vanilla release : a first-person camera and an arcball camera.
AECamera *pCamera = pEngine->CreateFirstPersonCamera();
See class AECamera, AEFirstPersonCamera and AEArcballCamera for more details on the methods provided by these classes.
AED3D11RenderingEngine::Initialize() creates the Direct3D resources necessary to load the scene and to use the GUI (Graphical User Interface), as well as the 'factories' that deal with the creation of resources. For more details of what is done in this function and if you want to reconfigure/add functionalities to the engine, refer Pipeline.
a
Depending on the Direct3D version you are using, you will need to use a different AERenderingEngine library which implements the functions of the D3D library. It is common in rendering engines to implement a rendering system for each D3D version and to allow fallback to a prior version if the most recent one is not supported.In the current release of AEngine, only Direct3D 11 (the lastest D3D version) is supported.
AEngine already provides you with a set of basic primitives, to draw customizable primitive batches, and allows to load mesh files from common assets from the 3D industry (see the Home page for a list of supported formats). The AED3D11MeshFactory, accessible through a singleton interface, deals with the creation of meshes.
#include <AED3D11RenderingEngine.hpp> AERenderable *pRenderable = AED3D11MeshFactory::GetSingleton()->CreateGeoSphere("GeoSphere", 1.0, 5); AERenderable *pRenderable2 = AED3D11MeshFactory::GetSingleton()->CreateFromFile("Car", "Car.obj");
In AEngine, factories create resources identified by their (unique) name. Attempting to create a resource with the same name as a resource previously created will return a pointer on the latter.
After creating a mesh, you need to add it to the scene. This is done by creating a node in the scene and attaching the mesh to this node. Actually, this is done by attaching an instance of this mesh to the node. Indeed, a same mesh can be used multiple times to render the same object many times just by transforming its coordinates. This saves up memory. Instances are created with the class AEntity. In continuation to the code above, this would be done as following :
AEScene *pScene = AED3D11RenderingSystem()::GetSingleton()->GetScene(); AEntity *pEntity1 = new AEntity("MySphere1", pRenderable); pScene->AddEntity(pEntity1); AEntity *pEntity2 = new AEntity("Car1", pRenderable2); pScene->AddEntity(pEntity2);
The code above adds the entities to the root node of the scene.
Just like any resource, all the entities and nodes must have unique names. AEEntity objects provide methods to transform the renderable attached to it and to define how you want to render it (e.g. : for a same AERenderable object, you can apply different effects by creating entities for each of the effects).
At last, after populating your scene, you need to call the rendering engine main loop which renders the scene.
AED3D11RenderingSystem()::GetSingleton()->Run();
A scene is created automatically when you initialize AED3D11RenderingEngine. Entities in a same scene must have unique names.
See the files AEScene.h, AENode.h, AEntity.h, AED3D11MeshFactory.h, AED3D11PrimitiveBatch.h and AED3D11Renderable.h for more information on the methods provided by these classes.
Effects/Shaders are an inherent part of Direct3D. They are computer programs that are used to do shading - the production of appropriate levels of light and color within an image - and also to produce special effects or do post-processing.
When you create a mesh and an entity to render it, a default effect is used to display it (AED3D11BasicEffect
, that renders non-textured and textured meshes with position(/color/normal/texture/tangent/binormal) data, the parameters in brackets are optional). If you want to use another effect to render it or to use your own effects derived from the class AED3D11Effect, you can do it with very few code lines. Have a look below :
AEntity *pEntity = new AEntity("MyMesh", pMesh); AEEffect *pEffect = new AED3D11MyCustomEffect(...); pEntity->SetEffect(pEffect);
If you want to be able to re-use the effect later for other entities, you can register it with the effect factory as follows :
AED3D11EffectFactory::GetSingleton()->Register(">InserUniqueEffectNameHere<", pEffect);
As for all the factories in AEngine, when you call :
AED3D11EffectFactory::GetSingleton()->CreateEffect(">InserUniqueEffectNameHere<");
a pointer on the registered effect will be returned. This way you won't have to create it again.
Prerequisites : an effect file or shader bytecode. Nvidia SDK and Microsoft DirectX SDK also provides a lot of effect/shader samples. If you are interested in shader coding, refer to Reference for HLSL
For a guide about effect programming, refer to Effects (Direct3D 9). Even if the article covers the D3D9 version, it is the same principle for the more recent versions. Read Effects (Direct3D 11) also to understand the D3D effect interface with D3D11.
When you code your own effects deriving AED3D11Effect, there are 5 steps :
redefine the method AED3D11Effect::Update(const SceneGlobalParameters*, const void*)
which updates these variables
create an input layout matching the vertex layout of the mesh to render (AEngine provides the convenient helper class AEVertexSemanticsMap
to ease the burden of this task. See 'More on mesh creation' for more details)
AED3D11Effect::Apply(ID3D11DeviceContext *)
if needed. The method from the base class AED3D11Effect
binds the input layout and the effect to the rendering context.The effect is now ready to be used.
For an example, you can refer to the code of AED3D11BasicEffect or AED3D11PhongLighting, which follows the very same steps presented above.
For now, only a maximum of _AE_MAX_NUM_LIGHTS
can be added to the scene and the current implementation is just meant for debugging and demonstration purposes. The lights are stored in AEScene
and are used by the shaders to compute the lighting.
AELight *pLight = new PointLight; // Initialize pLight with your values ... pScene->AddLight(pLight);
For complex scenes, it is better to use other rendering techniques instead of iterating on all the lights in the shader, which is costly. Some other efficient methods exist, such as deferred shading.
AEngine uses CEGUI for GUI rendering and OIS to capture the keyboard and mouse inputs. During the initialization of AEngine, CEGUI and OIS are initialized. All you need to do is adding GUI elements and providing their initialization parameters when you initialize the contents of your scene, using the CEGUI functions and classes. All the CEGUI data files are located in the folder CEGUI in the executable directory.
CEGUI/OIS include files are automatically added to your current file and CEGUI/OIS libraries are implictly linked as soon as you add :
#include "AED3D11RenderingEngine.hpp"
Internally, AED3D11RenderingEngine uses CEGUI to display the FPS and a console which parses user commands when you press the ESCAPE key.
To code what to do when you enter messages via this console, pass your own function to m_FnParseConsoleMessage