W4 Coordinate system and Node structure

From Ciliz|W4

W4 Engine Wiki > General Concepts > Coordinate system and Node structure:

Scope[edit]

The article describes the main solutions used in the W4 game engine:

  • Coordinate system
  • Node system
  • Node system main classes API

Coordinate System[edit]

Coordinate system

The W4 Engine uses the left-handed coordinate system. The rotation is performed counterclockwise provided you look in the direction of the axis.

Render Tree[edit]

The result displayed on the screen as well as the dependence of object transformations on each other, are determined by the render tree (tree-like structure of node objects). Features of the W4 Game Engine render tree:

  • A minimal render tree consist of the root node only.
  • Each node can have zero or more subnodes (“children”), but the node cannot have more than one “parent” (the root node does not have a parent).
  • The object has to be placed on the render tree in order to be displayed on the screen and/or recalculate the data.
  • The built-in node types hierarchy is displayed on the diagram below.

Type hierarchy

The purpose and interfaces of nodes (classes) are presented in the following paragraphs.

Usage notes:

  • When drawing several passes, a render tree with its root node is created for each pass.
  • For each node, the local transformations (transformations relative to the “parent") and the world transformations can be obtained and specified.
  • When world coordinates of a node are set, local coordinates are recalculated, and same correlation between local and world coordinates.
  • For a node that does not have a parent, local and world transformations match.
  • You can temporarily disable the node, thus disabling its descendants as well.

Node[edit]

Node is the base class of any node (including RootNode).

Method Description
w4::sptr<render::RootNode> getRoot() const
Returns root node of render tree or "nullptr" if there is none
w4::sptr<Node> clone() const
Creates a copy of the node. The created copy does not have a parent node
w4::sptr<Node> getParent() const
Returns the parent node or "nullptr" if there is none
void setEnabled(bool)
Enables/disables the node and his "descendants"
void addChild(w4::cref<Node>, bool preserveTransorm = true)

void addChild(const std::string&, w4::cref<Node>, bool preserveTransorm = true)
Adds “children” to the current node. In this method you can set a name for the "child". The "preserveTransform" parameter defines local (false) or global (true) transformations that are stored in the “child".

For example, if you complete the code on the left with the lines:

childNode->setLocalTranslation({1, 0, 0});
parentNode->addChild(childNode);

then "childNode" is in the world position {1, 0, 0},

On the other hand, if you use the following lines:

childNode->setLocalTranslation({1, 0, 0});
parentNode->addChild(childNode, false);

then "childNode" is shifted by 1 on the X axis relative to the parent.

void removeChild(w4::cref<Node>)

void removeChild(const std::string&)

void removeChild(const std::list<w4::sptr<Node>>&)
Unlinks “children” from node defined by pointer, name and list
void traversal(const Callback&)

void traversal(const PredicateC & predicate, const Callback&)

template<typename T> void traversalTyped(const std::function<void(w4::cref<T>)>&);
Executing the functor from the current node down the hierarchy

Callback has a signature void(Node&) PredicateC - bool(w4::core::Node&)

The last method calls functor only for those nodes whose type is inherited from T

void setWorldRotation(math::Rotator::cref, math::vec3::cref worldPt)
Sets rotation relative to a point in world coordinates
void rotateAroundPoint(const math::Rotator& rotator, const math::vec3& worldPt)
Rotates node around a point in world coordinates
template<typename T> w4::sptr<T> as()

template<typename T> w4::sptr<const T> as()   const

template<typename T> T* asRaw()

template<typename T> const T* asRaw() const
Conversion of type of the node (the type is not checked)
template<typename T> bool derived_from() const
Checks if node class is a descendant of the defined class
template<typename T> w4::sptr<T> getChild(const std::string&)
Gets “child” by name with type conversion (the specified type is not checked)
std::list<w4::sptr<Node>> getAllChildren() const
Gets list of all lower nodes in the hierarchy (“children“, “children of children“, etc.)
std::list<w4::sptr<Node>> findChildren(std::string const&) const
Searches for “child” by name
std::list<w4::sptr<Node>> findChildrenRecursive(std::string const&) const
Searches down the hierarchy by name
math::vec3::cref getWorldTranslation() const

void setWorldTranslation(math::vec3::cref)

math::vec3::cref getLocalTranslation() const

void setLocalTranslation(math::vec3::cref)
Gets/sets position in world/local coordinates
math::vec3::cref getWorldScale() const

void setWorldScale(math::vec3::cref)

math::vec3::cref getLocalScale() const

void setLocalScale(math::vec3::cref)
Gets/sets scale in world/local coordinates
math::vec3 getWorldUp() const

math::vec3 getWorldForward() const

math::vec3 getWorldRight() const
Gets normalized vectors in the up, forward, and right directions of the model space in world coordinates
math::Transform::cref getWorldTransform()     const

void setWorldTransform(math::Transform::cref)

math::Transform::cref getLocalTransform() const

void setLocalTransform(math::Transform::cref)
Gets/sets transformation (i.e. combination of position, rotation and scale) in world/local coordinates
math::Rotator::cref getWorldRotation() const

void setWorldRotation(math::Rotator::cref)

math::Rotator::cref getLocalRotation() const

void setLocalRotation(math::Rotator::cref)

void rotateLocal(const math::Rotator&rotator)

void rotateWorld(const math::Rotator&rotator)
Gets/sets rotation in world/local coordinates. "rotateWorld" and "rotateLocal" methods add rotation to the current values
const std::unordered_set<w4::sptr<Node>>& getChildren() const
Gets list of “children“
bool isEnabled() const
Returns the node state (enabled or disabled)
bool hasParent() const
Returns if the node has a “parent”

Hierarchy Example[edit]

Let's take real astronomical dimensions and build a simplified model of the solar system. Since real space distances are used, it is not possible to survey the entire system. In this particular case the model was selected not for visualization purpose, but as a pattern of the features of hierarchy and nesting of transforms (although nothing prevents you from trying to make the model more visual).

#include "W4Framework.h"

W4_USE_UNSTRICT_INTERFACE

class Planet
{
public:
//Some astronomical object data:
// - name
// - color
// - radius (km)
// - radius of the orbit (km)
// - orbital period (days)
// - orbital inclination
// - axis tilt
// - list of satellites
 Planet(const std::string& name, const color& planetColor, float planetRadius, float planetOrbit, float siderealPeriod, float eclipseAngle, float axisTilt, const std::vector<Planet>& moons)
    : m_color(planetColor),
      m_radius(planetRadius),
      m_orbit(planetOrbit),
      m_siderealPeriod(siderealPeriod),
      m_eclipseAngle(eclipseAngle),
      m_axisTilt(axisTilt),
      m_moons(moons)
 {}
 color m_color;
 float m_radius;
 float m_orbit;
 float m_siderealPeriod;
 float m_eclipseAngle;
 float m_axisTilt;
 std::vector<Planet> m_moons;
};

struct SolarDemo : public IGame
{
public:
    void onStart() override
    {
        //create the solar system at the start
        createSolarSystem();
    }

    void onMove(const event::Touch::Move& evt)
    {
    }

    void onUpdate(float dt) override
    {
        for(auto& rotation: m_rotations)
        {
            //object rotation around central body at speed of 0.5 days per second
            rotation.first->rotateLocal(rotation.second * (dt / 2));
        }
    }

private:

    void createSolarSystem()
    {
        // here it is - the solar system!
        const Planet solarSystem("Sun", color::yellow, 695500.f, 0.f, 345.39f, 0.f, 0.f, {
            {"Mercury", color::white,                        2439.7f,   57909050.f, .241f,   7.01f,    .0352f, {}},
            {"Venus",   color::magenta,                      6051.8f,  108208000.f, .615,    3.39f, 177.36f,   {}},
            {"Earth",   color::green,                        6378.f,   149598261.f, 1.f,     0.f,    23.44f,   {
                        {"Moon", color::gray, 1737.1f,  384399.f, 1.f, 0.f, 0.f, {}}
                }},
            {"Mars",    color::red,                          3393.5f,  227939100.f, 1.88f,   1.85f,  25.19f,   {
                        {"Phobos", color::gray, 11.2667f, 9377.2f, .317f,   1.093f, 0.f, {}},
                        {"Demos",  color::gray, 10.f,   23458.f, 1.2625f,   1.85f , 0.f, {}}
                }},
            {"Jupiter", color(1.f, .5f, 0.f, 1.f),          71400.f,   778547200.f, 11.86f,  1.31f,   3.13f,   {
                        {"Callisto", color::gray, 2410.3f, 1882709.f, 16.69f, .205f, 0.f, {}},
                        {"Europa",   color::gray, 1560.8f,  671034.f, 3.55f, .471f, 0.f,  {}},
                        {"Ganymede", color::gray, 2634.1f, 1070412.f, 7.15f, .204f, 0.f,  {}},
                        {"Io",       color::gray, 1818.f,   421700.f, 1.77f, .05f, 0.f,   {}}
                }},
            {"Saturn",  (color::yellow + color::white) / 2, 60000.f,  1433449370.f, 29.46f,  2.49f,  26.73f,   {
                        {"Dione",     color::gray, 560.f,   377415.f, 2.74f,      .028f, 0.f, {}},
                        {"Enceladus", color::gray, 251.4f,  238042.f, 1.370218f, 0.f, 0.f,    {}},
                        {"Tethys",    color::gray, 530.f,   294672.f, 1.887802f, 1.091f, 0.f, {}},
                        {"Titan",     color::gray, 2575.f, 1221865.f, 15.945f,    .306f, 0.f, {}}
                }},
            {"Uranus",  color::cyan,                        25600.f,  2876679082.f, 84.01f,  .77f,   97.77f,   {
                        {"Ariel",   color::gray, 578.9f,  191020.f, 2.520379f,  .26f,  0.f, {}},
                        {"Oberon",  color::gray, 761.4f,  583520.f, 13.463239f, .058f, 0.f, {}},
                        {"Titania", color::gray, 588.9f,  435910.f, 8.705872f,  .34f , 0.f, {}},
                        {"Umbriel", color::gray, 584.7f,  266300.f, 4.144177f,  .205f, 0.f, {}}
                }},
            {"Neptune", color::blue,                        24300.f,  4503443661.f, 164.79f, 1.77f,  28.32f,   {
                        {"Triton", color::gray, 1353.4, 4503443661.f, 164.79f, 1.77f, 0.f, {}}
                }}
        });

        //Create the Sun
        auto sun = Mesh::create::sphere(solarSystem.m_radius, 10, 10);
        //Add it to the root node
        Render::getRoot()->addChild(sun);

        //Set color of base material
        sun->getMaterialInst()->setParam("baseColor", solarSystem.m_color);
        //Create planets
        createMoons(sun, solarSystem);
        //Set scale. Alas, distances are extremely remote that is only the Sun that is visible with real distances without a magnifier... But this is an example
        sun->setLocalScale({1.e-7f, 1.e-7f, 1.e-7f});
    }
    void createMoons(cref<Node> planetNode, const Planet& planet)
    {
        //for each satellite
        for(const auto& moon: planet.m_moons)
        {
            //To test the possibilities of nesting, create an orbit as a node. When this node rotates around the center, the satellite moves in orbit
            auto orbitContainer = make::sptr<Node>();
            //tilt the orbit from the plane of rotation of the central body
            orbitContainer->setLocalRotation({(planet.m_axisTilt + moon.m_eclipseAngle) * DEG2RAD, 0, 0});
            //create an astronomical object
            auto moonNode = Mesh::create::sphere(moon.m_radius, 10, 10);
            //add satellite as a "child" of the orbit
            orbitContainer->addChild(moonNode);
            //set position of the astronomical object in the orbit
            moonNode->setLocalTranslation({moon.m_orbit, 0, 0});
            moonNode->getMaterialInst()->setParam("baseColor", moon.m_color);
            //add the orbit as a "child" of the central body. Pay attention to the "false" parameter which means that 
            //when a "child" is created, local transforms are saved. Thus, the orbit appears to be in the same 
            //position as the planet and is tilted relative to its plane of orbit around the central body
            planetNode->addChild(orbitContainer, false);
            //create satellites recursively
            createMoons(moonNode, moon);

            //add to the list orbits and quaternions for their rotation in local space (calculate from the Euler angles)
            m_rotations.emplace_back(orbitContainer, Rotator(0, 0, 1 / moon.m_siderealPeriod));
        }
    }

    std::vector<std::pair<sptr<Node>, Rotator>> m_rotations;
};

W4_RUN(SolarDemo)

VisibleNode[edit]

The base class for a visible node.

Special features:

  • All displayed nodes contain a vertex buffer and consist of one or more surface (which contains an index buffer).
  • Each surface can be assigned its own material.

All displayed nodes have the following additional methods:

Method Description
const MaterialInstPtr& getMaterialInst(const std::string& surfaceName) const
Returns material of the specified surface
const MaterialInstPtr& getMaterialInst() const
Gets single material (which was set for all surfaces). If materials differ for surfaces, the method generates an error in the log and returns some material back.
void setMaterialInst(const MaterialInstPtr & m)
Sets material for all surfaces

Mesh[edit]

An object that displays geometry.

There are three ways to create mesh type objects in the Engine: 1. Load from resources (see also Mesh Converter):

teapot = Asset::load(Path("resources/teapot", "teapot.asset"))->getRoot()->getChild<Mesh>("Utah Teapot Quads");

2. Call the built-in generator:

auto sphere = Mesh::create::sphere(radius, number of parallels, number of meridians);
auto box = Mesh::create::box({width, height, depth}); //"box" is a parallelepiped in which each face is a surface
auto cube = Mesh::create::cube({width, height, depth}); 
auto mappedCube = Mesh::create::mappedCube({width, height, depth}); //parallelepiped with uv coordinates for unfolding
auto plane1 = Mesh::create::plane({width, height}, scaleUv); //XY axis plane. scaleUv = false (default) is UV from 0 to 1, scaleUv = true is UV from 0 to width/height
auto plane2 = Mesh::create::plane({left, down}, {right, up}, scaleUv; //same
auto cylinder = Mesh::create::cylinder(height, radius, number of sectors);
auto cone = Mesh::create::cone(upper radius, lower radius, height, number of sectors, number of segments vertically);
auto torus = Mesh::create::torus(radius of the ring, radius of the "pipe", number of segments of the ring, number of segments of the "pipe", angle of the arc of the ring (2 * PI for a closed torus));
auto skybox = Mesh::create::skybox(); //Cuboid with sides that are displayed from the inside.

3. Create from code:

        auto indicesBuf = make::sptr<UserIndicesBuffer>("Floor indices");
        auto verticesBuf = make::sptr<UserVerticesBuffer<Mesh::VertexFormat>>("floor_" + std::to_string(width) + "x" + std::to_string(height) + "-" + std::to_string(offset));
        indicesBuf->setNeedExport(false);
        verticesBuf->setNeedExport(false);

        resources::MeshVertexDataBuilder vdb(verticesBuf, indicesBuf);
        //position, UV, normal
        vdb.addVertex({-width / 2 + offset, 0, height / 2}, {offset/width, 0.f}, {0, 1, 0});
        vdb.addVertex({width / 2 - offset, 0, height / 2}, {1.f - offset/width, 0.f}, {0, 1, 0});
        vdb.addVertex({-width / 2, 0, height / 2 - offset}, {0.f, offset/height}, {0, 1, 0});
        vdb.addVertex({width / 2, 0, height / 2 - offset}, {1.f, offset/height}, {0, 1, 0});

        vdb.addVertex({width / 2, 0, -height / 2 + offset}, {0.f, 1.f - offset/height}, {0, 1, 0});
        vdb.addVertex({-width / 2, 0, -height / 2 + offset}, {1.f, 1.f - offset/height}, {0, 1, 0});
        vdb.addVertex({width / 2 - offset, 0, -height / 2}, {offset/width, 1.f}, {0, 1, 0});
        vdb.addVertex({-width / 2 + offset, 0, -height / 2}, {1.f - offset/width, 1.f}, {0, 1, 0});

        vdb.addIndices({2, 1, 0,
                                2, 3, 1,
                                4, 3 ,2,
                                5, 4, 2,
                                5, 6, 4,
                                7, 6, 5});

        vdb.build();

        auto result = make::sptr<Mesh>(verticesBuf->getName(), verticesBuf);
        result->addComponent<Surface>("unnamed", indicesBuf);

        result->setMaterialInst(Material::getDefault()->createInstance());

SkinnedMesh[edit]

An object that displays geometry with animation.

Special features:

  • it can only be downloaded from a file;
  • it is a geometry with skeletal animation;
  • it contains a set of animations;
  • it contains an API for managing animations and allows you to play multiple animations with smooth transitions between them.
Method Description
w4::cref<core::Node> createSocket(const std::string& boneName)
Creates a socket for attaching to the defined bone. You can add “children“ to this socket
w4::cref<core::Node> getSocket(const std::string& boneName) const
Returns a socket for attaching to the defined bone
std::vector<std::string> getAvailableAnimations() const
Returns a list of available animations
bool haveAnimation(const std::string& animationName) const
Checks for animations with the defined name
size_t getAnimationIndex(const std::string& animationName) const
Gets an animation index by name
const std::string& getAnimationName(size_t animationIndex) const
Gets name of animation by index
void setAnimationStateChangedCallback(std::function<void(Animator&, Animator::State)>)

void setAnimationStateChangedCallback(Animator::State, std::function<void(Animator&)>)
Sets a functor that will be called upon changing the state of a specific animation. The method has an options:
  • applies only for a given state;
  • applies for any state.

Animation states:

Animator::State::Idle(Animation is not playing (including it is finished)), 
Animator::State::Play(Animation is still playing), 
Animator::State::Pause(Animation is paused)

Example:

node->setAnimationStateChangedCallback(Animator::State::Idle, [](Animator& animator)
{
    W4_LOG_DEBUG("Animator stopped:\n"
                 "\tName: %s,"
                 "\tSpeed: %f,"
                 "\tDuration: %f,"
                 "\tFps: %f",
                    animator.getName().c_str(),
                    animator.getSpeed(),
                    animator.getDuration(),
                    animator.getFps());
});
void play(const std::string& animationName, float duration = 0.f)

void play(size_t animationIndex = 0, float duration = 0.f)
Plays an animation by its index or name. Sets duration of animation, if it is equal to zero, then the entire animation is played
void play(std::initializer_list<std::pair<std::string, float>>, float duration = 0.f)

void play(std::initializer_list<std::pair<size_t, float>>, float duration = 0.f)
Plays a list of animations with weights. If duration is equal to zero, the method sets it equal to the animation with the maximum duration

Example:

skinned->play({{"run", .3f}, {"jump", .7f}});
void pause()
Pauses all active animations
void resume()
Resumes all paused animations
void stop()
Stops playing all active animations
bool isPlaying() const
Checks if any animation is playing now
Animator & getAnimator(size_t)
Animator & getAnimator(const std::string&)
const Animator & getAnimator(size_t) const
const Animator & getAnimator(const std::string&) const
Gets animator object by name or index. The Animator API, which is used to control animations with advanced features, is described below.

Managing animations through the Animator API and SkinnedMesh are not mutually exclusive. For example, the following practice of looping animations is common:

m_skinned->getAnimator("dance").setIsLooped(true);
Animator API[edit]
Method Description
void play()
Starts playing animation

If it is already playing, it will be stopped and started from the beginning

void pause()
Pauses animation playback
void resume()
Resumes animation playback
void stop()
Stops animation playback
void seek(float targetTime)
Sets current position in the animation for defined time. Values are automatically trimmed from top and bottom to the range [0; animation duration] or to the range specified by setBeginTime/setEndTime
bool isLooped() const
Returns if the loop playback state is enabled or disabled for this animation
float getSpeed() const
Gets animation playback speed multiplier (default 1.0)
State getState() const
Returns animation state

Possible animation states:

Animator::State::Idle (animation is not playing or it is finished),
Animator::State::Play (animation is still playing),
Animator::State::Pause (animation is paused)
void setPlayType(PlayType)
Sets playback direction

Possible parameter values:

Animator::PlayType::Forward,
Animator::PlayType::Backward
PlayType getPlayType() const
Returns current playing direction. For possible values see setPlayType
float getCurrentTime() const
Returns the current position in the animation
void setIsLooped(bool)
Enables/disables the loop mode for the animation
void setSpeed(float)
Sets the animation playback speed multiplier
void setBeginTime(float)
Sets the start time of the animation. It is useful for partial animation playback
void setEndTime(float)
Sets the end time of the animation. It is useful for partial animation playback
StateHandlerId setStateHandler(State state, StateHandler handler)
void resetStateHandler(StateHandlerId handler)
Sets/removes a callback to change the animation state to the specified one. Signature is callback - void (Animator &)
void setTimeHandler(float dt, TimeHandler handler)
Sets the callback to pass the specified timestamp. Signature callback - void (Animator &)
float getFps() const
Returns the number of values per second (animation characteristic)
float getDuration() const
Returns the duration of the animation

ParticlesEmitter[edit]

Special features:

  • ParticlesEmitter can only be loaded from a file;
  • The input file format is CoronaSDK (you can create it in any online editor, for example, at http://www.effecthub.com/particle2dx, save JSON with the extension part and texture and make sure that you use the path to the texture from the project root).

Bear in mind that due to the limited computational and asynchronous capabilities of WebAssembly technology currently, the particle system is displayed on a plane turned toward the camera.

API ParticlesEmitter:

Method Description
void start()
Starts particle generation
void pause()
Pauses particle generation. In this case, the processing of already released particles still continues
void resume()
Resumes particle generation
void stop()
Stops the processing of all particles
State getState() const
Gets the state

Options:

ParticlesEmitter::State::IDLE, 
ParticlesEmitter::State::STARTED, 
ParticlesEmitter::State::PAUSED

Billboard[edit]

A plane of a set size, always oriented towards the camera. It has methods getSize and setSize.

Plotter[edit]

Implementation of line drawing. The plotter data is an information about the dots (position and color) and a set of indices for pairing them.

Example:

auto plotter1 = make::sptr<Plotter>("Plotter_1");
const std::vector<uint32_t> indices = {1, 0};
const std::vector<LinesVertexFormat> vertices = {{{-10, -10, 0}, {1, 0, 0,1}},
                                                 {{10, 10, 0}, {0, 1, 0, 1}}};
plotter1->setLines(vertices, indices);

The example above will create a diagonal line with a color changing from red to green.

To create primitives, you can use static helpers that return a completed object. They are described in the Plotter class:

static w4::sptr<Plotter> build(std::vector<LinesVertexFormat> vertices, std::vector<uint32_t> indices);
static w4::sptr<Plotter> buildFromSegments(std::vector<std::array<w4::math::vec3, 2>> segments, const w4::math::vec4& color);
static w4::sptr<Plotter> buildFromPolyline(std::vector<w4::math::vec3> points, const w4::math::vec4& color);
static w4::sptr<Plotter> buildSphere(float radius, size_t rings, size_t sectors, const w4::math::vec4& color);
static w4::sptr<Plotter> buildOctahedron(std::array<w4::math::vec3, 8> vertices, const w4::math::vec4& color);
static w4::sptr<Plotter> buildCube(std::array<w4::math::vec3, 2> inVertices, const w4::math::vec4& color);
static w4::sptr<Plotter> buildCapsule(float radius, float height, size_t rings, size_t sectors, const w4::math::vec4& color);
static w4::sptr<Plotter> buildMesh(w4::cref<Mesh>, w4::math::vec4::cref color);
static w4::sptr<Plotter> buildMesh(w4::cref<SkinnedMesh>, w4::math::vec4::cref color);
static w4::sptr<Plotter> buildRay(math::vec3::cref startPoint, math::vec3::cref directionPoint, const w4::math::vec4& color);

DataNode[edit]

Unlike VisibleNode, DataNode is not displayed on the screen.

The following paragraphs describe the API for inherited classes.

ArcBallNode[edit]

Arcball implements a container (for underlying hierarchy objects) that allows you to rotate the contents as if they were in an inertia ball.

Method Description
ArcBallNode(const std::string& name = core::Object::defaultName, float radius = 1.f)
Constructor that receives the name and radius of the ball
void setFriction(float v)
Sets speed damping coefficient. Default = 0.95
void setSensitivity(float v)
Sets touch sensitivity multiplier. Default = 1
void setRadius(float r)
Sets radius of Arcball
void setVelocity(const math::Rotator& v)
Sets angular velocity
void enableUpdate(bool flag = true)
void disableUpdate()
Enables/disables arcball rotation. It does not slow down the rotation of the arcball. When turned on, it can continue to rotate (time damping)
void enableInput(bool flag = true)
void disableInput()
Enables/disables interception of touch events by arcball

Camera[edit]

Method Description
Camera(const std::string& name)
Camera(const std::string& name, float fov, float aspect, float near, float far)
Perspective camera constructors. You can specify the FOV, aspect ratio, and plane clip. FOV is set in degrees
Camera(const std::string& name, const math::size& screen, float near, float far)
Orthocamera constructor. You can specify dimensions and near/far clip plane of the camera
float getFov() const
void setFov(float v)
Gets/sets FOV. FOV is set in degrees
float getAspect() const
void setAspect(float v)
Gets/sets aspect ratio
float getNear() const
void setNear(float v)
Gets/sets near clip plane
float getFar() const
void setFar(float v)
Gets/sets far clip plane
bool getIsOrtho() const
Gets the camera type (orthocamera or not)
void setClearColor(const math::vec4& v)
Sets the color value to clear the color buffer (background color for the camera in the absence of Background or Skybox)
ClearMask getClearMask() const
void setClearMask(ClearMask v)
Gets/sets bit mask of screen cleaning mode. This value will be applied to render each frame

The default value: ClearMask::Color|ClearMask::Depth

Possible values:

None

Color (clear color buffer)

Depth (clear depth buffer)

Skybox (render skybox or not)

Background (render background or not)

bool hasSkybox() const
w4::cref<Skybox> getSkybox() const
Gets current skybox object (or "nullptr" if none)
bool hasBackground() const
w4::cref<Background> getBackground() const
Gets current background object (or "nullptr" if none)
Background[edit]

Background is a resource-friendly way to clear a color buffer with something that is more complex than a single color.

It can be used in two ways:

  1. By calling the method void setTexture (w4::cref<resources::Texture>texture). When it called, the default material is created (it simply displays the texture).
  2. By working with materials manually through the methods 'void setMaterial (w4::cref<resources::MaterialInst>)' and w4::sptr<resources::MaterialInst> getMaterial (). The vertex shader should use normalized coordinate space ([-1; 1])
Skybox[edit]

If you want to shift the background when the camera moves, you can use the Skybox object. There are two ways to used it:

1. By calling the method void setCubemap (w4::cref<resources::Cubemap> texture). When called, the default material is created (it simply displays the texture).

Example:

auto cubemap = Cubemap::get({"resources/textures/left.png",
                             "resources/textures/right.png",
                             "resources/textures/up.png",
                             "resources/textures/down.png",
                             "resources/textures/front.png",
                             "resources/textures/back.png",
                            });
m_cam->setClearMask(ClearMask::Color | ClearMask::Depth | ClearMask::Skybox);
m_cam->getSkybox()->setCubemap(cubemap);

2. By working with materials manually through the methods void setMaterial (w4::cref<resources::MaterialInst>) and w4::sptr<resources::MaterialInst> getMaterial (). The vertex shader should use normalized coordinate space ([-1; 1])

PointLight[edit]

A point source of light. It has the following API:

Method Description
math::vec3 getColor() const
void setColor(const math::vec3& c)
Gets/sets color of the light
float getIntensity() const
void setIntensity(float i)
Gets/sets brightness of the light source
core::LightDecayRate getDecayRate() const
void setDecayRate(core::LightDecayRate)
Gets/sets color fading algorithm (None, Linear, Quadratic, Cubic).

SpotLight[edit]

A directional light source in the form of a cone with a vertex at the point of the light source.

Method Description
float getAngle() const
void setAngle(float r)
Gets/sets top corner of the cone
math::vec3 getColor() const
void setColor(const math::vec3& c)
Gets/sets color of the light
float getIntensity() const
void setIntensity(float i)
Gets/sets brightness of the light source
core::LightDecayRate getDecayRate() const
void setDecayRate(core::LightDecayRate)
Gets/sets color fading algorithm (None, Linear, Quadratic, Cubic)
float getDecayFactor() const
void setDecayFactor(float f)
Gets/sets degree of fading (“transparency") of the color from 0 to 1 (default = 1)

Spline[edit]

Allows the use of trajectories imported from fbx (b-spline).

Note. In FBX format, Spline contains the only trajectory itself without a spin.

Method Description
bool isRepeatable() const
void setRepeatable(bool isRepeatable)
Gets/sets repeated playback mode
void play(float splineTime, std::function<void(const math::Transform&)> updateHandler, std::function<void(bool)> completionHandler = [](bool){})
Starts spline playback

splineTime: it is the final spline playing time which is used to calculate speed multiplier

updateHandler: Transform data comes to this method

completionHandler: This method is called when playback is completed (if no repetition is specified)

void stop()
Stops playback of transformations
bool isPlaying() const
Returns the spline state (playing or not)
bool isPaused() const
void pause()
Pauses spline playback
float getDuration() const
Returns the spline duration (in seconds)
void setPosition(float pos)
Sets position (in seconds)