-
Notifications
You must be signed in to change notification settings - Fork 94
spinning_cube
title: Spinning Cube description: published: true date: 2023-05-23T00:58:32.648Z tags: editor: markdown dateCreated: 2023-05-22T19:38:21.350Z
TODO: This tutorial has been autogenerated and is pending developer review. {.is-danger}
In this tutorial, we will our previously initialized NeL application context and 3D driver to set up a basic 3D scene in NeL. We will configure a camera, set up a lighting source, and render a spinning cube.
Before we start, we need to ensure that the necessary resources are available. In particular, we'll need a cube shape. If you have created a cube shape and named it "cube.shape", copy it into the build/data/shapes directory.
If you have a different data directory or a specific file structure, adjust the paths accordingly in the code snippets below.
In the main.cpp
file, include the necessary headers:
#include <nel/3d/u_camera.h>
#include <nel/3d/u_light.h>
#include <nel/3d/u_shape_bank.h>
#include <nel/3d/u_instance.h>
#include <nel/3d/u_scene.h>
#include <nel/misc/time_nl.h>
Next, we add member variables for the camera, light, and cube to our game class:
class CMyGame : public IEventListener
{
public:
CMyGame();
~CMyGame();
void run();
virtual void operator()(const CEvent &event) NL_OVERRIDE;
private:
NL3D::UDriver *m_Driver;
NL3D::UScene *m_Scene;
bool m_CloseWindow;
NL3D::UCamera *m_Camera;
NL3D::ULightPoint *m_Light;
NL3D::UShapeBank *m_ShapeBank;
NL3D::UInstance m_Cube;
NLMISC::TTime m_LastFrameTime;
};
In the constructor of CMyGame
, we initialize the camera, light, and shape bank:
CMyGame::CMyGame()
: m_CloseWindow(false), m_LastFrameTime(NLMISC::CTime::getLocalTime())
{
// ...
// Initialize the scene
m_Scene = m_Driver->createScene(true);
if (!m_Scene)
{
nlerror("Failed to create scene");
return;
}
// Create a camera
m_Camera = m_Scene->getCam();
m_Driver->setViewport(NLMISC::CViewport());
m_Camera->setFrustum(0.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1000.0f, false);
// Create a light
m_Light = m_Scene->createPointLight();
m_Light->setDirection(NLMISC::CVector(0.0f, 0.0f, 1.0f));
m_Light->setAmbiant(NLMISC::CRGBA(255, 255, 255, 255));
m_Light->setDiffuse(NLMISC::CRGBA(255, 255, 255, 255));
m_Scene->enableLight(*m_Light);
// Initialize the shape bank
m_ShapeBank = m_Driver->createShapeBank();
if (!m_ShapeBank)
{
nlerror("Failed to create shape bank");
return;
}
// Load the cube shape
m_Cube = m_ShapeBank->loadShape("cube.shape");
// ...
}
The cube shape should be located in the
data/shapes directory, which you can configure with addSearchPath()
. The shape is loaded into the m_Cube
instance variable, which is used later to render the cube.
If the cube shape isn't found, the program will print an error message and exit. So, make sure that the shape is in the correct location.
Finally, we update the cube's position and rotation in the run()
method:
void CMyGame::run()
{
// ...
// Calculate elapsed time since last frame
NLMISC::TTime currentTime = NLMISC::CTime::getLocalTime();
float deltaTime = (float)((currentTime - m_LastFrameTime) * 0.001);
m_LastFrameTime = currentTime;
// Calculate rotation amount
float rotationAmount = deltaTime * 90.0f; // Rotate 90 degrees per second
// Update the cube's position and rotation
NLMISC::CMatrix matrix = m_Cube.getMatrix();
matrix.rotateY(rotationAmount * (NLMISC::Pi / 180.0f)); // Pi / 180 converts degrees to radians
m_Cube.setMatrix(matrix);
// Clear the screen
m_Driver->clearBuffers(NLMISC::CRGBA(0, 0, 0, 0));
// Update the scene
m_Scene->animate(currentTime);
// Begin scene render
m_Driver->beginScene();
// Render the scene
m_Scene->render();
// End scene render
m_Driver->endScene();
// Swap buffers
m_Driver->swapBuffers();
// ...
}
Now, you should be able to compile and run your project. You will see a cube that spins around its Y-axis. If you encounter any issues, please ensure that the resources are correctly located and that the paths in the code match your directory structure.
In the next tutorial, we will introduce how to load and animate more complex 3D models.
The Shape Bank in NeL is essentially a repository that holds various geometric shapes used in the scene or game. These shapes could be any objects in your game world, from characters and props to environmental elements like trees and buildings. NeL supports various types of shapes, including basic shapes like spheres and cubes, and complex shapes like meshes and skeletons.
When you are developing a game or scene in NeL, you would typically load shapes from files stored on disk. This process can be time-consuming, especially when you have a large number of shapes or very complex shapes. To optimize this process, NeL uses a mechanism called a Shape Bank.
The Shape Bank is responsible for managing shapes in your application. Instead of loading a shape from disk every time it is needed, shapes are loaded once and stored in the Shape Bank. Then, whenever that shape is needed, it is retrieved from the Shape Bank. This significantly reduces the time taken to load shapes, leading to smoother gameplay and rendering.
Furthermore, the Shape Bank also handles freeing up memory when a shape is no longer needed. When a shape is removed from the scene, the Shape Bank automatically takes care of releasing the memory resources associated with that shape. This efficient management of memory resources is crucial in a game or graphics application where performance is of utmost importance.
In the code snippet provided earlier, we used the loadShape
function to load a cube shape from a file and add it to the Shape Bank:
// Load the cube shape
if (!m_ShapeBank->add("cube.shape"))
{
nlerror("Failed to load cube.shape");
}
In this example, "cube.shape" is the name of the shape file. The add
function attempts to load the shape and add it to the Shape Bank. If the shape is already in the Shape Bank, the add
function simply returns true
and does nothing. If the shape is not in the Shape Bank, the add
function loads the shape from the file and adds it to the Shape Bank, returning true
if successful or false
otherwise.
After loading the shape, we can use it in our application as many times as we want, without incurring the performance cost of loading the shape from disk each time:
m_Cube = m_Scene->createInstance("cube.shape");
In this line, the createInstance
function retrieves the cube shape from the Shape Bank and creates a new instance of it in the scene.
By making use of the Shape Bank, you can greatly enhance the performance and responsiveness of your NeL applications.