mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-05-28 21:42:00 +02:00
Merge pull request #5009 from ZappoMan/team-teaching-scene-api
TEAM TEACHING - hacking on rendering mesh parts
This commit is contained in:
commit
98c0cd7d23
15 changed files with 636 additions and 104 deletions
|
@ -844,7 +844,7 @@ void Application::paintGL() {
|
|||
_glWidget->makeCurrent();
|
||||
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
gpu::Context context;
|
||||
gpu::Context context(new gpu::GLBackend());
|
||||
RenderArgs renderArgs(&context, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(),
|
||||
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
|
||||
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
||||
|
@ -3183,12 +3183,12 @@ namespace render {
|
|||
if (args->_renderMode != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
PerformanceTimer perfTimer("worldBox");
|
||||
renderWorldBox();
|
||||
|
||||
// FIXME: there's currently a bug in the new render engine, if this origin dot is rendered out of view it will
|
||||
// screw up the state of textures on models so they all end up rendering in the incorrect tint/color/texture
|
||||
float originSphereRadius = 0.05f;
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
// never the less
|
||||
float originSphereRadius = 0.05f;
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -489,6 +489,10 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
void EntityTreeRenderer::render(RenderArgs* renderArgs) {
|
||||
|
||||
if (_tree && !_shuttingDown) {
|
||||
renderArgs->_renderer = this;
|
||||
|
||||
checkPendingAddToScene(renderArgs);
|
||||
|
||||
Model::startScene(renderArgs->_renderSide);
|
||||
|
||||
ViewFrustum* frustum = (renderArgs->_renderMode == RenderArgs::SHADOW_RENDER_MODE) ?
|
||||
|
@ -503,7 +507,6 @@ void EntityTreeRenderer::render(RenderArgs* renderArgs) {
|
|||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
renderArgs->_renderer = this;
|
||||
renderArgs->_batch = &batch;
|
||||
|
||||
_tree->lockForRead();
|
||||
|
@ -521,7 +524,7 @@ void EntityTreeRenderer::render(RenderArgs* renderArgs) {
|
|||
_tree->unlock();
|
||||
|
||||
glPushMatrix();
|
||||
renderArgs->_context->enqueueBatch(batch);
|
||||
renderArgs->_context->render(batch);
|
||||
glPopMatrix();
|
||||
|
||||
renderArgs->_batch = nullptr;
|
||||
|
@ -1081,16 +1084,38 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
|||
|
||||
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
||||
checkAndCallPreload(entityID);
|
||||
|
||||
// here's where we add the entity payload to the scene
|
||||
auto entity = static_cast<EntityTree*>(_tree)->findEntityByID(entityID);
|
||||
addEntityToScene(entity);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
|
||||
// here's where we add the entity payload to the scene
|
||||
if (entity && entity->canRenderInScene()) {
|
||||
render::PendingChanges pendingChanges;
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (entity->addToScene(entity, scene, pendingChanges)) {
|
||||
_entitiesInScene.insert(entity);
|
||||
if (entity->readyToAddToScene()) {
|
||||
render::PendingChanges pendingChanges;
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (entity->addToScene(entity, scene, pendingChanges)) {
|
||||
_entitiesInScene.insert(entity);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
} else {
|
||||
if (!_pendingAddToScene.contains(entity)) {
|
||||
_pendingAddToScene << entity;
|
||||
}
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::checkPendingAddToScene(RenderArgs* renderArgs) {
|
||||
QSet<EntityItemPointer> addedToScene;
|
||||
foreach (auto entity, _pendingAddToScene) {
|
||||
if (entity->readyToAddToScene(renderArgs)) {
|
||||
addEntityToScene(entity);
|
||||
addedToScene << entity;
|
||||
}
|
||||
}
|
||||
foreach (auto addedEntity, addedToScene) {
|
||||
_pendingAddToScene.remove(addedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -123,6 +123,10 @@ protected:
|
|||
virtual Octree* createTree() { return new EntityTree(true); }
|
||||
|
||||
private:
|
||||
void checkPendingAddToScene(RenderArgs* renderArgs);
|
||||
void addEntityToScene(EntityItemPointer entity);
|
||||
QSet<EntityItemPointer> _pendingAddToScene;
|
||||
|
||||
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
|
||||
void renderElementProxy(EntityTreeElement* entityTreeElement, RenderArgs* args);
|
||||
void checkAndCallPreload(const EntityItemID& entityID);
|
||||
|
|
|
@ -108,6 +108,49 @@ void RenderableModelEntityItem::remapTextures() {
|
|||
_currentTextures = _textures;
|
||||
}
|
||||
|
||||
// TODO: we need a solution for changes to the postion/rotation/etc of a model...
|
||||
// this current code path only addresses that in this setup case... not the changing/moving case
|
||||
bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
|
||||
if (!_model && renderArgs) {
|
||||
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||
PerformanceTimer perfTimer("getModel");
|
||||
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(renderArgs->_renderer);
|
||||
getModel(renderer);
|
||||
}
|
||||
if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoadedWithTextures()) {
|
||||
_model->setScaleToFit(true, getDimensions());
|
||||
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
||||
_model->setRotation(getRotation());
|
||||
_model->setTranslation(getPosition());
|
||||
|
||||
// make sure to simulate so everything gets set up correctly for rendering
|
||||
{
|
||||
PerformanceTimer perfTimer("_model->simulate");
|
||||
_model->simulate(0.0f);
|
||||
}
|
||||
_needsInitialSimulation = false;
|
||||
|
||||
_model->renderSetup(renderArgs);
|
||||
}
|
||||
bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(renderArgs);
|
||||
return ready;
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
if (_model) {
|
||||
return _model->addToScene(scene, pendingChanges);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
if (_model) {
|
||||
_model->removeFromScene(scene, pendingChanges);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RMEIrender");
|
||||
assert(getType() == EntityTypes::Model);
|
||||
|
@ -199,6 +242,10 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
|
||||
Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
||||
Model* result = NULL;
|
||||
|
||||
if (!renderer) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// make sure our renderer is setup
|
||||
if (!_myRenderer) {
|
||||
|
@ -206,7 +253,7 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
|||
}
|
||||
assert(_myRenderer == renderer); // you should only ever render on one renderer
|
||||
|
||||
if (QThread::currentThread() != _myRenderer->thread()) {
|
||||
if (!_myRenderer || QThread::currentThread() != _myRenderer->thread()) {
|
||||
return _model;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,12 @@ public:
|
|||
|
||||
virtual void somethingChangedNotification() { _needsInitialSimulation = true; }
|
||||
|
||||
virtual bool canRenderInScene() { return false; } // we don't yet play well with others
|
||||
virtual bool canRenderInScene() { return true; }
|
||||
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr);
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
|
|
|
@ -653,15 +653,15 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
|
|||
// lastEdited
|
||||
quint64 lastEditedInLocalTime;
|
||||
memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime));
|
||||
assert(lastEditedInLocalTime > 0);
|
||||
quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew;
|
||||
memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
|
||||
#ifdef WANT_DEBUG
|
||||
#if 1 //def WANT_DEBUG
|
||||
qCDebug(entities, "EntityItem::adjustEditPacketForClockSkew()...");
|
||||
qCDebug(entities) << " lastEditedInLocalTime: " << lastEditedInLocalTime;
|
||||
qCDebug(entities) << " clockSkew: " << clockSkew;
|
||||
qCDebug(entities) << " lastEditedInServerTime: " << lastEditedInServerTime;
|
||||
#endif
|
||||
//assert(lastEditedInLocalTime > (quint64)0);
|
||||
}
|
||||
|
||||
float EntityItem::computeMass() const {
|
||||
|
@ -980,7 +980,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
}
|
||||
|
||||
void EntityItem::recordCreationTime() {
|
||||
assert(_created == UNKNOWN_CREATED_TIME);
|
||||
//assert(_created == UNKNOWN_CREATED_TIME);
|
||||
_created = usecTimestampNow();
|
||||
_lastEdited = _created;
|
||||
_lastUpdated = _created;
|
||||
|
|
|
@ -158,6 +158,7 @@ public:
|
|||
{ return 0; }
|
||||
|
||||
virtual bool canRenderInScene() { return false; } // does your entity property render using Render Items and Payloads
|
||||
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return true; } // we assume you're ready to add
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) { return false; } // by default entity items don't add to scene
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
|
||||
using namespace gpu;
|
||||
|
||||
Context::Context() {
|
||||
Context::Context(Backend* backend) :
|
||||
_backend(backend) {
|
||||
}
|
||||
|
||||
Context::Context(const Context& context) {
|
||||
|
@ -31,6 +32,7 @@ bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Context::enqueueBatch(Batch& batch) {
|
||||
GLBackend::renderBatch(batch, true);
|
||||
void Context::render(Batch& batch) {
|
||||
_backend->render(batch);
|
||||
// GLBackend::renderBatch(batch, true);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ class Batch;
|
|||
class Backend {
|
||||
public:
|
||||
|
||||
virtual~ Backend() {};
|
||||
virtual void render(Batch& batch) = 0;
|
||||
|
||||
class TransformObject {
|
||||
public:
|
||||
Mat4 _model;
|
||||
|
@ -107,15 +110,14 @@ protected:
|
|||
|
||||
class Context {
|
||||
public:
|
||||
Context();
|
||||
Context(const Context& context);
|
||||
Context(Backend* backend);
|
||||
~Context();
|
||||
|
||||
void enqueueBatch(Batch& batch);
|
||||
|
||||
void render(Batch& batch);
|
||||
|
||||
|
||||
protected:
|
||||
Context(const Context& context);
|
||||
|
||||
// This function can only be called by "static Shader::makeProgram()"
|
||||
// makeProgramShader(...) make a program shader ready to be used in a Batch.
|
||||
|
@ -123,6 +125,8 @@ protected:
|
|||
// If the shader passed is not a program, nothing happens.
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||
|
||||
std::unique_ptr<Backend> _backend;
|
||||
|
||||
friend class Shader;
|
||||
};
|
||||
|
||||
|
|
|
@ -442,6 +442,8 @@ void Batch::_glUniform1f(GLint location, GLfloat v0) {
|
|||
}
|
||||
void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
glUniform1f(
|
||||
|
@ -460,6 +462,11 @@ void Batch::_glUniform2f(GLint location, GLfloat v0, GLfloat v1) {
|
|||
DO_IT_NOW(_glUniform2f, 1);
|
||||
}
|
||||
void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
glUniform2f(
|
||||
batch._params[paramOffset + 2]._int,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
|
@ -478,6 +485,11 @@ void Batch::_glUniform4fv(GLint location, GLsizei count, const GLfloat* value) {
|
|||
DO_IT_NOW(_glUniform4fv, 3);
|
||||
}
|
||||
void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
glUniform4fv(
|
||||
batch._params[paramOffset + 2]._int,
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
|
@ -498,6 +510,11 @@ void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpo
|
|||
DO_IT_NOW(_glUniformMatrix4fv, 4);
|
||||
}
|
||||
void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
glUniformMatrix4fv(
|
||||
batch._params[paramOffset + 3]._int,
|
||||
batch._params[paramOffset + 2]._uint,
|
||||
|
|
|
@ -26,9 +26,9 @@ public:
|
|||
|
||||
explicit GLBackend(bool syncCache);
|
||||
GLBackend();
|
||||
~GLBackend();
|
||||
virtual ~GLBackend();
|
||||
|
||||
void render(Batch& batch);
|
||||
virtual void render(Batch& batch);
|
||||
|
||||
// Render Batch create a local Context and execute the batch with it
|
||||
// WARNING:
|
||||
|
|
|
@ -107,7 +107,7 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
|||
}
|
||||
|
||||
void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured) {
|
||||
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true);
|
||||
// DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true);
|
||||
|
||||
if (textured) {
|
||||
batch.setPipeline(_simpleProgramTextured);
|
||||
|
@ -117,7 +117,7 @@ void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured)
|
|||
}
|
||||
|
||||
void DeferredLightingEffect::releaseSimpleProgram(gpu::Batch& batch) {
|
||||
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, false, false);
|
||||
// DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, false, false);
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) {
|
||||
|
|
|
@ -765,6 +765,109 @@ void Model::renderSetup(RenderArgs* args) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
class TransparentMeshPart {
|
||||
public:
|
||||
TransparentMeshPart(Model* model, int meshIndex, int partIndex) : model(model), meshIndex(meshIndex), partIndex(partIndex) { }
|
||||
typedef render::Payload<TransparentMeshPart> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
Model* model;
|
||||
int meshIndex;
|
||||
int partIndex;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const TransparentMeshPart::Pointer& payload) {
|
||||
return ItemKey::Builder::transparentShape();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const TransparentMeshPart::Pointer& payload) {
|
||||
if (payload) {
|
||||
//return payload->model->getPartBounds(payload->meshIndex, payload->partIndex);
|
||||
}
|
||||
return render::Item::Bound();
|
||||
}
|
||||
template <> void payloadRender(const TransparentMeshPart::Pointer& payload, RenderArgs* args) {
|
||||
if (args) {
|
||||
args->_elementsTouched++;
|
||||
//qDebug() << "would be TransparentMeshPart: " << payload->meshIndex << "," << payload->partIndex;
|
||||
return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OpaqueMeshPart {
|
||||
public:
|
||||
OpaqueMeshPart(Model* model, int meshIndex, int partIndex) : model(model), meshIndex(meshIndex), partIndex(partIndex) { }
|
||||
typedef render::Payload<OpaqueMeshPart> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
Model* model;
|
||||
int meshIndex;
|
||||
int partIndex;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const OpaqueMeshPart::Pointer& payload) {
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const OpaqueMeshPart::Pointer& payload) {
|
||||
if (payload) {
|
||||
//return payload->model->getPartBounds(payload->meshIndex, payload->partIndex);
|
||||
}
|
||||
return render::Item::Bound();
|
||||
}
|
||||
template <> void payloadRender(const OpaqueMeshPart::Pointer& payload, RenderArgs* args) {
|
||||
if (args) {
|
||||
args->_elementsTouched++;
|
||||
return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
bool somethingAdded = false;
|
||||
// allow the attachments to add to scene
|
||||
foreach (Model* attachment, _attachments) {
|
||||
bool attachementSomethingAdded = attachment->addToScene(scene, pendingChanges);
|
||||
somethingAdded = somethingAdded || attachementSomethingAdded;
|
||||
}
|
||||
|
||||
foreach (auto renderItem, _transparentRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderData = TransparentMeshPart::Pointer(renderItem);
|
||||
auto renderPayload = render::PayloadPointer(new TransparentMeshPart::Payload(renderData));
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
_renderItems << item;
|
||||
somethingAdded = true;
|
||||
}
|
||||
foreach (auto renderItem, _opaqueRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderData = OpaqueMeshPart::Pointer(renderItem);
|
||||
auto renderPayload = render::PayloadPointer(new OpaqueMeshPart::Payload(renderData));
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
_renderItems << item;
|
||||
somethingAdded = true;
|
||||
}
|
||||
|
||||
return somethingAdded;
|
||||
}
|
||||
|
||||
void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
// allow the attachments to remove to scene
|
||||
foreach (Model* attachment, _attachments) {
|
||||
attachment->removeFromScene(scene, pendingChanges);
|
||||
}
|
||||
|
||||
foreach (auto item, _renderItems) {
|
||||
pendingChanges.removeItem(item);
|
||||
}
|
||||
_renderItems.clear();
|
||||
}
|
||||
|
||||
bool Model::render(RenderArgs* renderArgs, float alpha) {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
|
||||
|
@ -1847,9 +1950,12 @@ void Model::setupBatchTransform(gpu::Batch& batch, RenderArgs* args) {
|
|||
}
|
||||
|
||||
void Model::endScene(RenderArgs* args) {
|
||||
// Now that we migrated everything to the new RENDER/SCENE no more work to do!
|
||||
return;
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
|
||||
|
||||
|
||||
#if (GPU_TRANSFORM_PROFILE == GPU_LEGACY)
|
||||
// with legacy transform profile, we still to protect that transform stack...
|
||||
glPushMatrix();
|
||||
|
@ -1862,6 +1968,7 @@ void Model::endScene(RenderArgs* args) {
|
|||
renderSide = args->_renderSide;
|
||||
}
|
||||
|
||||
|
||||
gpu::GLBackend backend;
|
||||
backend.syncCache(); // force sync with gl state here
|
||||
|
||||
|
@ -2068,6 +2175,212 @@ bool Model::renderInScene(float alpha, RenderArgs* args) {
|
|||
return true;
|
||||
}
|
||||
|
||||
AABox Model::getPartBounds(int meshIndex, int partIndex) {
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
||||
AABox partBox = mesh._mesh.evalPartBound(partIndex);
|
||||
|
||||
// FIX ME!
|
||||
// 1) needs to translate to world space, these values are in model space
|
||||
// 2) mesh._mesh.parts doesn't always have the correct values in it... so we
|
||||
// need to just use mesh.parts or find/fix whatever is causing mesh._mesh
|
||||
// to not contain data
|
||||
return partBox;
|
||||
}
|
||||
|
||||
void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) {
|
||||
renderSetup(args);
|
||||
|
||||
/*
|
||||
if (translucent) {
|
||||
renderCore(args, 1.0f);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
auto mode = args->_renderMode;
|
||||
|
||||
// Capture the view matrix once for the rendering of this model
|
||||
if (_transforms.empty()) {
|
||||
_transforms.push_back(Transform());
|
||||
}
|
||||
|
||||
_transforms[0] = _viewState->getViewTransform();
|
||||
|
||||
// apply entity translation offset to the viewTransform in one go (it's a preTranslate because viewTransform goes from world to eye space)
|
||||
_transforms[0].preTranslate(-_translation);
|
||||
|
||||
batch.setViewTransform(_transforms[0]);
|
||||
|
||||
|
||||
const float OPAQUE_ALPHA_THRESHOLD = 0.5f;
|
||||
const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
|
||||
auto alphaThreshold = translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
||||
|
||||
const NetworkMesh& networkMesh = networkMeshes.at(meshIndex);
|
||||
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
||||
const MeshState& state = _meshStates.at(meshIndex);
|
||||
|
||||
bool translucentMesh = translucent; // networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size();
|
||||
bool hasTangents = !mesh.tangents.isEmpty();
|
||||
bool hasSpecular = mesh.hasSpecularTexture();
|
||||
bool hasLightmap = mesh.hasEmissiveTexture();
|
||||
bool isSkinned = state.clusterMatrices.size() > 1;
|
||||
bool wireframe = isWireframe();
|
||||
|
||||
if (wireframe) {
|
||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||
}
|
||||
|
||||
Locations* locations = nullptr;
|
||||
pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||
args, locations);
|
||||
|
||||
|
||||
int meshPartsRendered = 0;
|
||||
updateVisibleJointStates();
|
||||
|
||||
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
|
||||
// to false to rebuild out mesh groups.
|
||||
|
||||
if (meshIndex < 0 || meshIndex >= networkMeshes.size() || meshIndex > geometry.meshes.size()) {
|
||||
_meshGroupsKnown = false; // regenerate these lists next time around.
|
||||
return; // FIXME!
|
||||
}
|
||||
|
||||
batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0);
|
||||
int vertexCount = mesh.vertices.size();
|
||||
if (vertexCount == 0) {
|
||||
// sanity check
|
||||
return; // FIXME!
|
||||
}
|
||||
|
||||
if (state.clusterMatrices.size() > 1) {
|
||||
GLBATCH(glUniformMatrix4fv)(locations->clusterMatrices, state.clusterMatrices.size(), false,
|
||||
(const float*)state.clusterMatrices.constData());
|
||||
batch.setModelTransform(Transform());
|
||||
} else {
|
||||
batch.setModelTransform(Transform(state.clusterMatrices[0]));
|
||||
}
|
||||
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
batch.setInputFormat(networkMesh._vertexFormat);
|
||||
batch.setInputStream(0, *networkMesh._vertexStream);
|
||||
} else {
|
||||
batch.setInputFormat(networkMesh._vertexFormat);
|
||||
batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
|
||||
batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3));
|
||||
batch.setInputStream(2, *networkMesh._vertexStream);
|
||||
}
|
||||
|
||||
if (mesh.colors.isEmpty()) {
|
||||
GLBATCH(glColor4f)(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
qint64 offset = 0;
|
||||
|
||||
const NetworkMeshPart& networkPart = networkMesh.parts.at(partIndex);
|
||||
const FBXMeshPart& part = mesh.parts.at(partIndex);
|
||||
model::MaterialPointer material = part._material;
|
||||
|
||||
if (material == nullptr) {
|
||||
qCDebug(renderutils) << "WARNING: material == nullptr!!!";
|
||||
}
|
||||
|
||||
if (material != nullptr) {
|
||||
|
||||
// apply material properties
|
||||
if (mode != RenderArgs::SHADOW_RENDER_MODE) {
|
||||
#ifdef WANT_DEBUG
|
||||
qCDebug(renderutils) << "Material Changed ---------------------------------------------";
|
||||
qCDebug(renderutils) << "part INDEX:" << partIndex;
|
||||
qCDebug(renderutils) << "NEW part.materialID:" << part.materialID;
|
||||
#endif //def WANT_DEBUG
|
||||
|
||||
if (locations->materialBufferUnit >= 0) {
|
||||
batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer());
|
||||
}
|
||||
|
||||
Texture* diffuseMap = networkPart.diffuseTexture.data();
|
||||
if (mesh.isEye && diffuseMap) {
|
||||
diffuseMap = (_dilatedTextures[meshIndex][partIndex] =
|
||||
static_cast<DilatableNetworkTexture*>(diffuseMap)->getDilatedTexture(_pupilDilation)).data();
|
||||
}
|
||||
static bool showDiffuse = true;
|
||||
if (showDiffuse && diffuseMap) {
|
||||
batch.setUniformTexture(0, diffuseMap->getGPUTexture());
|
||||
|
||||
} else {
|
||||
batch.setUniformTexture(0, textureCache->getWhiteTexture());
|
||||
}
|
||||
|
||||
if (locations->texcoordMatrices >= 0) {
|
||||
glm::mat4 texcoordTransform[2];
|
||||
if (!part.diffuseTexture.transform.isIdentity()) {
|
||||
part.diffuseTexture.transform.getMatrix(texcoordTransform[0]);
|
||||
}
|
||||
if (!part.emissiveTexture.transform.isIdentity()) {
|
||||
part.emissiveTexture.transform.getMatrix(texcoordTransform[1]);
|
||||
}
|
||||
GLBATCH(glUniformMatrix4fv)(locations->texcoordMatrices, 2, false, (const float*) &texcoordTransform);
|
||||
}
|
||||
|
||||
if (!mesh.tangents.isEmpty()) {
|
||||
Texture* normalMap = networkPart.normalTexture.data();
|
||||
batch.setUniformTexture(1, !normalMap ?
|
||||
textureCache->getBlueTexture() : normalMap->getGPUTexture());
|
||||
|
||||
}
|
||||
|
||||
if (locations->specularTextureUnit >= 0) {
|
||||
Texture* specularMap = networkPart.specularTexture.data();
|
||||
batch.setUniformTexture(locations->specularTextureUnit, !specularMap ?
|
||||
textureCache->getWhiteTexture() : specularMap->getGPUTexture());
|
||||
}
|
||||
|
||||
if (args) {
|
||||
args->_materialSwitches++;
|
||||
}
|
||||
|
||||
// HACK: For unknown reason (yet!) this code that should be assigned only if the material changes need to be called for every
|
||||
// drawcall with an emissive, so let's do it for now.
|
||||
if (locations->emissiveTextureUnit >= 0) {
|
||||
// assert(locations->emissiveParams >= 0); // we should have the emissiveParams defined in the shader
|
||||
float emissiveOffset = part.emissiveParams.x;
|
||||
float emissiveScale = part.emissiveParams.y;
|
||||
GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale);
|
||||
|
||||
Texture* emissiveMap = networkPart.emissiveTexture.data();
|
||||
batch.setUniformTexture(locations->emissiveTextureUnit, !emissiveMap ?
|
||||
textureCache->getWhiteTexture() : emissiveMap->getGPUTexture());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
meshPartsRendered++;
|
||||
|
||||
if (part.quadIndices.size() > 0) {
|
||||
batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset);
|
||||
offset += part.quadIndices.size() * sizeof(int);
|
||||
}
|
||||
|
||||
if (part.triangleIndices.size() > 0) {
|
||||
batch.drawIndexed(gpu::TRIANGLES, part.triangleIndices.size(), 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;
|
||||
}
|
||||
}
|
||||
|
||||
void Model::segregateMeshGroups() {
|
||||
_renderBuckets.clear();
|
||||
|
||||
|
@ -2086,6 +2399,7 @@ void Model::segregateMeshGroups() {
|
|||
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
const MeshState& state = _meshStates.at(i);
|
||||
|
||||
|
||||
bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size();
|
||||
bool hasTangents = !mesh.tangents.isEmpty();
|
||||
|
@ -2097,6 +2411,18 @@ void Model::segregateMeshGroups() {
|
|||
if (wireframe) {
|
||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||
}
|
||||
|
||||
// Debug...
|
||||
int totalParts = mesh.parts.size();
|
||||
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
|
||||
// this is a good place to create our renderPayloads
|
||||
if (translucentMesh) {
|
||||
_transparentRenderItems << std::shared_ptr<TransparentMeshPart>(new TransparentMeshPart(this, i, partIndex));
|
||||
} else {
|
||||
_opaqueRenderItems << std::shared_ptr<OpaqueMeshPart>(new OpaqueMeshPart(this, i, partIndex));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString materialID;
|
||||
|
||||
|
|
|
@ -45,6 +45,22 @@ class Shape;
|
|||
#include "RenderArgs.h"
|
||||
class ViewFrustum;
|
||||
|
||||
namespace render {
|
||||
class Scene;
|
||||
class PendingChanges;
|
||||
typedef unsigned int ItemID;
|
||||
}
|
||||
class OpaqueMeshPart;
|
||||
class TransparentMeshPart;
|
||||
|
||||
inline uint qHash(const std::shared_ptr<TransparentMeshPart>& a, uint seed) {
|
||||
return qHash(a.get(), seed);
|
||||
}
|
||||
inline uint qHash(const std::shared_ptr<OpaqueMeshPart>& a, uint seed) {
|
||||
return qHash(a.get(), seed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// A generic 3D model displaying geometry loaded from a URL.
|
||||
class Model : public QObject, public PhysicsEntity {
|
||||
|
@ -99,12 +115,18 @@ public:
|
|||
virtual void simulate(float deltaTime, bool fullUpdate = true);
|
||||
|
||||
bool render(RenderArgs* renderArgs, float alpha = 1.0f);
|
||||
void renderSetup(RenderArgs* args);
|
||||
|
||||
// Scene rendering support
|
||||
static void startScene(RenderArgs::RenderSide renderSide);
|
||||
bool renderInScene(float alpha = 1.0f, RenderArgs* args = NULL);
|
||||
static void endScene(RenderArgs* args);
|
||||
|
||||
// new Scene/Engine rendering support
|
||||
bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return isRenderable() && isActive() && isLoadedWithTextures(); }
|
||||
bool addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
|
||||
/// 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
|
||||
/// \param retainCurrent if true, keep rendering the current model until the new one is loaded
|
||||
|
@ -219,6 +241,9 @@ public:
|
|||
BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false);
|
||||
bool convexHullContains(glm::vec3 point);
|
||||
|
||||
AABox getPartBounds(int meshIndex, int partIndex);
|
||||
void renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent);
|
||||
|
||||
protected:
|
||||
QSharedPointer<NetworkGeometry> _geometry;
|
||||
|
||||
|
@ -370,7 +395,6 @@ private:
|
|||
static void endSceneSplitPass(RenderArgs::RenderMode mode = RenderArgs::DEFAULT_RENDER_MODE, RenderArgs* args = NULL);
|
||||
|
||||
// helper functions used by render() or renderInScene()
|
||||
void renderSetup(RenderArgs* args);
|
||||
bool renderCore(RenderArgs* args, float alpha);
|
||||
int renderMeshes(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold,
|
||||
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args = NULL,
|
||||
|
@ -511,6 +535,11 @@ private:
|
|||
RenderBucketMap _renderBuckets;
|
||||
|
||||
bool _renderCollisionHull;
|
||||
|
||||
|
||||
QSet<std::shared_ptr<TransparentMeshPart>> _transparentRenderItems;
|
||||
QSet<std::shared_ptr<OpaqueMeshPart>> _opaqueRenderItems;
|
||||
QSet<render::ItemID> _renderItems;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QPointer<Model>)
|
||||
|
|
|
@ -55,73 +55,6 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon
|
|||
Job::~Job() {
|
||||
}
|
||||
|
||||
template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
// render opaques
|
||||
auto& scene = sceneContext->_scene;
|
||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape());
|
||||
|
||||
ItemIDs inItems;
|
||||
inItems.reserve(items.size());
|
||||
for (auto id : items) {
|
||||
inItems.push_back(id);
|
||||
}
|
||||
|
||||
ItemIDs culledItems;
|
||||
cullItems(sceneContext, renderContext, inItems, culledItems);
|
||||
|
||||
ItemIDs sortedItems;
|
||||
depthSortItems(sceneContext, renderContext, true, culledItems, sortedItems); // Sort Front to back opaque items!
|
||||
|
||||
renderItems(sceneContext, renderContext, sortedItems);
|
||||
}
|
||||
|
||||
|
||||
template <> void render::jobRun(const DrawTransparent& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
// render transparents
|
||||
auto& scene = sceneContext->_scene;
|
||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape());
|
||||
|
||||
ItemIDs inItems;
|
||||
inItems.reserve(items.size());
|
||||
for (auto id : items) {
|
||||
inItems.push_back(id);
|
||||
}
|
||||
|
||||
ItemIDs culledItems;
|
||||
cullItems(sceneContext, renderContext, inItems, culledItems);
|
||||
|
||||
ItemIDs sortedItems;
|
||||
depthSortItems(sceneContext, renderContext, false, culledItems, sortedItems); // Sort Back to front transparent items!
|
||||
|
||||
renderItems(sceneContext, renderContext, sortedItems);
|
||||
}
|
||||
|
||||
template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
// render lights
|
||||
auto& scene = sceneContext->_scene;
|
||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::light());
|
||||
|
||||
|
||||
ItemIDs inItems;
|
||||
inItems.reserve(items.size());
|
||||
for (auto id : items) {
|
||||
inItems.push_back(id);
|
||||
}
|
||||
|
||||
ItemIDs culledItems;
|
||||
cullItems(sceneContext, renderContext, inItems, culledItems);
|
||||
renderItems(sceneContext, renderContext, culledItems);
|
||||
}
|
||||
|
||||
/*
|
||||
bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera) {
|
||||
const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it.
|
||||
|
@ -263,16 +196,155 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende
|
|||
void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDs& inItems) {
|
||||
auto& scene = sceneContext->_scene;
|
||||
RenderArgs* args = renderContext->args;
|
||||
gpu::Batch theBatch;
|
||||
args->_batch = &theBatch;
|
||||
|
||||
// render
|
||||
for (auto id : inItems) {
|
||||
auto item = scene->getItem(id);
|
||||
item.render(args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
args->_context->enqueueBatch((*args->_batch));
|
||||
void addClearStateCommands(gpu::Batch& batch) {
|
||||
batch._glDepthMask(true);
|
||||
batch._glDepthFunc(GL_LESS);
|
||||
batch._glDisable(GL_CULL_FACE);
|
||||
|
||||
batch._glActiveTexture(GL_TEXTURE0 + 1);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, 0);
|
||||
batch._glActiveTexture(GL_TEXTURE0 + 2);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, 0);
|
||||
batch._glActiveTexture(GL_TEXTURE0 + 3);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, 0);
|
||||
batch._glActiveTexture(GL_TEXTURE0);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
|
||||
// deactivate vertex arrays after drawing
|
||||
batch._glDisableClientState(GL_NORMAL_ARRAY);
|
||||
batch._glDisableClientState(GL_VERTEX_ARRAY);
|
||||
batch._glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
batch._glDisableClientState(GL_COLOR_ARRAY);
|
||||
batch._glDisableVertexAttribArray(gpu::Stream::TANGENT);
|
||||
batch._glDisableVertexAttribArray(gpu::Stream::SKIN_CLUSTER_INDEX);
|
||||
batch._glDisableVertexAttribArray(gpu::Stream::SKIN_CLUSTER_WEIGHT);
|
||||
|
||||
// bind with 0 to switch back to normal operation
|
||||
batch._glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
batch._glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// Back to no program
|
||||
batch._glUseProgram(0);
|
||||
}
|
||||
|
||||
|
||||
template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
// render opaques
|
||||
auto& scene = sceneContext->_scene;
|
||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape());
|
||||
|
||||
ItemIDs inItems;
|
||||
inItems.reserve(items.size());
|
||||
for (auto id : items) {
|
||||
inItems.push_back(id);
|
||||
}
|
||||
|
||||
ItemIDs culledItems;
|
||||
cullItems(sceneContext, renderContext, inItems, culledItems);
|
||||
|
||||
ItemIDs sortedItems;
|
||||
depthSortItems(sceneContext, renderContext, true, culledItems, sortedItems); // Sort Front to back opaque items!
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
gpu::Batch theBatch;
|
||||
args->_batch = &theBatch;
|
||||
|
||||
glm::mat4 proj;
|
||||
args->_viewFrustum->evalProjectionMatrix(proj);
|
||||
theBatch.setProjectionTransform(proj);
|
||||
|
||||
renderContext->args->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
|
||||
{
|
||||
GLenum buffers[3];
|
||||
int bufferCount = 0;
|
||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
|
||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
|
||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
|
||||
theBatch._glDrawBuffers(bufferCount, buffers);
|
||||
}
|
||||
|
||||
renderItems(sceneContext, renderContext, sortedItems);
|
||||
|
||||
addClearStateCommands((*args->_batch));
|
||||
args->_context->render((*args->_batch));
|
||||
args->_batch = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <> void render::jobRun(const DrawTransparent& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
// render transparents
|
||||
auto& scene = sceneContext->_scene;
|
||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape());
|
||||
|
||||
ItemIDs inItems;
|
||||
inItems.reserve(items.size());
|
||||
for (auto id : items) {
|
||||
inItems.push_back(id);
|
||||
}
|
||||
|
||||
ItemIDs culledItems;
|
||||
cullItems(sceneContext, renderContext, inItems, culledItems);
|
||||
|
||||
ItemIDs sortedItems;
|
||||
depthSortItems(sceneContext, renderContext, false, culledItems, sortedItems); // Sort Back to front transparent items!
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
gpu::Batch theBatch;
|
||||
args->_batch = &theBatch;
|
||||
|
||||
renderContext->args->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
|
||||
{
|
||||
GLenum buffers[3];
|
||||
int bufferCount = 0;
|
||||
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
|
||||
theBatch._glDrawBuffers(bufferCount, buffers);
|
||||
}
|
||||
|
||||
renderItems(sceneContext, renderContext, sortedItems);
|
||||
|
||||
addClearStateCommands((*args->_batch));
|
||||
args->_context->render((*args->_batch));
|
||||
args->_batch = nullptr;
|
||||
}
|
||||
|
||||
template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
// render lights
|
||||
auto& scene = sceneContext->_scene;
|
||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::light());
|
||||
|
||||
|
||||
ItemIDs inItems;
|
||||
inItems.reserve(items.size());
|
||||
for (auto id : items) {
|
||||
inItems.push_back(id);
|
||||
}
|
||||
|
||||
ItemIDs culledItems;
|
||||
cullItems(sceneContext, renderContext, inItems, culledItems);
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
gpu::Batch theBatch;
|
||||
args->_batch = &theBatch;
|
||||
renderItems(sceneContext, renderContext, culledItems);
|
||||
args->_context->render((*args->_batch));
|
||||
args->_batch = nullptr;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue