more hacking on rendering of virtual entities

This commit is contained in:
ZappoMan 2014-08-06 09:12:14 -07:00
parent a194db837f
commit e540bef672
8 changed files with 245 additions and 240 deletions

View file

@ -14,9 +14,15 @@
#include <FBXReader.h>
#include "InterfaceConfig.h"
#include <ModelEntityItem.h>
#include "Menu.h"
#include "EntityTreeRenderer.h"
EntityTreeRenderer::EntityTreeRenderer() :
OctreeRenderer() {
}
@ -45,36 +51,9 @@ void EntityTreeRenderer::clearModelsCache() {
_unknownEntityItemModels.clear();
}
class ModelEntityItemRenderer {
public:
static void render(EntityItem* entity) {
glm::vec3 position = entity->getPosition() * (float)TREE_SCALE;
float radius = entity->getRadius() * (float)TREE_SCALE;
glColor3f(1.0f, 0.0f, 0.0f);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
};
class BoxEntityItemRenderer {
public:
static void render(EntityItem* entity) {
glm::vec3 position = entity->getPosition() * (float)TREE_SCALE;
float size = entity->getSize() * (float)TREE_SCALE;
glColor3f(0.0f, 1.0f, 0.0f);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidCube(size);
glPopMatrix();
}
};
void EntityTreeRenderer::init() {
REGISTER_ENTITY_TYPE_RENDERER(Model)
REGISTER_ENTITY_TYPE_RENDERER(Box)
//REGISTER_ENTITY_TYPE_RENDERER(Model, this->renderEntityTypeModel);
//REGISTER_ENTITY_TYPE_RENDERER(Box, this->renderEntityTypeBox);
OctreeRenderer::init();
static_cast<EntityTree*>(_tree)->setFBXService(this);
@ -272,125 +251,86 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
// render entityItem aspoints
AACube entityCube = entityItem->getAACube();
entityCube.scale(TREE_SCALE);
// TODO: some entity types (like lights) might want to be rendered even
// when they are outside of the view frustum...
if (args->_viewFrustum->cubeInFrustum(entityCube) != ViewFrustum::OUTSIDE) {
glm::vec3 position = entityItem->getPosition() * (float)TREE_SCALE;
float radius = entityItem->getRadius() * (float)TREE_SCALE;
float size = entityItem->getSize() * (float)TREE_SCALE;
if (entityItem->getType() == EntityTypes::Model) {
renderEntityTypeModel(entityItem, args);
} else if (entityItem->getType() == EntityTypes::Box) {
renderEntityTypeBox(entityItem, args);
}
} else {
args->_itemsOutOfView++;
}
}
}
#if 0 //def HIDE_SUBCLASS_METHODS
bool drawAsModel = entityItem->hasModel();
#else
bool drawAsModel = false;
#endif
void EntityTreeRenderer::renderEntityTypeModel(EntityItem* entity, RenderArgs* args) {
assert(entity->getType() == EntityTypes::Model);
ModelEntityItem* entityItem = static_cast<ModelEntityItem*>(entity);
bool drawAsModel = entityItem->hasModel();
args->_itemsRendered++;
glm::vec3 position = entityItem->getPosition() * (float)TREE_SCALE;
float radius = entityItem->getRadius() * (float)TREE_SCALE;
float size = entity->getSize() * (float)TREE_SCALE;
if (drawAsModel) {
glPushMatrix();
{
const float alpha = 1.0f;
Model* model = getModel(*entityItem);
if (model) {
model->setScaleToFit(true, radius * 2.0f);
model->setSnapModelToCenter(true);
// set the rotation
glm::quat rotation = entityItem->getRotation();
model->setRotation(rotation);
// set the position
model->setTranslation(position);
// handle animations..
if (entityItem->hasAnimation()) {
if (!entityItem->jointsMapped()) {
QStringList modelJointNames = model->getJointNames();
entityItem->mapJoints(modelJointNames);
}
if (drawAsModel) {
#if 0 //def HIDE_SUBCLASS_METHODS
glPushMatrix();
{
const float alpha = 1.0f;
Model* model = getModel(*entityItem);
QVector<glm::quat> frameData = entityItem->getAnimationFrame();
for (int i = 0; i < frameData.size(); i++) {
model->setJointState(i, true, frameData[i]);
}
}
// make sure to simulate so everything gets set up correctly for rendering
model->simulate(0.0f);
// TODO: should we allow entityItems to have alpha on their models?
Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE
? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
if (entityItem->getGlowLevel() > 0.0f) {
Glower glower(entityItem->getGlowLevel());
if (model) {
model->setScaleToFit(true, radius * 2.0f);
model->setSnapModelToCenter(true);
// set the rotation
glm::quat rotation = entityItem->getRotation();
model->setRotation(rotation);
// set the position
model->setTranslation(position);
// handle animations..
if (entityItem->hasAnimation()) {
if (!entityItem->jointsMapped()) {
QStringList modelJointNames = model->getJointNames();
entityItem->mapJoints(modelJointNames);
}
QVector<glm::quat> frameData = entityItem->getAnimationFrame();
for (int i = 0; i < frameData.size(); i++) {
model->setJointState(i, true, frameData[i]);
}
}
// make sure to simulate so everything gets set up correctly for rendering
model->simulate(0.0f);
// TODO: should we allow entityItems to have alpha on their models?
Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE
? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
if (entityItem->getGlowLevel() > 0.0f) {
Glower glower(entityItem->getGlowLevel());
if (model->isActive()) {
model->render(alpha, modelRenderMode);
} else {
// if we couldn't get a model, then just draw a sphere
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
} else {
if (model->isActive()) {
model->render(alpha, modelRenderMode);
} else {
// if we couldn't get a model, then just draw a sphere
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
}
if (!isShadowMode && displayModelBounds) {
glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum;
glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum;
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
float width = unRotatedExtents.x;
float height = unRotatedExtents.y;
float depth = unRotatedExtents.z;
Extents rotatedExtents = model->getUnscaledMeshExtents();
calculateRotatedExtents(rotatedExtents, rotation);
glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum;
const glm::vec3& modelScale = model->getScale();
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
// draw the orignal bounding cube
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
glutWireCube(size);
// draw the rotated bounding cube
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glPushMatrix();
glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z);
glutWireCube(1.0);
glPopMatrix();
// draw the model relative bounding box
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z);
glColor3f(0.0f, 1.0f, 0.0f);
glutWireCube(1.0);
glPopMatrix();
}
if (model->isActive()) {
model->render(alpha, modelRenderMode);
} else {
// if we couldn't get a model, then just draw a sphere
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
} else {
if (model->isActive()) {
model->render(alpha, modelRenderMode);
} else {
// if we couldn't get a model, then just draw a sphere
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
@ -400,17 +340,83 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
glPopMatrix();
}
}
glPopMatrix();
#endif
bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE;
bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds);
if (!isShadowMode && displayModelBounds) {
glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum;
glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum;
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
float width = unRotatedExtents.x;
float height = unRotatedExtents.y;
float depth = unRotatedExtents.z;
Extents rotatedExtents = model->getUnscaledMeshExtents();
calculateRotatedExtents(rotatedExtents, rotation);
glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum;
const glm::vec3& modelScale = model->getScale();
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
// draw the orignal bounding cube
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
glutWireCube(size);
// draw the rotated bounding cube
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glPushMatrix();
glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z);
glutWireCube(1.0);
glPopMatrix();
// draw the model relative bounding box
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z);
glColor3f(0.0f, 1.0f, 0.0f);
glutWireCube(1.0);
glPopMatrix();
}
} else {
EntityTypes::renderEntityItem(entityItem);
// if we couldn't get a model, then just draw a sphere
glColor3ub(entityItem->getColor()[RED_INDEX],entityItem->getColor()[GREEN_INDEX],entityItem->getColor()[BLUE_INDEX]);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
} else {
args->_itemsOutOfView++;
}
glPopMatrix();
} else {
glColor3f(1.0f, 0.0f, 0.0f);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15);
glPopMatrix();
}
}
void EntityTreeRenderer::renderEntityTypeBox(EntityItem* entity, RenderArgs* args) {
assert(entity->getType() == EntityTypes::Box);
glm::vec3 position = entity->getPosition() * (float)TREE_SCALE;
float size = entity->getSize() * (float)TREE_SCALE;
glColor3f(0.0f, 1.0f, 0.0f);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glutSolidCube(size);
glPopMatrix();
};
float EntityTreeRenderer::getSizeScale() const {
return Menu::getInstance()->getVoxelSizeScale();
}

View file

@ -57,6 +57,10 @@ public:
Q_INVOKABLE Model* getModel(const EntityItem& modelItem);
// renderers for various types of entities
void renderEntityTypeBox(EntityItem* entity, RenderArgs* args);
void renderEntityTypeModel(EntityItem* entity, RenderArgs* args);
protected:
void clearModelsCache();
QMap<uint32_t, Model*> _knownEntityItemModels;

View file

@ -1085,84 +1085,6 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
}
}
#if 0 //def HIDE_SUBCLASS_METHODS
QMap<QString, AnimationPointer> EntityItem::_loadedAnimations; // TODO: improve cleanup by leveraging the AnimationPointer(s)
AnimationCache EntityItem::_animationCache;
// This class/instance will cleanup the animations once unloaded.
class EntityAnimationsBookkeeper {
public:
~EntityAnimationsBookkeeper() {
EntityItem::cleanupLoadedAnimations();
}
};
EntityAnimationsBookkeeper modelAnimationsBookkeeperInstance;
void EntityItem::cleanupLoadedAnimations() {
foreach(AnimationPointer animation, _loadedAnimations) {
animation.clear();
}
_loadedAnimations.clear();
}
Animation* EntityItem::getAnimation(const QString& url) {
AnimationPointer animation;
// if we don't already have this model then create it and initialize it
if (_loadedAnimations.find(url) == _loadedAnimations.end()) {
animation = _animationCache.getAnimation(url);
_loadedAnimations[url] = animation;
} else {
animation = _loadedAnimations[url];
}
return animation.data();
}
void EntityItem::mapJoints(const QStringList& modelJointNames) {
// if we don't have animation, or we're already joint mapped then bail early
if (!hasAnimation() || _jointMappingCompleted) {
return;
}
Animation* myAnimation = getAnimation(_animationURL);
if (!_jointMappingCompleted) {
QStringList animationJointNames = myAnimation->getJointNames();
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
_jointMapping.resize(modelJointNames.size());
for (int i = 0; i < modelJointNames.size(); i++) {
_jointMapping[i] = animationJointNames.indexOf(modelJointNames[i]);
}
_jointMappingCompleted = true;
}
}
}
QVector<glm::quat> EntityItem::getAnimationFrame() {
QVector<glm::quat> frameData;
if (hasAnimation() && _jointMappingCompleted) {
Animation* myAnimation = getAnimation(_animationURL);
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
int frameCount = frames.size();
if (frameCount > 0) {
int animationFrameIndex = (int)glm::floor(_animationFrameIndex) % frameCount;
QVector<glm::quat> rotations = frames[animationFrameIndex].rotations;
frameData.resize(_jointMapping.size());
for (int j = 0; j < _jointMapping.size(); j++) {
int rotationIndex = _jointMapping[j];
if (rotationIndex != -1 && rotationIndex < rotations.size()) {
frameData[j] = rotations[rotationIndex];
}
}
}
}
return frameData;
}
#endif
void EntityItem::update(const quint64& updateTime) {
_lastUpdated = updateTime;
setShouldBeDeleted(getShouldBeDeleted());

View file

@ -97,8 +97,6 @@ public:
glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); }
AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); } /// AACube in domain scale units (0.0 - 1.0)
static void cleanupLoadedAnimations();
protected:
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init

View file

@ -387,11 +387,11 @@ bool EntityTypes::registerEntityTypeRenderer(EntityType_t entityType, EntityType
return true;
}
void EntityTypes::renderEntityItem(EntityItem* entityItem) {
void EntityTypes::renderEntityItem(EntityItem* entityItem, RenderArgs* args) {
EntityType_t entityType = entityItem->getType();
EntityTypeRenderer renderMethod = _renderers[entityType];
if (renderMethod) {
renderMethod(entityItem);
renderMethod(entityItem, args);
}
}

View file

@ -17,13 +17,15 @@
#include <QHash>
#include <QString>
#include <OctreeRenderer.h> // for RenderArgs
class EntityItem;
class EntityItemID;
class EntityItemProperties;
class ReadBitstreamToTreeParams;
typedef EntityItem* (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties);
typedef void (*EntityTypeRenderer)(EntityItem* entity);
typedef void (*EntityTypeRenderer)(EntityItem* entity, RenderArgs* args);
class EntityTypes {
public:
@ -47,7 +49,7 @@ public:
EntityItemID& entityID, EntityItemProperties& properties);
static bool registerEntityTypeRenderer(EntityType_t entityType, EntityTypeRenderer renderMethod);
static void renderEntityItem(EntityItem* entityItem);
static void renderEntityItem(EntityItem* entityItem, RenderArgs* args);
private:
static QMap<EntityType_t, QString> _typeToNameMap;
@ -65,10 +67,7 @@ private:
#define REGISTER_ENTITY_TYPE(x) static bool x##Registration = \
EntityTypes::registerEntityType(EntityTypes::x, #x, x##EntityItem::factory);
#define REGISTER_ENTITY_TYPE_RENDERER(x) static bool x##RendererRegistration = \
EntityTypes::registerEntityTypeRenderer(EntityTypes::x, x##EntityItemRenderer::render); \
x##RendererRegistration = x##RendererRegistration;
#define REGISTER_ENTITY_TYPE_RENDERER(x,y) EntityTypes::registerEntityTypeRenderer(EntityTypes::x, y);
#endif // hifi_EntityTypes_h

View file

@ -16,9 +16,6 @@
#include "ModelEntityItem.h"
//EntityTypes::registerEntityType(EntityTypes::Model, "Model", ModelEntityItem::factory);
EntityItem* ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
qDebug() << "ModelEntityItem::factory(const EntityItemID& entityItemID, const EntityItemProperties& properties)...";
return new ModelEntityItem(entityID, properties);
@ -778,4 +775,81 @@ qDebug() << "ModelEntityItem::appendEntityData()... modelURL=" << getModelURL();
}
return appendState;
}
}
QMap<QString, AnimationPointer> ModelEntityItem::_loadedAnimations; // TODO: improve cleanup by leveraging the AnimationPointer(s)
AnimationCache ModelEntityItem::_animationCache;
// This class/instance will cleanup the animations once unloaded.
class EntityAnimationsBookkeeper {
public:
~EntityAnimationsBookkeeper() {
ModelEntityItem::cleanupLoadedAnimations();
}
};
EntityAnimationsBookkeeper modelAnimationsBookkeeperInstance;
void ModelEntityItem::cleanupLoadedAnimations() {
foreach(AnimationPointer animation, _loadedAnimations) {
animation.clear();
}
_loadedAnimations.clear();
}
Animation* ModelEntityItem::getAnimation(const QString& url) {
AnimationPointer animation;
// if we don't already have this model then create it and initialize it
if (_loadedAnimations.find(url) == _loadedAnimations.end()) {
animation = _animationCache.getAnimation(url);
_loadedAnimations[url] = animation;
} else {
animation = _loadedAnimations[url];
}
return animation.data();
}
void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
// if we don't have animation, or we're already joint mapped then bail early
if (!hasAnimation() || _jointMappingCompleted) {
return;
}
Animation* myAnimation = getAnimation(_animationURL);
if (!_jointMappingCompleted) {
QStringList animationJointNames = myAnimation->getJointNames();
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
_jointMapping.resize(modelJointNames.size());
for (int i = 0; i < modelJointNames.size(); i++) {
_jointMapping[i] = animationJointNames.indexOf(modelJointNames[i]);
}
_jointMappingCompleted = true;
}
}
}
QVector<glm::quat> ModelEntityItem::getAnimationFrame() {
QVector<glm::quat> frameData;
if (hasAnimation() && _jointMappingCompleted) {
Animation* myAnimation = getAnimation(_animationURL);
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
int frameCount = frames.size();
if (frameCount > 0) {
int animationFrameIndex = (int)glm::floor(_animationFrameIndex) % frameCount;
QVector<glm::quat> rotations = frames[animationFrameIndex].rotations;
frameData.resize(_jointMapping.size());
for (int j = 0; j < _jointMapping.size(); j++) {
int rotationIndex = _jointMapping[j];
if (rotationIndex != -1 && rotationIndex < rotations.size()) {
frameData[j] = rotations[rotationIndex];
}
}
}
}
return frameData;
}

View file

@ -71,6 +71,8 @@ public:
float getAnimationFrameIndex() const { return _animationFrameIndex; }
float getAnimationFPS() const { return _animationFPS; }
static void cleanupLoadedAnimations();
protected:
rgbColor _color;