Fix #1795, fix #2755 and fix #2886

Allow using bone attachment in straight-frame static mesh.

Advanced headlight rendering with light origin from center mass
of headlight model which can be bound to any bone in kart model
This commit is contained in:
Benau 2017-09-15 16:14:57 +08:00
parent 32243e7eb3
commit 00660293b7
8 changed files with 181 additions and 155 deletions

View File

@ -153,13 +153,6 @@ void ShaderBasedRenderer::prepareForwardRenderer()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
// ----------------------------------------------------------------------------
void ShaderBasedRenderer::updateLightsInfo(scene::ICameraSceneNode * const camnode,
float dt)
{
m_lighting_passes.updateLightsInfo(camnode, dt);
}
// ----------------------------------------------------------------------------
/** Upload lighting info to the dedicated uniform buffer
*/
@ -257,6 +250,10 @@ void ShaderBasedRenderer::renderScene(scene::ICameraSceneNode * const camnode,
m_poly_count[SOLID_NORMAL_AND_DEPTH_PASS] += solid_poly_count;
m_poly_count[SHADOW_PASS] += shadow_poly_count;
PROFILER_POP_CPU_MARKER();
// For correct position of headlight in karts
PROFILER_PUSH_CPU_MARKER("Update Light Info", 0xFF, 0x0, 0x0);
m_lighting_passes.updateLightsInfo(camnode, dt);
PROFILER_POP_CPU_MARKER();
#if !defined(USE_GLES2)
// Shadows
@ -806,9 +803,6 @@ void ShaderBasedRenderer::render(float dt)
if (!CVS->isDefferedEnabled())
glEnable(GL_FRAMEBUFFER_SRGB);
PROFILER_PUSH_CPU_MARKER("Update Light Info", 0xFF, 0x0, 0x0);
m_lighting_passes.updateLightsInfo(camnode, dt);
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("UBO upload", 0x0, 0xFF, 0x0);
computeMatrixesAndCameras(camnode, m_rtts->getWidth(), m_rtts->getHeight());
m_shadow_matrices.updateSunOrthoMatrices();
@ -920,7 +914,6 @@ void ShaderBasedRenderer::renderToTexture(GL3RenderTarget *render_target,
irr_driver->getSceneManager()->setActiveCamera(camera);
computeMatrixesAndCameras(camera, m_rtts->getWidth(), m_rtts->getHeight());
updateLightsInfo(camera, dt);
if (CVS->isARBUniformBufferObjectUsable())
uploadLightingData();

View File

@ -60,10 +60,7 @@ private:
void removeItemsInGlowingList();
void prepareForwardRenderer();
void updateLightsInfo(irr::scene::ICameraSceneNode * const camnode,
float dt);
void uploadLightingData() const;
void computeMatrixesAndCameras(scene::ICameraSceneNode * const camnode,

View File

@ -167,10 +167,7 @@ public:
// Access to the graphical kart model.
// ------------------------------------------------------------------------
/** Returns this kart's kart model. */
KartModel* getKartModel() { return m_kart_model; }
// ------------------------------------------------------------------------
/** Returns this kart's kart model. */
const KartModel* getKartModel() const { return m_kart_model; }
KartModel* getKartModel() const { return m_kart_model; }
// ------------------------------------------------------------------------
/** Returns the length of the kart. */
float getKartLength() const { return m_kart_length; }

View File

@ -235,7 +235,7 @@ void Kart::init(RaceManager::KartType type)
}
loadData(type, animations);
m_kart_gfx = new KartGFX(this, m_type, Track::getCurrentTrack()->getIsDuringDay());
m_kart_gfx = new KartGFX(this, Track::getCurrentTrack()->getIsDuringDay());
m_skidding = new Skidding(this);
// Create the stars effect
m_stars_effect = new Stars(this);

View File

@ -36,12 +36,11 @@
#include <iostream>
KartGFX::KartGFX(const AbstractKart *kart, RaceManager::KartType type, bool is_day)
KartGFX::KartGFX(const AbstractKart *kart, bool is_day)
{
m_nitro_light = NULL;
m_skidding_light_1 = NULL;
m_skidding_light_2 = NULL;
m_head_light = NULL;
m_kart = kart;
m_wheel_toggle = 0;
m_skid_level = 0;
@ -80,22 +79,11 @@ KartGFX::KartGFX(const AbstractKart *kart, RaceManager::KartType type, bool is_d
0.05f), /* force */0.4f, /*radius*/4.0f,
1.0f, 0.0f, 0.0f, false, node);
m_skidding_light_2->setVisible(false);
m_skidding_light_2->setName(("skidding emitter 2 (" + m_kart->getIdent()
+ ")").c_str() );
m_head_light =
irr_driver->addLight(core::vector3df(0.0f, 0.2f, 1.5f * length),
/* force */ 0.5f, /*radius*/5.0f, 1.0f, 1.0f,
1.0f, false, node);
m_head_light->setName( ("head light " + m_kart->getIdent()
+ ")").c_str() );
m_head_light->setVisible(type == RaceManager::KT_PLAYER && !is_day);
m_skidding_light_2->setName(("skidding emitter 2 (" + m_kart->getIdent()
+ ")").c_str() );
m_nitro_light->grab();
m_skidding_light_1->grab();
m_skidding_light_2->grab();
m_head_light->grab();
}
#endif
@ -149,7 +137,6 @@ KartGFX::~KartGFX()
m_nitro_light->drop();
m_skidding_light_1->drop();
m_skidding_light_2->drop();
m_head_light->drop();
}
#endif
@ -560,7 +547,7 @@ void KartGFX::setGFXInvisible()
m_nitro_light->setVisible(false);
m_skidding_light_1->setVisible(false);
m_skidding_light_2->setVisible(false);
m_head_light->setVisible(false);
m_kart->getKartModel()->turnOffHeadlights();
}
#endif
} // setGFXInvisible

View File

@ -24,7 +24,6 @@
#include <vector>
#include <string>
#include "race/race_manager.hpp"
class AbstractKart;
class ParticleEmitter;
@ -90,15 +89,12 @@ private:
/** A light that's shown on the second skid-level with another color. */
irr::scene::ISceneNode* m_skidding_light_2;
/** A light that's shown on the second skid-level with another color. */
irr::scene::ISceneNode* m_head_light;
void addEffect(KartGFXType type, const std::string &file_name,
const Vec3 &position, bool important);
void resizeBox(const KartGFXType type, float new_size);
public:
KartGFX(const AbstractKart *kart, RaceManager::KartType type, bool is_day);
KartGFX(const AbstractKart *kart, bool is_day);
~KartGFX();
void reset();
void setSkidLevel(const unsigned int level);

View File

@ -117,9 +117,7 @@ KartModel::KartModel(bool is_master)
m_is_master = is_master;
m_kart = NULL;
m_mesh = NULL;
m_hat_name = "";
m_hat_node = NULL;
m_hat_offset = core::vector3df(0,0,0);
m_hat_location = NULL;
m_render_info = NULL;
for(unsigned int i=0; i<4; i++)
@ -159,6 +157,7 @@ KartModel::KartModel(bool is_master)
*/
void KartModel::loadInfo(const XMLNode &node)
{
node.get("version", &m_version);
node.get("model-file", &m_model_filename);
if(const XMLNode *animation_node=node.getNode("animations"))
{
@ -195,11 +194,6 @@ void KartModel::loadInfo(const XMLNode &node)
loadWheelInfo(*wheels_node, "rear-right", 2);
loadWheelInfo(*wheels_node, "rear-left", 3);
}
if (const XMLNode *headlights_node = node.getNode("headlights"))
{
loadHeadlights(*headlights_node);
}
m_nitro_emitter_position[0] = Vec3 (0,0.1f,0);
m_nitro_emitter_position[1] = Vec3 (0,0.1f,0);
@ -223,10 +217,27 @@ void KartModel::loadInfo(const XMLNode &node)
}
}
if(const XMLNode *hat_node=node.getNode("hat"))
if (m_version > 2)
{
hat_node->get("offset", &m_hat_offset);
if (const XMLNode* headlights_node = node.getNode("headlights"))
{
loadHeadlights(*headlights_node);
}
if (const XMLNode* hat_node = node.getNode("hat"))
{
core::vector3df position, rotation, scale;
hat_node->get("position", &position);
hat_node->get("rotation", &rotation);
hat_node->get("scale", &scale);
core::matrix4 lm, sm, rm;
lm.setTranslation(position);
sm.setScale(scale);
rm.setRotationDegrees(rotation);
m_hat_location = new core::matrix4(lm * rm * sm);
hat_node->get("bone", &m_hat_bone);
}
}
} // loadInfo
// ----------------------------------------------------------------------------
@ -298,6 +309,7 @@ KartModel::~KartModel()
}
}
delete m_hat_location;
delete m_render_info;
#ifdef DEBUG
#if SKELETON_DEBUG
@ -322,6 +334,7 @@ KartModel* KartModel::makeCopy(KartRenderType krt)
assert(m_render_info == NULL);
assert(!m_animated_node);
KartModel *km = new KartModel(/*is master*/ false);
km->m_version = m_version;
km->m_kart_width = m_kart_width;
km->m_kart_length = m_kart_length;
km->m_kart_height = m_kart_height;
@ -332,8 +345,8 @@ KartModel* KartModel::makeCopy(KartRenderType krt)
km->m_animation_speed = m_animation_speed;
km->m_current_animation = AF_DEFAULT;
km->m_animated_node = NULL;
km->m_hat_offset = m_hat_offset;
km->m_hat_name = m_hat_name;
km->m_hat_bone = m_hat_bone;
km->m_krt = krt;
km->m_support_colorization = m_support_colorization;
km->m_render_info = new RenderInfo();
@ -342,6 +355,11 @@ KartModel* KartModel::makeCopy(KartRenderType krt)
km->m_nitro_emitter_position[0] = m_nitro_emitter_position[0];
km->m_nitro_emitter_position[1] = m_nitro_emitter_position[1];
km->m_has_nitro_emitter = m_has_nitro_emitter;
if (m_hat_location)
{
km->m_hat_location = new core::matrix4();
*(km->m_hat_location) = *m_hat_location;
}
for(unsigned int i=0; i<4; i++)
{
@ -383,7 +401,7 @@ KartModel* KartModel::makeCopy(KartRenderType krt)
/** Attach the kart model and wheels to the scene node.
* \return the node with the model attached
*/
scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_animated)
scene::ISceneNode* KartModel::attachModel(bool animated_models, bool human_player)
{
assert(!m_is_master);
@ -401,7 +419,7 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
NULL/*parent*/, getRenderInfo());
node->setAutomaticCulling(scene::EAC_FRUSTUM_BOX);
#endif
if (always_animated)
if (human_player)
{
// give a huge LOD distance for the player's kart. the reason is that it should
// use its animations for the shadow pass too, where the camera can be quite far
@ -418,8 +436,6 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
m_animated_node = static_cast<scene::IAnimatedMeshSceneNode*>(node);
}
attachHat();
#ifdef DEBUG
std::string debug_name = m_model_filename+" (animated-kart-model)";
node->setName(debug_name.c_str());
@ -445,12 +461,6 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
m_speed_weighted_objects[i].m_node->setParent(lod_node);
}
for (size_t i = 0; i<m_headlight_objects.size(); i++)
{
if (!m_headlight_objects[i].getNode()) continue;
m_headlight_objects[i].getNode()->setParent(lod_node);
}
#ifndef SERVER_ONLY
// Enable rim lighting for the kart
irr_driver->applyObjectPassShader(lod_node, true);
@ -528,28 +538,48 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim
obj.m_node->setPosition(obj.m_position.toIrrVector());
}
}
for (unsigned int i = 0; i < m_headlight_objects.size(); i++)
{
HeadlightObject& obj = m_headlight_objects[i];
obj.setNode(NULL);
if (obj.getModel())
{
scene::ISceneNode *new_node =
irr_driver->addMesh(obj.getModel(), "kart_headlight",
node, getRenderInfo() );
new_node->grab();
obj.setNode(new_node);
Track* track = Track::getCurrentTrack();
if (track == NULL || track->getIsDuringDay())
obj.getNode()->setVisible(false);
}
}
}
const float each_energy = 0.2f / m_headlight_objects.size();
const float each_radius = 2.0f / m_headlight_objects.size();
for (unsigned int i = 0; i < m_headlight_objects.size(); i++)
{
HeadlightObject& obj = m_headlight_objects[i];
Track* track = Track::getCurrentTrack();
if (obj.getModel() && !(track == NULL || track->getIsDuringDay()))
{
const bool bone_attachment =
m_animated_node && !obj.getBoneName().empty();
scene::ISceneNode* parent = bone_attachment ?
m_animated_node->getJointNode(obj.getBoneName().c_str()) : node;
scene::ISceneNode* new_node =
irr_driver->addMesh(obj.getModel(), "kart_headlight",
parent, getRenderInfo());
#ifndef SERVER_ONLY
if (human_player && CVS->isGLSL() && CVS->isDefferedEnabled())
{
obj.setNode(irr_driver->addLight(core::vector3df
(0.0f, 0.0f, 0.0f), each_energy, each_radius,
1.0f, 1.0f, 1.0f, false, new_node));
obj.getNode()->grab();
}
#endif
configNode(new_node, obj.getLocation(), bone_attachment ?
getInverseBoneMatrix(obj.getBoneName().c_str()) : core::matrix4());
}
}
if (m_hat_location && !m_hat_name.empty())
{
const bool bone_attachment = m_animated_node && !m_hat_bone.empty();
scene::ISceneNode* parent = bone_attachment ?
m_animated_node->getJointNode(m_hat_bone.c_str()) : node;
scene::IMesh* hat_mesh = irr_driver->getAnimatedMesh
(file_manager->getAsset(FileManager::MODEL, m_hat_name));
scene::ISceneNode* node = irr_driver->addMesh(hat_mesh, "hat", parent);
configNode(node, *m_hat_location, bone_attachment ?
getInverseBoneMatrix(m_hat_bone.c_str()) : core::matrix4());
}
return node;
} // attachModel
@ -770,14 +800,20 @@ void KartModel::loadHeadlights(const XMLNode &node)
const XMLNode* child = node.getNode(i);
if (child->getName() == "object")
{
// <object position="-0.168000 0.151288 0.917929" model="TuxHeadlight.spm"/>
core::vector3df position;
core::vector3df position, rotation, scale;
child->get("position", &position);
child->get("rotation", &rotation);
child->get("scale", &scale);
core::matrix4 lm, sm, rm;
lm.setTranslation(position);
sm.setScale(scale);
rm.setRotationDegrees(rotation);
core::matrix4 location = lm * rm * sm;
std::string bone_name;
child->get("bone", &bone_name);
std::string model;
child->get("model", &model);
m_headlight_objects.push_back(HeadlightObject(model, position));
m_headlight_objects.push_back(HeadlightObject(model, location, bone_name));
}
else
{
@ -809,6 +845,15 @@ void KartModel::reset()
LODNode *lod = dynamic_cast<LODNode*>(m_kart->getNode());
if (lod)
lod->forceLevelOfDetail(-1);
for (unsigned int i = 0; i < m_headlight_objects.size(); i++)
{
HeadlightObject& obj = m_headlight_objects[i];
if (obj.getNode())
{
obj.getNode()->setVisible(true);
}
}
} // reset
// ----------------------------------------------------------------------------
@ -1123,55 +1168,47 @@ void KartModel::resetVisualWheelPosition()
} // for i < 4
} // resetVisualSuspension
//-----------------------------------------------------------------------------
void KartModel::attachHat()
{
m_hat_node = NULL;
if(m_hat_name.size()>0)
{
scene::IBoneSceneNode *bone = m_animated_node->getJointNode("Head");
if(!bone)
bone = m_animated_node->getJointNode("head");
if(bone)
{
// Till we have all models fixed, accept Head and head as bone name
scene::IMesh *hat_mesh =
irr_driver->getAnimatedMesh(
file_manager->getAsset(FileManager::MODEL, m_hat_name));
m_hat_node = irr_driver->addMesh(hat_mesh, "hat");
bone->addChild(m_hat_node);
m_animated_node->setCurrentFrame((float)m_animation_frame[AF_STRAIGHT]);
#ifndef SERVER_ONLY
STKAnimatedMesh* am = dynamic_cast<STKAnimatedMesh*>(m_animated_node);
if (am)
{
am->setHardwareSkinning(false);
am->OnAnimate(0);
am->setHardwareSkinning(true);
}
else
#endif
m_animated_node->OnAnimate(0);
bone->updateAbsolutePosition();
// With the hat node attached to the head bone, we have to
// reverse the transformation of the bone, so that the hat
// is still properly placed. Esp. the hat offset needs
// to be rotated.
const core::matrix4 mat = bone->getAbsoluteTransformation();
core::matrix4 inv;
mat.getInverse(inv);
core::vector3df rotated_offset;
inv.rotateVect(rotated_offset, m_hat_offset);
m_hat_node->setPosition(rotated_offset);
m_hat_node->setScale(inv.getScale());
m_hat_node->setRotation(inv.getRotationDegrees());
} // if bone
} // if(m_hat_name)
} // attachHat
//-----------------------------------------------------------------------------
RenderInfo* KartModel::getRenderInfo()
{
return m_support_colorization || m_krt == KRT_TRANSPARENT ?
m_render_info : NULL;
} // getRenderInfo
//-----------------------------------------------------------------------------
void KartModel::turnOffHeadlights()
{
for (unsigned int i = 0; i < m_headlight_objects.size(); i++)
{
HeadlightObject& obj = m_headlight_objects[i];
if (obj.getNode())
{
obj.getNode()->setVisible(false);
}
}
} // turnOffHeadlights
//-----------------------------------------------------------------------------
core::matrix4 KartModel::getInverseBoneMatrix(const char* bone_name)
{
assert(m_animated_node);
scene::IBoneSceneNode* bone = m_animated_node->getJointNode(bone_name);
assert(bone);
m_animated_node->setCurrentFrame((float)m_animation_frame[AF_STRAIGHT]);
#ifndef SERVER_ONLY
STKAnimatedMesh* am = dynamic_cast<STKAnimatedMesh*>(m_animated_node);
if (am)
{
am->setHardwareSkinning(false);
am->OnAnimate(0);
am->setHardwareSkinning(true);
}
else
#endif
m_animated_node->OnAnimate(0);
bone->updateAbsolutePosition();
const core::matrix4 mat = bone->getAbsoluteTransformation();
core::matrix4 inv;
mat.getInverse(inv);
return inv;
} // getInverseBoneMatrix

View File

@ -92,30 +92,32 @@ class HeadlightObject
private:
/** The filename of the headlight model. */
std::string m_filename;
/** The position relative to the parent kart scene node where the
* headlight mesh is attached to. */
core::vector3df m_position;
/** The relative matrix to the parent kart scene node
* or bone where the headlight mesh is attached to. */
core::matrix4 m_location;
/** The mesh for the headlight. */
scene::IMesh* m_model;
/** The scene node of the headlight. */
scene::ISceneNode* m_node;
std::string m_bone_name;
public:
HeadlightObject()
{
m_model = NULL;
m_node = NULL;
m_filename = "";
m_position.set(0, 0, 0);
} // HeadlightObject
// ------------------------------------------------------------------------
HeadlightObject(const std::string& filename, core::vector3df &pos)
HeadlightObject(const std::string& filename, const core::matrix4& location,
const std::string& bone_name)
{
m_filename = filename;
m_position = pos;
m_location = location;
m_model = NULL;
m_node = NULL;
m_bone_name = bone_name;
} // HeadlightObjects
// ------------------------------------------------------------------------
const std::string& getFilename() const { return m_filename; }
@ -123,12 +125,10 @@ public:
/** Sets the mesh for this headlight object. */
void setModel(scene::IMesh *mesh) { m_model = mesh; }
// ------------------------------------------------------------------------
/** Sets the node of the headlight, and (if not NULL) also sets the
* position of this scene node to be the position of the headlight. */
/** Sets the node of the headlight. */
void setNode(scene::ISceneNode *node)
{
m_node = node;
if (m_node) m_node->setPosition(m_position);
m_node = node;
} // setNode
// ------------------------------------------------------------------------
const scene::ISceneNode *getNode() const { return m_node; }
@ -139,6 +139,10 @@ public:
// ------------------------------------------------------------------------
scene::IMesh *getModel() { return m_model; }
// ------------------------------------------------------------------------
const core::matrix4& getLocation() const { return m_location; }
// ------------------------------------------------------------------------
const std::string& getBoneName() const { return m_bone_name; }
// ------------------------------------------------------------------------
}; // class HeadlightObject
// ============================================================================
@ -198,11 +202,11 @@ private:
* (i.e. neither read nor written) if animations are disabled. */
scene::IAnimatedMeshSceneNode *m_animated_node;
/** The scene node for a hat the driver is wearing. */
scene::IMeshSceneNode *m_hat_node;
/** Location of hat in object space. */
core::matrix4* m_hat_location;
/** Offset of the hat relative to the bone called 'head'. */
core::vector3df m_hat_offset;
/** Name of the bone for hat attachment. */
std::string m_hat_bone;
/** Name of the hat to use for this kart. "" if no hat. */
std::string m_hat_name;
@ -307,6 +311,23 @@ private:
bool m_support_colorization;
unsigned m_version;
// ------------------------------------------------------------------------
core::matrix4 getInverseBoneMatrix(const char* bone_name);
// ------------------------------------------------------------------------
void configNode(scene::ISceneNode* node, const core::matrix4& global_mat,
const core::matrix4& inv_mat)
{
const core::matrix4 mat = inv_mat * global_mat;
const core::vector3df position = mat.getTranslation();
const core::vector3df rotation = mat.getRotationDegrees();
const core::vector3df scale = mat.getScale();
node->setPosition(position);
node->setRotation(rotation);
node->setScale(scale);
}
public:
KartModel(bool is_master);
~KartModel();
@ -321,7 +342,7 @@ public:
void finishedRace();
void resetVisualWheelPosition();
scene::ISceneNode*
attachModel(bool animatedModels, bool always_animated);
attachModel(bool animatedModels, bool human_player);
// ------------------------------------------------------------------------
/** Returns the animated mesh of this kart model. */
scene::IAnimatedMesh*
@ -403,18 +424,16 @@ public:
/** Name of the hat mesh to use. */
void setHatMeshName(const std::string &name) {m_hat_name = name; }
// ------------------------------------------------------------------------
void attachHat();
// ------------------------------------------------------------------------
/** Returns the array of wheel nodes. */
scene::ISceneNode** getWheelNodes() { return m_wheel_node; }
// ------------------------------------------------------------------------
scene::IAnimatedMeshSceneNode* getAnimatedNode(){ return m_animated_node; }
// ------------------------------------------------------------------------
core::vector3df getHatOffset() { return m_hat_offset; }
// ------------------------------------------------------------------------
RenderInfo* getRenderInfo();
// ------------------------------------------------------------------------
bool supportColorization() const { return m_support_colorization; }
// ------------------------------------------------------------------------
void turnOffHeadlights();
}; // KartModel
#endif