spinning_cube - ryzom/ryzomcore GitHub Wiki


title: Spinning Cube description: published: true date: 2023-05-23T00:58:28.552Z 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.

Preparation

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.

Adding Necessary Headers

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>

Initializing the Camera, Light, and Cube

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;
};

Creating a Camera and Light

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.

Manipulating the Cube

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.




Shape Bank

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.

⚠️ **GitHub.com Fallback** ⚠️