mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 06:13:09 +02:00
Merge pull request #2815 from ZappoMan/modelserver
More Model Improvements & some other tweaks
This commit is contained in:
commit
538e785208
27 changed files with 359 additions and 103 deletions
|
@ -2373,8 +2373,8 @@ void Application::updateShadowMap() {
|
||||||
updateUntranslatedViewMatrix();
|
updateUntranslatedViewMatrix();
|
||||||
|
|
||||||
_avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
|
_avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
|
||||||
_particles.render();
|
_particles.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||||
_models.render();
|
_models.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
|
|
|
@ -292,7 +292,6 @@ Menu::Menu() :
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false);
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true);
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Models, 0, true);
|
|
||||||
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools()));
|
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools()));
|
||||||
|
|
||||||
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options");
|
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options");
|
||||||
|
@ -309,6 +308,12 @@ Menu::Menu() :
|
||||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges);
|
||||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableAutoAdjustLOD);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableAutoAdjustLOD);
|
||||||
|
|
||||||
|
QMenu* modelOptionsMenu = developerMenu->addMenu("Model Options");
|
||||||
|
addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::Models, 0, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelBounds, 0, false);
|
||||||
|
addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementProxy, 0, false);
|
||||||
|
addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementChildProxies, 0, false);
|
||||||
|
|
||||||
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");
|
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true);
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true);
|
||||||
|
|
|
@ -304,6 +304,9 @@ namespace MenuOption {
|
||||||
const QString DisplayFrustum = "Display Frustum";
|
const QString DisplayFrustum = "Display Frustum";
|
||||||
const QString DisplayHands = "Display Hands";
|
const QString DisplayHands = "Display Hands";
|
||||||
const QString DisplayHandTargets = "Display Hand Targets";
|
const QString DisplayHandTargets = "Display Hand Targets";
|
||||||
|
const QString DisplayModelBounds = "Display Model Bounds";
|
||||||
|
const QString DisplayModelElementProxy = "Display Model Element Bounds";
|
||||||
|
const QString DisplayModelElementChildProxies = "Display Model Element Children";
|
||||||
const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes";
|
const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes";
|
||||||
const QString EchoLocalAudio = "Echo Local Audio";
|
const QString EchoLocalAudio = "Echo Local Audio";
|
||||||
const QString EchoServerAudio = "Echo Server Audio";
|
const QString EchoServerAudio = "Echo Server Audio";
|
||||||
|
@ -338,6 +341,7 @@ namespace MenuOption {
|
||||||
const QString Metavoxels = "Metavoxels";
|
const QString Metavoxels = "Metavoxels";
|
||||||
const QString Mirror = "Mirror";
|
const QString Mirror = "Mirror";
|
||||||
const QString Models = "Models";
|
const QString Models = "Models";
|
||||||
|
const QString ModelOptions = "Model Options";
|
||||||
const QString MoveWithLean = "Move with Lean";
|
const QString MoveWithLean = "Move with Lean";
|
||||||
const QString MuteAudio = "Mute Microphone";
|
const QString MuteAudio = "Mute Microphone";
|
||||||
const QString MuteEnvironment = "Mute Environment";
|
const QString MuteEnvironment = "Mute Environment";
|
||||||
|
|
|
@ -215,17 +215,20 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
|
||||||
renderBody(renderMode, glowLevel);
|
renderBody(renderMode, glowLevel);
|
||||||
}
|
}
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) {
|
if (renderMode != SHADOW_RENDER_MODE &&
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) {
|
||||||
_skeletonModel.updateShapePositions();
|
_skeletonModel.updateShapePositions();
|
||||||
_skeletonModel.renderJointCollisionShapes(0.7f);
|
_skeletonModel.renderJointCollisionShapes(0.7f);
|
||||||
}
|
}
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes)) {
|
if (renderMode != SHADOW_RENDER_MODE &&
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes)) {
|
||||||
if (shouldRenderHead(cameraPosition, renderMode)) {
|
if (shouldRenderHead(cameraPosition, renderMode)) {
|
||||||
getHead()->getFaceModel().updateShapePositions();
|
getHead()->getFaceModel().updateShapePositions();
|
||||||
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
|
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes)) {
|
if (renderMode != SHADOW_RENDER_MODE &&
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes)) {
|
||||||
if (shouldRenderHead(cameraPosition, renderMode)) {
|
if (shouldRenderHead(cameraPosition, renderMode)) {
|
||||||
getHead()->getFaceModel().updateShapePositions();
|
getHead()->getFaceModel().updateShapePositions();
|
||||||
getHead()->getFaceModel().renderBoundingCollisionShapes(0.7f);
|
getHead()->getFaceModel().renderBoundingCollisionShapes(0.7f);
|
||||||
|
@ -234,7 +237,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If this is the avatar being looked at, render a little ball above their head
|
// If this is the avatar being looked at, render a little ball above their head
|
||||||
if (_isLookAtTarget) {
|
if (renderMode != SHADOW_RENDER_MODE &&_isLookAtTarget) {
|
||||||
const float LOOK_AT_INDICATOR_RADIUS = 0.03f;
|
const float LOOK_AT_INDICATOR_RADIUS = 0.03f;
|
||||||
const float LOOK_AT_INDICATOR_HEIGHT = 0.60f;
|
const float LOOK_AT_INDICATOR_HEIGHT = 0.60f;
|
||||||
const float LOOK_AT_INDICATOR_COLOR[] = { 0.8f, 0.0f, 0.0f, 0.5f };
|
const float LOOK_AT_INDICATOR_COLOR[] = { 0.8f, 0.0f, 0.0f, 0.5f };
|
||||||
|
@ -340,7 +343,8 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
||||||
|
|
||||||
void Avatar::renderBody(RenderMode renderMode, float glowLevel) {
|
void Avatar::renderBody(RenderMode renderMode, float glowLevel) {
|
||||||
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
|
||||||
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||||
|
|
||||||
{
|
{
|
||||||
Glower glower(glowLevel);
|
Glower glower(glowLevel);
|
||||||
|
|
||||||
|
@ -351,7 +355,7 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) {
|
||||||
}
|
}
|
||||||
_skeletonModel.render(1.0f, modelRenderMode);
|
_skeletonModel.render(1.0f, modelRenderMode);
|
||||||
renderAttachments(modelRenderMode);
|
renderAttachments(modelRenderMode);
|
||||||
getHand()->render(false);
|
getHand()->render(false, modelRenderMode);
|
||||||
}
|
}
|
||||||
getHead()->render(1.0f, modelRenderMode);
|
getHead()->render(1.0f, modelRenderMode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,11 +192,11 @@ void Hand::calculateGeometry() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hand::render(bool isMine) {
|
void Hand::render(bool isMine, Model::RenderMode renderMode) {
|
||||||
|
|
||||||
_renderAlpha = 1.0;
|
_renderAlpha = 1.0;
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) {
|
if (renderMode != Model::SHADOW_RENDER_MODE &&
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) {
|
||||||
// draw a green sphere at hand joint location, which is actually near the wrist)
|
// draw a green sphere at hand joint location, which is actually near the wrist)
|
||||||
for (size_t i = 0; i < getNumPalms(); i++) {
|
for (size_t i = 0; i < getNumPalms(); i++) {
|
||||||
PalmData& palm = getPalms()[i];
|
PalmData& palm = getPalms()[i];
|
||||||
|
@ -212,7 +212,7 @@ void Hand::render(bool isMine) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) {
|
if (renderMode != Model::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) {
|
||||||
renderLeapHands(isMine);
|
renderLeapHands(isMine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <HandData.h>
|
#include <HandData.h>
|
||||||
|
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
|
#include "renderer/Model.h"
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ public:
|
||||||
void init();
|
void init();
|
||||||
void reset();
|
void reset();
|
||||||
void simulate(float deltaTime, bool isMine);
|
void simulate(float deltaTime, bool isMine);
|
||||||
void render(bool isMine);
|
void render(bool isMine, Model::RenderMode renderMode = Model::DEFAULT_RENDER_MODE);
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;}
|
const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;}
|
||||||
|
|
|
@ -182,7 +182,7 @@ void Head::relaxLean(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::render(float alpha, Model::RenderMode mode) {
|
void Head::render(float alpha, Model::RenderMode mode) {
|
||||||
if (_faceModel.render(alpha, mode) && _renderLookatVectors) {
|
if (_faceModel.render(alpha, mode) && _renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) {
|
||||||
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
|
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,7 +337,9 @@ void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
||||||
return; // exit early
|
return; // exit early
|
||||||
}
|
}
|
||||||
Avatar::render(cameraPosition, renderMode);
|
Avatar::render(cameraPosition, renderMode);
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints)) {
|
|
||||||
|
// don't display IK constraints in shadow mode
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && renderMode != SHADOW_RENDER_MODE) {
|
||||||
_skeletonModel.renderIKConstraints();
|
_skeletonModel.renderIKConstraints();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -586,7 +588,7 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) {
|
||||||
if (shouldRenderHead(Application::getInstance()->getCamera()->getPosition(), renderMode)) {
|
if (shouldRenderHead(Application::getInstance()->getCamera()->getPosition(), renderMode)) {
|
||||||
getHead()->render(1.0f, modelRenderMode);
|
getHead()->render(1.0f, modelRenderMode);
|
||||||
}
|
}
|
||||||
getHand()->render(true);
|
getHand()->render(true, modelRenderMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
|
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
|
||||||
|
|
|
@ -39,8 +39,8 @@ void ModelTreeRenderer::update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelTreeRenderer::render() {
|
void ModelTreeRenderer::render(RenderMode renderMode) {
|
||||||
OctreeRenderer::render();
|
OctreeRenderer::render(renderMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* ModelTreeRenderer::getModel(const QString& url) {
|
Model* ModelTreeRenderer::getModel(const QString& url) {
|
||||||
|
@ -67,53 +67,129 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
||||||
|
|
||||||
uint16_t numberOfModels = modelItems.size();
|
uint16_t numberOfModels = modelItems.size();
|
||||||
|
|
||||||
|
bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE;
|
||||||
|
|
||||||
|
bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds);
|
||||||
|
bool displayElementProxy = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelElementProxy);
|
||||||
|
bool displayElementChildProxies = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelElementChildProxies);
|
||||||
|
|
||||||
|
|
||||||
|
if (!isShadowMode && displayElementProxy && numberOfModels > 0) {
|
||||||
|
glm::vec3 elementCenter = modelTreeElement->getAABox().calcCenter() * (float)TREE_SCALE;
|
||||||
|
float elementSize = modelTreeElement->getScale() * (float)TREE_SCALE;
|
||||||
|
glColor3f(1.0f, 0.0f, 0.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(elementCenter.x, elementCenter.y, elementCenter.z);
|
||||||
|
glutWireCube(elementSize);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
if (displayElementChildProxies) {
|
||||||
|
// draw the children
|
||||||
|
float halfSize = elementSize / 2.0f;
|
||||||
|
float quarterSize = elementSize / 4.0f;
|
||||||
|
glColor3f(1.0f, 1.0f, 0.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(elementCenter.x - quarterSize, elementCenter.y - quarterSize, elementCenter.z - quarterSize);
|
||||||
|
glutWireCube(halfSize);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glColor3f(1.0f, 0.0f, 1.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(elementCenter.x + quarterSize, elementCenter.y - quarterSize, elementCenter.z - quarterSize);
|
||||||
|
glutWireCube(halfSize);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glColor3f(0.0f, 1.0f, 0.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(elementCenter.x - quarterSize, elementCenter.y + quarterSize, elementCenter.z - quarterSize);
|
||||||
|
glutWireCube(halfSize);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glColor3f(0.0f, 0.0f, 1.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(elementCenter.x - quarterSize, elementCenter.y - quarterSize, elementCenter.z + quarterSize);
|
||||||
|
glutWireCube(halfSize);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(elementCenter.x + quarterSize, elementCenter.y + quarterSize, elementCenter.z + quarterSize);
|
||||||
|
glutWireCube(halfSize);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glColor3f(0.0f, 0.5f, 0.5f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(elementCenter.x - quarterSize, elementCenter.y + quarterSize, elementCenter.z + quarterSize);
|
||||||
|
glutWireCube(halfSize);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glColor3f(0.5f, 0.0f, 0.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(elementCenter.x + quarterSize, elementCenter.y - quarterSize, elementCenter.z + quarterSize);
|
||||||
|
glutWireCube(halfSize);
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
glColor3f(0.0f, 0.5f, 0.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(elementCenter.x + quarterSize, elementCenter.y + quarterSize, elementCenter.z - quarterSize);
|
||||||
|
glutWireCube(halfSize);
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
for (uint16_t i = 0; i < numberOfModels; i++) {
|
for (uint16_t i = 0; i < numberOfModels; i++) {
|
||||||
const ModelItem& modelItem = modelItems[i];
|
const ModelItem& modelItem = modelItems[i];
|
||||||
// render modelItem aspoints
|
// render modelItem aspoints
|
||||||
glm::vec3 position = modelItem.getPosition() * (float)TREE_SCALE;
|
AABox modelBox = modelItem.getAABox();
|
||||||
glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]);
|
modelBox.scale(TREE_SCALE);
|
||||||
float radius = modelItem.getRadius() * (float)TREE_SCALE;
|
if (args->_viewFrustum->boxInFrustum(modelBox) != ViewFrustum::OUTSIDE) {
|
||||||
//glm::vec3 center = position + glm::vec3(radius, radius, radius); // center it around the position
|
glm::vec3 position = modelItem.getPosition() * (float)TREE_SCALE;
|
||||||
|
float radius = modelItem.getRadius() * (float)TREE_SCALE;
|
||||||
|
float size = modelItem.getSize() * (float)TREE_SCALE;
|
||||||
|
|
||||||
bool drawAsModel = modelItem.hasModel();
|
bool drawAsModel = modelItem.hasModel();
|
||||||
|
|
||||||
args->_renderedItems++;
|
args->_renderedItems++;
|
||||||
|
|
||||||
if (drawAsModel) {
|
if (drawAsModel) {
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
const float alpha = 1.0f;
|
const float alpha = 1.0f;
|
||||||
|
|
||||||
Model* model = getModel(modelItem.getModelURL());
|
Model* model = getModel(modelItem.getModelURL());
|
||||||
|
|
||||||
model->setScaleToFit(true, radius * 2.0f);
|
model->setScaleToFit(true, radius * 2.0f);
|
||||||
model->setSnapModelToCenter(true);
|
model->setSnapModelToCenter(true);
|
||||||
|
|
||||||
// set the rotation
|
// set the rotation
|
||||||
glm::quat rotation = modelItem.getModelRotation();
|
glm::quat rotation = modelItem.getModelRotation();
|
||||||
model->setRotation(rotation);
|
model->setRotation(rotation);
|
||||||
|
|
||||||
// set the position
|
// set the position
|
||||||
model->setTranslation(position);
|
model->setTranslation(position);
|
||||||
|
model->simulate(0.0f);
|
||||||
|
|
||||||
model->simulate(0.0f);
|
// TODO: should we allow modelItems to have alpha on their models?
|
||||||
|
Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE
|
||||||
|
? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||||
|
model->render(alpha, modelRenderMode);
|
||||||
|
|
||||||
|
if (!isShadowMode && displayModelBounds) {
|
||||||
|
glColor3f(0.0f, 1.0f, 0.0f);
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(position.x, position.y, position.z);
|
||||||
|
glutWireCube(size);
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
model->render(alpha); // TODO: should we allow modelItems to have alpha on their models?
|
glPopMatrix();
|
||||||
|
} else {
|
||||||
const bool wantDebugSphere = false;
|
glColor3ub(modelItem.getColor()[RED_INDEX],modelItem.getColor()[GREEN_INDEX],modelItem.getColor()[BLUE_INDEX]);
|
||||||
if (wantDebugSphere) {
|
glPushMatrix();
|
||||||
glPushMatrix();
|
glTranslatef(position.x, position.y, position.z);
|
||||||
glTranslatef(position.x, position.y, position.z);
|
glutSolidSphere(radius, 15, 15);
|
||||||
glutWireSphere(radius, 15, 15);
|
glPopMatrix();
|
||||||
glPopMatrix();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
} else {
|
|
||||||
glPushMatrix();
|
|
||||||
glTranslatef(position.x, position.y, position.z);
|
|
||||||
glutSolidSphere(radius, 15, 15);
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||||
|
|
||||||
virtual void init();
|
virtual void init();
|
||||||
virtual void render();
|
virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Model* getModel(const QString& url);
|
Model* getModel(const QString& url);
|
||||||
|
|
|
@ -39,8 +39,8 @@ void ParticleTreeRenderer::update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleTreeRenderer::render() {
|
void ParticleTreeRenderer::render(RenderMode renderMode) {
|
||||||
OctreeRenderer::render();
|
OctreeRenderer::render(renderMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* ParticleTreeRenderer::getModel(const QString& url) {
|
Model* ParticleTreeRenderer::getModel(const QString& url) {
|
||||||
|
@ -102,7 +102,11 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg
|
||||||
model->setScale(scale * MODEL_SCALE * radius * modelScale);
|
model->setScale(scale * MODEL_SCALE * radius * modelScale);
|
||||||
|
|
||||||
model->simulate(0.0f);
|
model->simulate(0.0f);
|
||||||
model->render(alpha); // TODO: should we allow particles to have alpha on their models?
|
|
||||||
|
// TODO: should we allow particles to have alpha on their models?
|
||||||
|
Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE
|
||||||
|
? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
|
||||||
|
model->render(alpha, modelRenderMode);
|
||||||
|
|
||||||
const bool wantDebugSphere = false;
|
const bool wantDebugSphere = false;
|
||||||
if (wantDebugSphere) {
|
if (wantDebugSphere) {
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||||
|
|
||||||
virtual void init();
|
virtual void init();
|
||||||
virtual void render();
|
virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Model* getModel(const QString& url);
|
Model* getModel(const QString& url);
|
||||||
|
|
|
@ -86,6 +86,9 @@ public:
|
||||||
/// used by ModelScriptingInterface to return ModelItemProperties for unknown models
|
/// used by ModelScriptingInterface to return ModelItemProperties for unknown models
|
||||||
void setIsUnknownID() { _id = UNKNOWN_MODEL_ID; _idSet = true; }
|
void setIsUnknownID() { _id = UNKNOWN_MODEL_ID; _idSet = true; }
|
||||||
|
|
||||||
|
glm::vec3 getMinimumPoint() const { return _position - glm::vec3(_radius, _radius, _radius); }
|
||||||
|
glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
glm::vec3 _position;
|
glm::vec3 _position;
|
||||||
xColor _color;
|
xColor _color;
|
||||||
|
@ -156,12 +159,21 @@ public:
|
||||||
/// get position in domain scale units (0.0 - 1.0)
|
/// get position in domain scale units (0.0 - 1.0)
|
||||||
const glm::vec3& getPosition() const { return _position; }
|
const glm::vec3& getPosition() const { return _position; }
|
||||||
|
|
||||||
|
glm::vec3 getMinimumPoint() const { return _position - glm::vec3(_radius, _radius, _radius); }
|
||||||
|
glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); }
|
||||||
|
|
||||||
const rgbColor& getColor() const { return _color; }
|
const rgbColor& getColor() const { return _color; }
|
||||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||||
|
|
||||||
/// get radius in domain scale units (0.0 - 1.0)
|
/// get radius in domain scale units (0.0 - 1.0)
|
||||||
float getRadius() const { return _radius; }
|
float getRadius() const { return _radius; }
|
||||||
|
|
||||||
|
/// get maximum dimension in domain scale units (0.0 - 1.0)
|
||||||
|
float getSize() const { return _radius * 2.0f; }
|
||||||
|
|
||||||
|
/// get maximum dimension in domain scale units (0.0 - 1.0)
|
||||||
|
AABox getAABox() const { return AABox(getMinimumPoint(), getSize()); }
|
||||||
|
|
||||||
// model related properties
|
// model related properties
|
||||||
bool hasModel() const { return !_modelURL.isEmpty(); }
|
bool hasModel() const { return !_modelURL.isEmpty(); }
|
||||||
const QString& getModelURL() const { return _modelURL; }
|
const QString& getModelURL() const { return _modelURL; }
|
||||||
|
|
|
@ -113,13 +113,10 @@ void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& send
|
||||||
FindAndUpdateModelOperator theOperator(model);
|
FindAndUpdateModelOperator theOperator(model);
|
||||||
recurseTreeWithOperator(&theOperator);
|
recurseTreeWithOperator(&theOperator);
|
||||||
|
|
||||||
|
|
||||||
// if we didn't find it in the tree, then store it...
|
// if we didn't find it in the tree, then store it...
|
||||||
if (!theOperator.wasFound()) {
|
if (!theOperator.wasFound()) {
|
||||||
glm::vec3 position = model.getPosition();
|
AABox modelBox = model.getAABox();
|
||||||
float size = std::max(MINIMUM_MODEL_ELEMENT_SIZE, model.getRadius());
|
ModelTreeElement* element = (ModelTreeElement*)getOrCreateChildElementContaining(model.getAABox());
|
||||||
|
|
||||||
ModelTreeElement* element = (ModelTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size);
|
|
||||||
element->storeModel(model);
|
element->storeModel(model);
|
||||||
}
|
}
|
||||||
// what else do we need to do here to get reaveraging to work
|
// what else do we need to do here to get reaveraging to work
|
||||||
|
@ -494,12 +491,29 @@ void ModelTree::update() {
|
||||||
lockForWrite();
|
lockForWrite();
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
|
|
||||||
// TODO: we don't need to update models yet, but when we do, for example
|
ModelTreeUpdateArgs args = { };
|
||||||
// when we add animation support, we will revisit this code.
|
recurseTreeWithOperation(updateOperation, &args);
|
||||||
//ModelTreeUpdateArgs args = { };
|
|
||||||
//recurseTreeWithOperation(updateOperation, &args);
|
|
||||||
|
|
||||||
// Now is a reasonable time to prune the tree...
|
// now add back any of the particles that moved elements....
|
||||||
|
int movingModels = args._movingModels.size();
|
||||||
|
for (int i = 0; i < movingModels; i++) {
|
||||||
|
bool shouldDie = args._movingModels[i].getShouldDie();
|
||||||
|
|
||||||
|
// if the particle is still inside our total bounds, then re-add it
|
||||||
|
AABox treeBounds = getRoot()->getAABox();
|
||||||
|
|
||||||
|
if (!shouldDie && treeBounds.contains(args._movingModels[i].getPosition())) {
|
||||||
|
storeModel(args._movingModels[i]);
|
||||||
|
} else {
|
||||||
|
uint32_t modelItemID = args._movingModels[i].getID();
|
||||||
|
quint64 deletedAt = usecTimestampNow();
|
||||||
|
_recentlyDeletedModelsLock.lockForWrite();
|
||||||
|
_recentlyDeletedModelItemIDs.insert(deletedAt, modelItemID);
|
||||||
|
_recentlyDeletedModelsLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prune the tree...
|
||||||
recurseTreeWithOperation(pruneOperation, NULL);
|
recurseTreeWithOperation(pruneOperation, NULL);
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,15 +47,32 @@ ModelTreeElement* ModelTreeElement::addChildAtIndex(int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ModelTreeElement::appendElementData(OctreePacketData* packetData) const {
|
bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const {
|
||||||
bool success = true; // assume the best...
|
bool success = true; // assume the best...
|
||||||
|
|
||||||
// write our models out...
|
// write our models out... first determine which of the models are in view based on our params
|
||||||
uint16_t numberOfModels = _modelItems->size();
|
uint16_t numberOfModels = 0;
|
||||||
|
QVector<uint16_t> indexesOfModelsToInclude;
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < _modelItems->size(); i++) {
|
||||||
|
if (params.viewFrustum) {
|
||||||
|
const ModelItem& model = (*_modelItems)[i];
|
||||||
|
AABox modelBox = model.getAABox();
|
||||||
|
modelBox.scale(TREE_SCALE);
|
||||||
|
if (params.viewFrustum->boxInFrustum(modelBox) != ViewFrustum::OUTSIDE) {
|
||||||
|
indexesOfModelsToInclude << i;
|
||||||
|
numberOfModels++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
indexesOfModelsToInclude << i;
|
||||||
|
numberOfModels++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
success = packetData->appendValue(numberOfModels);
|
success = packetData->appendValue(numberOfModels);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
for (uint16_t i = 0; i < numberOfModels; i++) {
|
foreach (uint16_t i, indexesOfModelsToInclude) {
|
||||||
const ModelItem& model = (*_modelItems)[i];
|
const ModelItem& model = (*_modelItems)[i];
|
||||||
success = model.appendModelData(packetData);
|
success = model.appendModelData(packetData);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -66,10 +83,25 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData) const {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelTreeElement::update(ModelTreeUpdateArgs& args) {
|
bool ModelTreeElement::containsModelBounds(const ModelItem& model) const {
|
||||||
markWithChangedTime();
|
return _box.contains(model.getMinimumPoint()) && _box.contains(model.getMaximumPoint());
|
||||||
// TODO: early exit when _modelItems is empty
|
}
|
||||||
|
|
||||||
|
bool ModelTreeElement::bestFitModelBounds(const ModelItem& model) const {
|
||||||
|
if (_box.contains(model.getMinimumPoint()) && _box.contains(model.getMaximumPoint())) {
|
||||||
|
int childForMinimumPoint = getMyChildContainingPoint(model.getMinimumPoint());
|
||||||
|
int childForMaximumPoint = getMyChildContainingPoint(model.getMaximumPoint());
|
||||||
|
|
||||||
|
// If I contain both the minimum and maximum point, but two different children of mine
|
||||||
|
// contain those points, then I am the best fit for that model
|
||||||
|
if (childForMinimumPoint != childForMaximumPoint) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelTreeElement::update(ModelTreeUpdateArgs& args) {
|
||||||
// update our contained models
|
// update our contained models
|
||||||
QList<ModelItem>::iterator modelItr = _modelItems->begin();
|
QList<ModelItem>::iterator modelItr = _modelItems->begin();
|
||||||
while(modelItr != _modelItems->end()) {
|
while(modelItr != _modelItems->end()) {
|
||||||
|
@ -78,19 +110,18 @@ void ModelTreeElement::update(ModelTreeUpdateArgs& args) {
|
||||||
|
|
||||||
// If the model wants to die, or if it's left our bounding box, then move it
|
// If the model wants to die, or if it's left our bounding box, then move it
|
||||||
// into the arguments moving models. These will be added back or deleted completely
|
// into the arguments moving models. These will be added back or deleted completely
|
||||||
if (model.getShouldDie() || !_box.contains(model.getPosition())) {
|
if (model.getShouldDie() || !bestFitModelBounds(model)) {
|
||||||
args._movingModels.push_back(model);
|
args._movingModels.push_back(model);
|
||||||
|
|
||||||
// erase this model
|
// erase this model
|
||||||
modelItr = _modelItems->erase(modelItr);
|
modelItr = _modelItems->erase(modelItr);
|
||||||
|
|
||||||
|
// this element has changed so mark it...
|
||||||
|
markWithChangedTime();
|
||||||
} else {
|
} else {
|
||||||
++modelItr;
|
++modelItr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: if _modelItems is empty after while loop consider freeing memory in _modelItems if
|
|
||||||
// internal array is too big (QList internal array does not decrease size except in dtor and
|
|
||||||
// assignment operator). Otherwise _modelItems could become a "resource leak" for large
|
|
||||||
// roaming piles of models.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
bool ModelTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
||||||
|
@ -136,6 +167,7 @@ bool ModelTreeElement::updateModel(const ModelItem& model) {
|
||||||
(localOlder ? "OLDER" : "NEWER"),
|
(localOlder ? "OLDER" : "NEWER"),
|
||||||
difference, debug::valueOf(model.isNewlyCreated()) );
|
difference, debug::valueOf(model.isNewlyCreated()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
thisModel.copyChangedProperties(model);
|
thisModel.copyChangedProperties(model);
|
||||||
markWithChangedTime();
|
markWithChangedTime();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -74,7 +74,7 @@ public:
|
||||||
virtual bool requiresSplit() const { return false; }
|
virtual bool requiresSplit() const { return false; }
|
||||||
|
|
||||||
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
|
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
|
||||||
virtual bool appendElementData(OctreePacketData* packetData) const;
|
virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const;
|
||||||
|
|
||||||
/// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading
|
/// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading
|
||||||
/// from the network.
|
/// from the network.
|
||||||
|
@ -118,6 +118,9 @@ public:
|
||||||
|
|
||||||
bool removeModelWithID(uint32_t id);
|
bool removeModelWithID(uint32_t id);
|
||||||
|
|
||||||
|
bool containsModelBounds(const ModelItem& model) const;
|
||||||
|
bool bestFitModelBounds(const ModelItem& model) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void init(unsigned char * octalCode);
|
virtual void init(unsigned char * octalCode);
|
||||||
|
|
||||||
|
|
|
@ -578,6 +578,10 @@ OctreeElement* Octree::getOrCreateChildElementAt(float x, float y, float z, floa
|
||||||
return getRoot()->getOrCreateChildElementAt(x, y, z, s);
|
return getRoot()->getOrCreateChildElementAt(x, y, z, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OctreeElement* Octree::getOrCreateChildElementContaining(const AABox& box) {
|
||||||
|
return getRoot()->getOrCreateChildElementContaining(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// combines the ray cast arguments into a single object
|
// combines the ray cast arguments into a single object
|
||||||
class RayArgs {
|
class RayArgs {
|
||||||
|
@ -1001,7 +1005,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
|
||||||
// Keep track of how deep we've encoded.
|
// Keep track of how deep we've encoded.
|
||||||
currentEncodeLevel++;
|
currentEncodeLevel++;
|
||||||
|
|
||||||
params.maxLevelReached = std::max(currentEncodeLevel,params.maxLevelReached);
|
params.maxLevelReached = std::max(currentEncodeLevel, params.maxLevelReached);
|
||||||
|
|
||||||
// If we've reached our max Search Level, then stop searching.
|
// If we've reached our max Search Level, then stop searching.
|
||||||
if (currentEncodeLevel >= params.maxEncodeLevel) {
|
if (currentEncodeLevel >= params.maxEncodeLevel) {
|
||||||
|
@ -1342,7 +1346,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
|
||||||
OctreeElement* childElement = element->getChildAtIndex(i);
|
OctreeElement* childElement = element->getChildAtIndex(i);
|
||||||
if (childElement) {
|
if (childElement) {
|
||||||
int bytesBeforeChild = packetData->getUncompressedSize();
|
int bytesBeforeChild = packetData->getUncompressedSize();
|
||||||
continueThisLevel = childElement->appendElementData(packetData);
|
continueThisLevel = childElement->appendElementData(packetData, params);
|
||||||
int bytesAfterChild = packetData->getUncompressedSize();
|
int bytesAfterChild = packetData->getUncompressedSize();
|
||||||
|
|
||||||
if (!continueThisLevel) {
|
if (!continueThisLevel) {
|
||||||
|
|
|
@ -227,6 +227,7 @@ public:
|
||||||
OctreeElement* getOctreeEnclosingElementAt(float x, float y, float z, float s) const;
|
OctreeElement* getOctreeEnclosingElementAt(float x, float y, float z, float s) const;
|
||||||
|
|
||||||
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
||||||
|
OctreeElement* getOrCreateChildElementContaining(const AABox& box);
|
||||||
|
|
||||||
void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL);
|
void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL);
|
||||||
void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData = NULL);
|
void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData = NULL);
|
||||||
|
|
|
@ -1379,3 +1379,90 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float
|
||||||
// Now that we have the child to recurse down, let it answer the original question...
|
// Now that we have the child to recurse down, let it answer the original question...
|
||||||
return child->getOrCreateChildElementAt(x, y, z, s);
|
return child->getOrCreateChildElementAt(x, y, z, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) {
|
||||||
|
OctreeElement* child = NULL;
|
||||||
|
|
||||||
|
float ourScale = getScale();
|
||||||
|
float boxScale = box.getScale();
|
||||||
|
|
||||||
|
if(boxScale > ourScale) {
|
||||||
|
qDebug("UNEXPECTED -- OctreeElement::getOrCreateChildElementContaining() "
|
||||||
|
"boxScale=[%f] > ourScale=[%f] ", boxScale, ourScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine which of our children the minimum and maximum corners of the box live in...
|
||||||
|
glm::vec3 boxCornerMinimum = box.getCorner();
|
||||||
|
glm::vec3 boxCornerMaximum = box.calcTopFarLeft();
|
||||||
|
|
||||||
|
int childIndexBoxMinimum = getMyChildContainingPoint(boxCornerMinimum);
|
||||||
|
int childIndexBoxMaximum = getMyChildContainingPoint(boxCornerMaximum);
|
||||||
|
|
||||||
|
// If the minimum and maximum corners of the box are in two different children's boxes, then we are the containing element
|
||||||
|
if (childIndexBoxMinimum != childIndexBoxMaximum) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, they are the same and that child should be considered as the correct element
|
||||||
|
int childIndex = childIndexBoxMinimum; // both the same...
|
||||||
|
|
||||||
|
// Now, check if we have a child at that location
|
||||||
|
child = getChildAtIndex(childIndex);
|
||||||
|
if (!child) {
|
||||||
|
child = addChildAtIndex(childIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we have the child to recurse down, let it answer the original question...
|
||||||
|
return child->getOrCreateChildElementContaining(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const {
|
||||||
|
glm::vec3 ourCenter = _box.calcCenter();
|
||||||
|
int childIndex = CHILD_UNKNOWN;
|
||||||
|
// left half
|
||||||
|
if (point.x > ourCenter.x) {
|
||||||
|
if (point.y > ourCenter.y) {
|
||||||
|
// top left
|
||||||
|
if (point.z > ourCenter.z) {
|
||||||
|
// top left far
|
||||||
|
childIndex = CHILD_TOP_LEFT_FAR;
|
||||||
|
} else {
|
||||||
|
// top left near
|
||||||
|
childIndex = CHILD_TOP_LEFT_NEAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// bottom left
|
||||||
|
if (point.z > ourCenter.z) {
|
||||||
|
// bottom left far
|
||||||
|
childIndex = CHILD_BOTTOM_LEFT_FAR;
|
||||||
|
} else {
|
||||||
|
// bottom left near
|
||||||
|
childIndex = CHILD_BOTTOM_LEFT_NEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// right half
|
||||||
|
if (point.y > ourCenter.y) {
|
||||||
|
// top right
|
||||||
|
if (point.z > ourCenter.z) {
|
||||||
|
// top right far
|
||||||
|
childIndex = CHILD_TOP_RIGHT_FAR;
|
||||||
|
} else {
|
||||||
|
// top right near
|
||||||
|
childIndex = CHILD_TOP_RIGHT_NEAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// bottom right
|
||||||
|
if (point.z > ourCenter.z) {
|
||||||
|
// bottom right far
|
||||||
|
childIndex = CHILD_BOTTOM_RIGHT_FAR;
|
||||||
|
} else {
|
||||||
|
// bottom right near
|
||||||
|
childIndex = CHILD_BOTTOM_RIGHT_NEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return childIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,14 +23,14 @@
|
||||||
#include "AABox.h"
|
#include "AABox.h"
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include "OctreeConstants.h"
|
#include "OctreeConstants.h"
|
||||||
//#include "Octree.h"
|
|
||||||
|
|
||||||
|
class EncodeBitstreamParams;
|
||||||
class Octree;
|
class Octree;
|
||||||
class OctreeElement;
|
class OctreeElement;
|
||||||
class OctreeElementDeleteHook;
|
class OctreeElementDeleteHook;
|
||||||
class OctreePacketData;
|
class OctreePacketData;
|
||||||
class VoxelSystem;
|
|
||||||
class ReadBitstreamToTreeParams;
|
class ReadBitstreamToTreeParams;
|
||||||
|
class VoxelSystem;
|
||||||
|
|
||||||
// Callers who want delete hook callbacks should implement this class
|
// Callers who want delete hook callbacks should implement this class
|
||||||
class OctreeElementDeleteHook {
|
class OctreeElementDeleteHook {
|
||||||
|
@ -81,7 +81,7 @@ public:
|
||||||
virtual bool requiresSplit() const { return false; }
|
virtual bool requiresSplit() const { return false; }
|
||||||
|
|
||||||
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
|
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
|
||||||
virtual bool appendElementData(OctreePacketData* packetData) const { return true; }
|
virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const { return true; }
|
||||||
|
|
||||||
/// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading
|
/// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading
|
||||||
/// from the network.
|
/// from the network.
|
||||||
|
@ -217,6 +217,8 @@ public:
|
||||||
|
|
||||||
|
|
||||||
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
||||||
|
OctreeElement* getOrCreateChildElementContaining(const AABox& box);
|
||||||
|
int getMyChildContainingPoint(const glm::vec3& point) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
virtual void renderElement(OctreeElement* element, RenderArgs* args) { /* swallow these */ };
|
virtual void renderElement(OctreeElement* element, RenderArgs* args) { /* swallow these */ };
|
||||||
|
|
||||||
virtual void init();
|
virtual void init();
|
||||||
virtual void render() { /* swallow these */ };
|
virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE) { /* swallow these */ };
|
||||||
|
|
||||||
void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; }
|
void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; }
|
||||||
|
|
||||||
|
|
|
@ -154,8 +154,8 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeRenderer::render() {
|
void OctreeRenderer::render(RenderMode renderMode) {
|
||||||
RenderArgs args = { 0, this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust() };
|
RenderArgs args = { 0, this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode };
|
||||||
if (_tree) {
|
if (_tree) {
|
||||||
_tree->lockForRead();
|
_tree->lockForRead();
|
||||||
_tree->recurseTreeWithOperation(renderOperation, &args);
|
_tree->recurseTreeWithOperation(renderOperation, &args);
|
||||||
|
|
|
@ -25,15 +25,7 @@
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
|
|
||||||
class OctreeRenderer;
|
class OctreeRenderer;
|
||||||
|
class RenderArgs;
|
||||||
class RenderArgs {
|
|
||||||
public:
|
|
||||||
int _renderedItems;
|
|
||||||
OctreeRenderer* _renderer;
|
|
||||||
ViewFrustum* _viewFrustum;
|
|
||||||
float _sizeScale;
|
|
||||||
int _boundaryLevelAdjust;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Generic client side Octree renderer class.
|
// Generic client side Octree renderer class.
|
||||||
|
@ -59,8 +51,10 @@ public:
|
||||||
/// initialize and GPU/rendering related resources
|
/// initialize and GPU/rendering related resources
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
|
||||||
|
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE };
|
||||||
|
|
||||||
/// render the content of the octree
|
/// render the content of the octree
|
||||||
virtual void render();
|
virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE);
|
||||||
|
|
||||||
ViewFrustum* getViewFrustum() const { return _viewFrustum; }
|
ViewFrustum* getViewFrustum() const { return _viewFrustum; }
|
||||||
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }
|
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }
|
||||||
|
@ -75,4 +69,15 @@ protected:
|
||||||
ViewFrustum* _viewFrustum;
|
ViewFrustum* _viewFrustum;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RenderArgs {
|
||||||
|
public:
|
||||||
|
int _renderedItems;
|
||||||
|
OctreeRenderer* _renderer;
|
||||||
|
ViewFrustum* _viewFrustum;
|
||||||
|
float _sizeScale;
|
||||||
|
int _boundaryLevelAdjust;
|
||||||
|
OctreeRenderer::RenderMode _renderMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // hifi_OctreeRenderer_h
|
#endif // hifi_OctreeRenderer_h
|
||||||
|
|
|
@ -47,7 +47,7 @@ ParticleTreeElement* ParticleTreeElement::addChildAtIndex(int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ParticleTreeElement::appendElementData(OctreePacketData* packetData) const {
|
bool ParticleTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const {
|
||||||
bool success = true; // assume the best...
|
bool success = true; // assume the best...
|
||||||
|
|
||||||
// write our particles out...
|
// write our particles out...
|
||||||
|
|
|
@ -76,7 +76,7 @@ public:
|
||||||
virtual bool requiresSplit() const { return false; }
|
virtual bool requiresSplit() const { return false; }
|
||||||
|
|
||||||
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
|
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
|
||||||
virtual bool appendElementData(OctreePacketData* packetData) const;
|
virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const;
|
||||||
|
|
||||||
/// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading
|
/// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading
|
||||||
/// from the network.
|
/// from the network.
|
||||||
|
|
|
@ -65,7 +65,7 @@ void VoxelTreeElement::splitChildren() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoxelTreeElement::appendElementData(OctreePacketData* packetData) const {
|
bool VoxelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const {
|
||||||
return packetData->appendColor(getColor());
|
return packetData->appendColor(getColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
virtual bool hasContent() const { return isColored(); }
|
virtual bool hasContent() const { return isColored(); }
|
||||||
virtual void splitChildren();
|
virtual void splitChildren();
|
||||||
virtual bool requiresSplit() const;
|
virtual bool requiresSplit() const;
|
||||||
virtual bool appendElementData(OctreePacketData* packetData) const;
|
virtual bool appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const;
|
||||||
virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
||||||
virtual void calculateAverageFromChildren();
|
virtual void calculateAverageFromChildren();
|
||||||
virtual bool collapseChildren();
|
virtual bool collapseChildren();
|
||||||
|
|
Loading…
Reference in a new issue