I have created the following draws a custom scenenode which:
- Draws an object at the camera target which scales so the size in pixels stays the same.
Creates a directional light
The Light:- Rotates with the camera so the light is always to the left of the object
Is always at a fixed distance in pixels from the object
The lights rotation is set to the camera target
- Rotates with the camera so the light is always to the left of the object
The distance in pixels of the light stays the same, which implies that the distance of the light in the scene increases as i zoom out.
The situation i would like is that the lighting on the object does not change as i:
- Rotate (This already works)
Zoom
I added the code below i used some pieces of code from the forum don't remember which posts i got them from, otherwise i would refer to the original posts for some credits
.h
Code: Select all
#pragma once
#include <vector>
#include <irrlicht/ISceneNode.h>
#include <irrlicht/aabbox3d.h>
#include <irrlicht/SMaterial.h>
#include <irrlicht/vector3d.h>
// Forward declarations
namespace irr
{
namespace scene
{
class ISceneManager;
class IAnimatedMesh;
class IAnimatedMeshSceneNode;
class ICameraSceneNode;
class ILightSceneNode;
}
namespace video
{
class IVideoDriver;
}
}
class CTestSceneNode : public irr::scene::ISceneNode
{
public:
CTestSceneNode(irr::scene::ISceneNode* parent, irr::scene::ISceneManager* mgr, int id);
~CTestSceneNode(void);
void Initialize();
virtual void setMaterial(irr::video::SMaterial material);
virtual irr::video::SMaterial getMaterial(int i);
inline virtual irr::u32 getMaterialCount() const { return 1; }
virtual const irr::core::aabbox3d<float>& getBoundingBox() const;
virtual void OnRegisterSceneNode();
virtual void render();
void renderDebugData(irr::video::IVideoDriver* pDriver);
private:
float GetScreenScaleFactor(const irr::core::vector3df& worldpnt, irr::scene::ICameraSceneNode* camera);
float CalculateScale(float fBoundingBoxLegth, float fSizeNeeded, float fScreenScaleFactor);
irr::video::SMaterial m_material;
irr::core::aabbox3d<float> m_boundingBox;
irr::scene::IAnimatedMeshSceneNode* m_pConeTopSceneNode;
irr::scene::ILightSceneNode* m_pLightTopCone;
};
Code: Select all
#include "StdAfx.h"
#include "TestSceneNode.h"
#include <irrlicht/ISceneManager.h>
#include <irrlicht/ICameraSceneNode.h>
#include <irrlicht/IVideoDriver.h>
#include <irrlicht/IAnimatedMeshSceneNode.h>
#include <irrlicht/ILightSceneNode.h>
CTestSceneNode::CTestSceneNode(irr::scene::ISceneNode* parent, irr::scene::ISceneManager* mgr, int id)
: irr::scene::ISceneNode(parent, mgr, id)
, m_pConeTopSceneNode(NULL)
, m_pLightTopCone(NULL)
{
m_material.Lighting = false;
m_material.AntiAliasing = true;
m_material.BackfaceCulling = false;
setAutomaticCulling(irr::scene::EAC_OFF);
}
CTestSceneNode::~CTestSceneNode(void)
{
}
void CTestSceneNode::Initialize()
{
irr::scene::IAnimatedMesh* pConeTopMesh = SceneManager->getMesh("./resources/Objects/cone.3ds");
m_pConeTopSceneNode = SceneManager->addAnimatedMeshSceneNode(pConeTopMesh, this);
m_pConeTopSceneNode->setName("Top Cone");
//Add a light
m_pLightTopCone = SceneManager->addLightSceneNode(this);
irr::video::SLight sLightSettings;
sLightSettings.Type = irr::video::E_LIGHT_TYPE::ELT_DIRECTIONAL;
sLightSettings.CastShadows = false;
m_pLightTopCone->setLightData(sLightSettings);
m_pLightTopCone->setDebugDataVisible(irr::scene::E_DEBUG_SCENE_TYPE::EDS_BBOX);
}
void CTestSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
irr::scene::ICameraSceneNode* pActiveCamera = SceneManager->getActiveCamera();
irr::core::vector3df vCameraPosition = pActiveCamera->getAbsolutePosition();
irr::core::vector3df vCameraTarget = pActiveCamera->getTarget();
float fScreenScaleFactor = GetScreenScaleFactor(vCameraTarget, pActiveCamera);
//Calculate the position and scale of the cone
if(m_pConeTopSceneNode)
{
m_pConeTopSceneNode->setPosition(vCameraTarget);
float fScale = CalculateScale(m_pConeTopSceneNode->getBoundingBox().MinEdge.getLength(), 15, fScreenScaleFactor);
m_pConeTopSceneNode->setScale(irr::core::vector3df(fScale, fScale, fScale));
}
//Calculate the position of the light
if(m_pLightTopCone)
{
float fLightDistance = 0.200f * fScreenScaleFactor;
irr::core::vector3df vLightTopCone(vCameraTarget.X - fLightDistance, vCameraTarget.Y, vCameraTarget.Z);
irr::core::vector3df vDirectionStartToCamera = vCameraTarget - vCameraPosition;
irr::core::vector3df vHorizontalAngle = vDirectionStartToCamera.getHorizontalAngle();
vLightTopCone.rotateXZBy(-vHorizontalAngle.Y, vCameraTarget);
m_pLightTopCone->setPosition(vLightTopCone);
irr::core::vector3df diff = vCameraTarget - vLightTopCone;
m_pLightTopCone->setRotation(diff.getHorizontalAngle());
}
}
float CTestSceneNode::CalculateScale(float fBoundingBoxLegth, float fSizeNeeded, float fScreenScaleFactor)
{
float pixels = fBoundingBoxLegth / fScreenScaleFactor;
return fSizeNeeded / (pixels * 1000);
}
void CTestSceneNode::render()
{
irr::video::IVideoDriver* pDriver = SceneManager->getVideoDriver();
irr::scene::ICameraSceneNode* pCurrentCamera = SceneManager->getActiveCamera();
pDriver->setMaterial(m_material);
pDriver->setTransform(irr::video::ETS_WORLD, AbsoluteTransformation);
//Start rendering the light
//NOTE: The light is not set to invisible until all the nodes
//have been rendered onto which the light should be applied
if(m_pLightTopCone)
{
m_pLightTopCone->setVisible(true);
m_pLightTopCone->updateAbsolutePosition();
m_pLightTopCone->render();
}
if(m_pConeTopSceneNode)
{
m_pConeTopSceneNode->setVisible(true);
m_pConeTopSceneNode->updateAbsolutePosition();
m_pConeTopSceneNode->render();
m_pConeTopSceneNode->setVisible(false);
}
//All nodes were rendered set the light to invisible so it doesnt affect any other nodes
if(m_pLightTopCone)
m_pLightTopCone->setVisible(false);
}
float CTestSceneNode::GetScreenScaleFactor(const irr::core::vector3df& worldpnt, irr::scene::ICameraSceneNode* camera)
{
irr::core::vector3df viewpnt = worldpnt;
camera->getViewMatrix().transformVect(viewpnt);
return 2 * viewpnt.Z / camera->getProjectionMatrix()[0];
}
void CTestSceneNode::setMaterial(irr::video::SMaterial material)
{
m_material = material;
}
irr::video::SMaterial CTestSceneNode::getMaterial(int i)
{
irr::video::SMaterial material = m_material;
return material;
}
const irr::core::aabbox3d<float>& CTestSceneNode::getBoundingBox() const
{
irr::core::aabbox3d<float> boundingBox = m_boundingBox;
return boundingBox;
}