Skip to content

Instantly share code, notes, and snippets.

@undefined06855
Last active June 14, 2025 21:37
Show Gist options
  • Select an option

  • Save undefined06855/54e849f7403fc5bc20dbcd1f16d58b57 to your computer and use it in GitHub Desktop.

Select an option

Save undefined06855/54e849f7403fc5bc20dbcd1f16d58b57 to your computer and use it in GitHub Desktop.
cocos2d-x perspective camera node
#include "PerspectiveNode.hpp"
PerspectiveCamera::PerspectiveCamera()
: m_dirty(true)
, m_projectionViewMatrix({ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 })
, m_aim({ 0.f, 0.f, 0.f })
, m_pos({ 0.f, 0.f, -100.f })
, m_fov(80.f) {}
void PerspectiveCamera::setFOV(float fov) {
m_fov = fov;
m_dirty = true;
}
void PerspectiveCamera::set3DPosition(cocos2d::CCPoint3D pos) {
m_pos = pos;
m_dirty = true;
}
void PerspectiveCamera::set3DAim(cocos2d::CCPoint3D aim) {
m_aim = aim;
m_dirty = true;
}
kmMat4 PerspectiveCamera::getProjectionViewMatrix() {
if (!m_dirty) return m_projectionViewMatrix;
// create projection matrix
kmMat4 proj;
auto winSize = cocos2d::CCDirector::get()->getWinSizeInPixels();
float fov = m_fov;
float aspect = winSize.width / winSize.height;
float nearZ = .1f;
float farZ = 2000.0f;
kmMat4PerspectiveProjection(&proj, fov, aspect, nearZ, farZ);
// create view matrix
kmMat4 view;
kmVec3 eye = { m_pos.x, m_pos.y, m_pos.z };
kmVec3 center = { m_aim.x, m_aim.y, m_aim.z };
kmVec3 up = { 0, 1, 0 };
kmMat4LookAt(&view, &eye, &center, &up);
kmMat4Multiply(&m_projectionViewMatrix, &proj, &view);
m_dirty = false;
return m_projectionViewMatrix;
}
float PerspectiveCamera::getFOV() {
return m_fov;
}
cocos2d::CCPoint3D PerspectiveCamera::get3DPosition() {
return m_pos;
}
cocos2d::CCPoint3D PerspectiveCamera::get3DAim() {
return m_aim;
}
PerspectiveNode::PerspectiveNode(PerspectiveCamera& camera)
: m_dirty(true)
, m_transformationMatrix({ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 })
, m_rot({ 0.f, 0.f, 0.f })
, m_pos({ 0.f, 0.f, 0.f })
, m_camera(camera) {}
PerspectiveNode* PerspectiveNode::create(PerspectiveCamera& camera) {
auto ret = new PerspectiveNode(camera);
if (ret->init(camera)) {
ret->autorelease();
return ret;
}
delete ret;
return nullptr;
}
bool PerspectiveNode::init(PerspectiveCamera& camera) {
if (!CCNode::init()) return false;
setAnchorPoint({ .5f, .5f });
return true;
}
void PerspectiveNode::visit() {
// store original projection
kmMat4 orig;
kmGLGetMatrix(KM_GL_PROJECTION, &orig);
// set perspective
kmGLMatrixMode(KM_GL_PROJECTION);
auto matrix = m_camera.getProjectionViewMatrix();
kmGLLoadMatrix(&matrix);
kmGLMatrixMode(KM_GL_MODELVIEW);
m_sTransform = cocos2d::CCAffineTransformMakeIdentity(); // dont use cocos
kmGLPushMatrix();
matrix = getTransformationMatrix();
kmGLMultMatrix(&matrix);
CCNode::visit();
kmGLPopMatrix();
// restore cocos projection (orthographic projection probably)
kmGLMatrixMode(KM_GL_PROJECTION);
kmGLLoadMatrix(&orig);
kmGLMatrixMode(KM_GL_MODELVIEW);
}
void PerspectiveNode::set3DRotation(cocos2d::CCPoint3D rot) {
m_rot = rot;
m_dirty = true;
}
void PerspectiveNode::set3DPosition(cocos2d::CCPoint3D pos) {
m_pos = pos;
m_dirty = true;
}
kmMat4 PerspectiveNode::getTransformationMatrix() {
if (!m_dirty) return m_transformationMatrix;
kmMat4 matRotX, matRotY, matRotZ, matRot, matTranslation;
kmMat4RotationX(&matRotX, kmDegreesToRadians(m_rot.x));
kmMat4RotationY(&matRotY, kmDegreesToRadians(m_rot.y));
kmMat4RotationZ(&matRotZ, kmDegreesToRadians(m_rot.z));
// z * (y * x)
kmMat4Multiply(&matRot, &matRotY, &matRotX);
kmMat4Multiply(&matRot, &matRotZ, &matRot);
kmMat4Translation(&matTranslation, m_pos.x, m_pos.y, m_pos.z);
// translation * rot
kmMat4Multiply(&m_transformationMatrix, &matTranslation, &matRot);
m_dirty = false;
return m_transformationMatrix;
}
cocos2d::CCPoint3D PerspectiveNode::get3DRotation() {
return m_rot;
}
cocos2d::CCPoint3D PerspectiveNode::get3DPosition() {
return m_pos;
}
#pragma once
namespace cocos2d {
struct CCPoint3D { float x, y, z; };
}
class PerspectiveCamera {
bool m_dirty;
kmMat4 m_projectionViewMatrix;
cocos2d::CCPoint3D m_pos;
cocos2d::CCPoint3D m_aim;
float m_fov;
public:
PerspectiveCamera();
void setFOV(float fov);
void set3DPosition(cocos2d::CCPoint3D pos);
void set3DAim(cocos2d::CCPoint3D pos);
float getFOV();
cocos2d::CCPoint3D get3DPosition();
cocos2d::CCPoint3D get3DAim();
kmMat4 getProjectionViewMatrix();
};
class PerspectiveNode : public cocos2d::CCNode {
PerspectiveNode(PerspectiveCamera& camera);
bool m_dirty;
kmMat4 m_transformationMatrix;
cocos2d::CCPoint3D m_rot;
cocos2d::CCPoint3D m_pos;
public:
static PerspectiveNode* create(PerspectiveCamera& camera);
bool init(PerspectiveCamera& camera);
PerspectiveCamera& m_camera;
void visit() override;
void set3DRotation(cocos2d::CCPoint3D rot);
void set3DPosition(cocos2d::CCPoint3D pos);
cocos2d::CCPoint3D get3DRotation();
cocos2d::CCPoint3D get3DPosition();
kmMat4 getTransformationMatrix();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment