view cull mesh parts

This commit is contained in:
ZappoMan 2014-10-15 10:08:21 -07:00
parent eab96587fe
commit 46cb780aa5
4 changed files with 84 additions and 13 deletions

View file

@ -15,9 +15,9 @@
#include "Joystick.h"
const float MAX_AXIS = 32768.0f;
#ifdef HAVE_SDL2
const float MAX_AXIS = 32768.0f;
Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
_instanceId(instanceId),

View file

@ -59,7 +59,7 @@ int RenderableModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned c
void RenderableModelEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableModelEntityItem::render");
PerformanceTimer perfTimer("RMEIrender");
assert(getType() == EntityTypes::Model);
bool drawAsModel = hasModel();
@ -119,7 +119,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
// TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render
// is significantly more expensive. Is there a way to call this that doesn't cost us as much?
PerformanceTimer perfTimer("model->render");
_model->render(alpha, modelRenderMode);
_model->render(alpha, modelRenderMode, args);
} else {
// if we couldn't get a model, then just draw a cube
glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);

View file

@ -18,6 +18,7 @@
#include <CapsuleShape.h>
#include <GeometryUtil.h>
#include <PerfStat.h>
#include <PhysicsEntity.h>
#include <ShapeCollider.h>
#include <SphereShape.h>
@ -44,7 +45,8 @@ Model::Model(QObject* parent) :
_pupilDilation(0.0f),
_url("http://invalid.com"),
_blendNumber(0),
_appliedBlendNumber(0) {
_appliedBlendNumber(0),
_calculatedMeshBoxesValid(false) {
// we may have been created in the network thread, but we live in the main thread
moveToThread(Application::getInstance()->thread());
@ -384,7 +386,7 @@ void Model::setJointStates(QVector<JointState> states) {
_boundingRadius = radius;
}
bool Model::render(float alpha, RenderMode mode) {
bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
// render the attachments
foreach (Model* attachment, _attachments) {
attachment->render(alpha, mode);
@ -392,6 +394,23 @@ bool Model::render(float alpha, RenderMode mode) {
if (_meshStates.isEmpty()) {
return false;
}
// if we don't have valid mesh boxes, calculate them now, this only matters in cases
// where our caller has passed RenderArgs which will include a view frustum we can cull
// against. We cache the results of these calculations so long as the model hasn't been
// simulated and the mesh hasn't changed.
if (args && !_calculatedMeshBoxesValid) {
PerformanceTimer perfTimer("calculatedMeshBoxes");
const FBXGeometry& geometry = _geometry->getFBXGeometry();
int numberOfMeshes = geometry.meshes.size();
_calculatedMeshBoxes.resize(numberOfMeshes);
for (int i = 0; i < numberOfMeshes; i++) {
const FBXMesh& mesh = geometry.meshes.at(i);
Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents);
_calculatedMeshBoxes[i] = AABox(scaledMeshExtents);
}
_calculatedMeshBoxesValid = true;
}
// set up dilated textures on first render after load/simulate
const FBXGeometry& geometry = _geometry->getFBXGeometry();
@ -431,11 +450,12 @@ bool Model::render(float alpha, RenderMode mode) {
mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE,
mode == DEFAULT_RENDER_MODE);
renderMeshes(mode, false);
const float DEFAULT_ALPHA_THRESHOLD = 0.5f;
renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, args);
// render translucent meshes afterwards
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true);
renderMeshes(mode, true, 0.75f);
renderMeshes(mode, true, 0.75f, args);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
@ -445,7 +465,7 @@ bool Model::render(float alpha, RenderMode mode) {
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true);
if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) {
renderMeshes(mode, true, 0.0f);
renderMeshes(mode, true, 0.0f, args);
}
glDepthMask(true);
@ -511,6 +531,22 @@ Extents Model::getUnscaledMeshExtents() const {
return scaledExtents;
}
Extents Model::calculateScaledOffsetExtents(const Extents& extents) const {
// we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix
glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
Extents scaledOffsetExtents = { ((minimum + _offset) * _scale),
((maximum + _offset) * _scale) };
Extents rotatedExtents = scaledOffsetExtents.getRotated(_rotation);
Extents translatedExtents = { rotatedExtents.minimum + _translation,
rotatedExtents.maximum + _translation };
return translatedExtents;
}
bool Model::getJointState(int index, glm::quat& rotation) const {
if (index == -1 || index >= _jointStates.size()) {
return false;
@ -790,6 +826,8 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
|| (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);
if (isActive() && fullUpdate) {
_calculatedMeshBoxesValid = false; // if we have to simulate, we need to assume our mesh boxes are all invalid
// check for scale to fit
if (_scaleToFit && !_scaledToFit) {
scaleToFit();
@ -1200,10 +1238,12 @@ void Model::deleteGeometry() {
_blendedBlendshapeCoefficients.clear();
}
void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold) {
void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args) {
updateVisibleJointStates();
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
bool cullMeshParts = args && !Menu::getInstance()->isOptionChecked(MenuOption::DontCullMeshParts);
for (int i = 0; i < networkMeshes.size(); i++) {
// exit early if the translucency doesn't match what we're drawing
@ -1221,6 +1261,23 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
continue;
}
// if we got here, then check to see if this mesh is in view
if (args) {
bool shouldRender = true;
args->_meshesConsidered++;
if (cullMeshParts && args->_viewFrustum) {
shouldRender = args->_viewFrustum->boxInFrustum(_calculatedMeshBoxes.at(i)) != ViewFrustum::OUTSIDE;
}
if (shouldRender) {
args->_meshesRendered++;
} else {
args->_meshesOutOfView++;
continue; // skip this mesh
}
}
const_cast<QOpenGLBuffer&>(networkMesh.vertexBuffer).bind();
ProgramObject* program = &_program;
@ -1372,6 +1429,13 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(),
GL_UNSIGNED_INT, (void*)offset);
offset += part.triangleIndices.size() * sizeof(int);
if (args) {
const int INDICES_PER_TRIANGLE = 3;
const int INDICES_PER_QUAD = 4;
args->_trianglesRendered += part.triangleIndices.size() / INDICES_PER_TRIANGLE;
args->_quadsRendered += part.quadIndices.size() / INDICES_PER_QUAD;
}
}
if (!mesh.colors.isEmpty()) {

View file

@ -16,9 +16,9 @@
#include <QObject>
#include <QUrl>
#include <PhysicsEntity.h>
#include <AABox.h>
#include <AnimationCache.h>
#include <PhysicsEntity.h>
#include "GeometryCache.h"
#include "InterfaceConfig.h"
@ -30,6 +30,7 @@ class QScriptEngine;
class AnimationHandle;
class Shape;
class RenderArgs;
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
@ -84,7 +85,7 @@ public:
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE };
bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE);
bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL);
/// Sets the URL of the model to render.
/// \param fallback the URL of a fallback model to render if the requested model fails to load
@ -107,6 +108,9 @@ public:
/// Returns the unscaled extents of the model's mesh
Extents getUnscaledMeshExtents() const;
/// Returns the scaled equivalent of some extents in model space.
Extents calculateScaledOffsetExtents(const Extents& extents) const;
/// Returns a reference to the shared geometry.
const QSharedPointer<NetworkGeometry>& getGeometry() const { return _geometry; }
@ -247,7 +251,7 @@ private:
void applyNextGeometry();
void deleteGeometry();
void renderMeshes(RenderMode mode, bool translucent, float alphaThreshold = 0.5f);
void renderMeshes(RenderMode mode, bool translucent, float alphaThreshold = 0.5f, RenderArgs* args = NULL);
QVector<JointState> createJointStates(const FBXGeometry& geometry);
void initJointTransforms();
@ -325,6 +329,9 @@ private:
static SkinLocations _skinTranslucentLocations;
static void initSkinProgram(ProgramObject& program, SkinLocations& locations, int specularTextureUnit = 1);
QVector<AABox> _calculatedMeshBoxes;
bool _calculatedMeshBoxesValid;
};
Q_DECLARE_METATYPE(QPointer<Model>)