From e024d23366fa7e818f392c41afaebf5e03d0d7e3 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Fri, 18 Sep 2015 18:51:44 -0700 Subject: [PATCH] Instancing work, second pass --- examples/cubePerfTest.js | 4 +- interface/src/Stars.cpp | 2 +- interface/src/Util.cpp | 28 +- interface/src/avatar/Avatar.cpp | 44 +- interface/src/avatar/Hand.cpp | 13 +- interface/src/avatar/Head.cpp | 7 +- interface/src/avatar/SkeletonModel.cpp | 22 +- interface/src/ui/overlays/Cube3DOverlay.cpp | 7 +- interface/src/ui/overlays/Sphere3DOverlay.cpp | 10 +- .../src/RenderableBoxEntityItem.cpp | 4 +- .../src/RenderableDebugableEntityItem.cpp | 9 +- .../src/RenderableSphereEntityItem.cpp | 17 +- .../src/RenderableZoneEntityItem.cpp | 12 +- libraries/fbx/src/FBXReader.cpp | 4 +- libraries/gpu/src/gpu/Batch.cpp | 8 +- libraries/gpu/src/gpu/Batch.h | 3 + libraries/gpu/src/gpu/Format.cpp | 21 + libraries/gpu/src/gpu/Format.h | 19 +- libraries/gpu/src/gpu/GLBackend.cpp | 9 +- libraries/gpu/src/gpu/GLBackendShared.h | 3 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 4 +- libraries/gpu/src/gpu/Resource.cpp | 5 - libraries/gpu/src/gpu/Resource.h | 5 + libraries/gpu/src/gpu/Stream.cpp | 44 + libraries/gpu/src/gpu/Stream.h | 30 +- .../src/DeferredLightingEffect.cpp | 95 +- .../render-utils/src/DeferredLightingEffect.h | 28 +- libraries/render-utils/src/Environment.cpp | 6 +- libraries/render-utils/src/GeometryCache.cpp | 983 +++++++++--------- libraries/render-utils/src/GeometryCache.h | 92 +- tests/gpu-test/src/main.cpp | 312 ++---- tests/gpu-test/src/{simple.slf => unlit.slf} | 1 - tests/gpu-test/src/{simple.slv => unlit.slv} | 11 +- 33 files changed, 960 insertions(+), 902 deletions(-) create mode 100644 libraries/gpu/src/gpu/Format.cpp rename tests/gpu-test/src/{simple.slf => unlit.slf} (94%) rename tests/gpu-test/src/{simple.slv => unlit.slv} (64%) diff --git a/examples/cubePerfTest.js b/examples/cubePerfTest.js index 699472edd9..f2f4d48b22 100644 --- a/examples/cubePerfTest.js +++ b/examples/cubePerfTest.js @@ -36,7 +36,7 @@ for (var x = 0; x < SIDE_SIZE; x++) { var position = Vec3.sum(MyAvatar.position, { x: x * 0.2, y: y * 0.2, z: z * 0.2}); var radius = Math.random() * 0.1; boxes.push(Entities.addEntity({ - type: cube ? "Box" : "Box", + type: cube ? "Box" : "Sphere", name: "PerfTest", position: position, dimensions: { x: radius, y: radius, z: radius }, @@ -52,7 +52,7 @@ for (var x = 0; x < SIDE_SIZE; x++) { function scriptEnding() { for (var i = 0; i < boxes.length; i++) { - //Entities.deleteEntity(boxes[i]); + Entities.deleteEntity(boxes[i]); } } Script.scriptEnding.connect(scriptEnding); diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index 119b9ed1a2..6bc160d5eb 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -204,7 +204,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { float msecs = (float)(usecTimestampNow() - start) / (float)USECS_PER_MSEC; float secs = msecs / (float)MSECS_PER_SECOND; batch._glUniform1f(_timeSlot, secs); - geometryCache->renderUnitCube(batch); + geometryCache->renderCube(batch); static const size_t VERTEX_STRIDE = sizeof(StarVertex); size_t offset = offsetof(StarVertex, position); diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index dad34e9243..d09dd41999 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "world.h" #include "Application.h" @@ -93,29 +94,28 @@ void renderWorldBox(gpu::Batch& batch) { geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY); - geometryCache->renderWireCube(batch, TREE_SCALE, GREY4); + auto deferredLighting = DependencyManager::get(); + + deferredLighting->renderWireCubeInstance(batch, Transform(), GREY4); // Draw meter markers along the 3 axis to help with measuring things const float MARKER_DISTANCE = 1.0f; const float MARKER_RADIUS = 0.05f; - geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, RED); + transform = Transform().setScale(MARKER_RADIUS); + deferredLighting->renderSolidSphereInstance(batch, transform, RED); - transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)); - batch.setModelTransform(transform); - geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, RED); + transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)).setScale(MARKER_RADIUS); + deferredLighting->renderSolidSphereInstance(batch, transform, RED); - transform.setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f)); - batch.setModelTransform(transform); - geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, GREEN); + transform = Transform().setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f)).setScale(MARKER_RADIUS); + deferredLighting->renderSolidSphereInstance(batch, transform, GREEN); - transform.setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE)); - batch.setModelTransform(transform); - geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, BLUE); + transform = Transform().setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS); + deferredLighting->renderSolidSphereInstance(batch, transform, BLUE); - transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE)); - batch.setModelTransform(transform); - geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, GREY); + transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS); + deferredLighting->renderSolidSphereInstance(batch, transform, GREY); } // Return a random vector of average length 1 diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5ac830baf3..0a934e1ed3 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -448,15 +448,14 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { // If this is the avatar being looked at, render a little ball above their head if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) { - const float INDICATOR_OFFSET = 0.22f; - const float INDICATOR_RADIUS = 0.03f; - const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f }; + static const float INDICATOR_OFFSET = 0.22f; + static const float INDICATOR_RADIUS = 0.03f; + static const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f }; glm::vec3 position = glm::vec3(_position.x, getDisplayNamePosition().y + INDICATOR_OFFSET, _position.z); Transform transform; transform.setTranslation(position); - batch.setModelTransform(transform); - DependencyManager::get()->renderSolidSphere(batch, INDICATOR_RADIUS, - 15, 15, LOOK_AT_INDICATOR_COLOR); + transform.postScale(INDICATOR_RADIUS); + DependencyManager::get()->renderSolidSphereInstance(batch, transform, LOOK_AT_INDICATOR_COLOR); } // If the avatar is looking at me, indicate that they are @@ -473,27 +472,29 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { if (geometry && geometry->isLoaded()) { const float DEFAULT_EYE_DIAMETER = 0.048f; // Typical human eye const float RADIUS_INCREMENT = 0.005f; - Transform transform; + batch.setModelTransform(Transform()); glm::vec3 position = getHead()->getLeftEyePosition(); + Transform transform; transform.setTranslation(position); - batch.setModelTransform(transform); float eyeDiameter = geometry->getFBXGeometry().leftEyeSize; if (eyeDiameter == 0.0f) { eyeDiameter = DEFAULT_EYE_DIAMETER; } - DependencyManager::get()->renderSolidSphere(batch, - eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT, 15, 15, glm::vec4(LOOKING_AT_ME_COLOR, alpha)); + + DependencyManager::get()->renderSolidSphereInstance(batch, + Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT), + glm::vec4(LOOKING_AT_ME_COLOR, alpha)); position = getHead()->getRightEyePosition(); transform.setTranslation(position); - batch.setModelTransform(transform); eyeDiameter = geometry->getFBXGeometry().rightEyeSize; if (eyeDiameter == 0.0f) { eyeDiameter = DEFAULT_EYE_DIAMETER; } - DependencyManager::get()->renderSolidSphere(batch, - eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT, 15, 15, glm::vec4(LOOKING_AT_ME_COLOR, alpha)); + DependencyManager::get()->renderSolidSphereInstance(batch, + Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT), + glm::vec4(LOOKING_AT_ME_COLOR, alpha)); } } @@ -518,19 +519,16 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { if (renderArgs->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) && (angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) { + batch.setModelTransform(Transform()); + + Transform transform; transform.setTranslation(_position); transform.setScale(height); - batch.setModelTransform(transform); - - if (_voiceSphereID == GeometryCache::UNKNOWN_ID) { - _voiceSphereID = DependencyManager::get()->allocateID(); - } - - DependencyManager::get()->bindSimpleProgram(batch); - DependencyManager::get()->renderSphere(batch, sphereRadius, 15, 15, - glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true, - _voiceSphereID); + transform.postScale(sphereRadius); + DependencyManager::get()->renderSolidSphereInstance(batch, + transform, + glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE)); } } } diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index a0125ca736..a144661f8b 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "Avatar.h" #include "AvatarManager.h" @@ -65,16 +66,16 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { Transform transform = Transform(); transform.setTranslation(position); transform.setRotation(palm.getRotation()); - batch.setModelTransform(transform); - DependencyManager::get()->renderSphere(batch, SPHERE_RADIUS, - NUM_FACETS, NUM_FACETS, grayColor); + transform.postScale(SPHERE_RADIUS); + DependencyManager::get()->renderSolidSphereInstance(batch, transform, grayColor); // draw a green sphere at the old "finger tip" + transform = Transform(); position = palm.getTipPosition(); transform.setTranslation(position); - batch.setModelTransform(transform); - DependencyManager::get()->renderSphere(batch, SPHERE_RADIUS, - NUM_FACETS, NUM_FACETS, greenColor, false); + transform.setRotation(palm.getRotation()); + transform.postScale(SPHERE_RADIUS); + DependencyManager::get()->renderSolidSphereInstance(batch, transform, greenColor); } } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index a514eb4e8d..96c55dfa93 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -462,13 +462,10 @@ void Head::renderLookatTarget(RenderArgs* renderArgs, glm::vec3 lookatPosition) auto& batch = *renderArgs->_batch; auto transform = Transform{}; transform.setTranslation(lookatPosition); - batch.setModelTransform(transform); auto deferredLighting = DependencyManager::get(); - deferredLighting->bindSimpleProgram(batch); - - auto geometryCache = DependencyManager::get(); const float LOOK_AT_TARGET_RADIUS = 0.075f; + transform.postScale(LOOK_AT_TARGET_RADIUS); const glm::vec4 LOOK_AT_TARGET_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f }; - geometryCache->renderSphere(batch, LOOK_AT_TARGET_RADIUS, 15, 15, LOOK_AT_TARGET_COLOR, true); + deferredLighting->renderSolidSphereInstance(batch, transform, LOOK_AT_TARGET_COLOR); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 27e61175eb..ff8cde3df8 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -639,27 +639,25 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha auto geometryCache = DependencyManager::get(); auto deferredLighting = DependencyManager::get(); - Transform transform; // = Transform(); - // draw a blue sphere at the capsule top point glm::vec3 topPoint = _translation + _boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * glm::vec3(0.0f, 1.0f, 0.0f); - transform.setTranslation(topPoint); - batch.setModelTransform(transform); - deferredLighting->bindSimpleProgram(batch); - geometryCache->renderSphere(batch, _boundingCapsuleRadius, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, - glm::vec4(0.6f, 0.6f, 0.8f, alpha)); + + deferredLighting->renderSolidSphereInstance(batch, + Transform().setTranslation(topPoint).postScale(_boundingCapsuleRadius * 2.0), + glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule bottom point glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, _boundingCapsuleHeight, 0.0f); glm::vec3 axis = topPoint - bottomPoint; - transform.setTranslation(bottomPoint); - batch.setModelTransform(transform); - deferredLighting->bindSimpleProgram(batch); - geometryCache->renderSphere(batch, _boundingCapsuleRadius, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, - glm::vec4(0.8f, 0.8f, 0.6f, alpha)); + + deferredLighting->renderSolidSphereInstance(batch, + Transform().setTranslation(bottomPoint).postScale(_boundingCapsuleRadius * 2.0), + glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); + batch.setModelTransform(Transform().setTranslation(bottomPoint)); + deferredLighting->bindSimpleProgram(batch); Avatar::renderJointConnectingCone(batch, origin, axis, _boundingCapsuleRadius, _boundingCapsuleRadius, glm::vec4(0.6f, 0.8f, 0.6f, alpha)); } diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index a306c7c86d..3ad887ca65 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -61,8 +61,7 @@ void Cube3DOverlay::render(RenderArgs* args) { // } transform.setScale(dimensions); - batch->setModelTransform(transform); - DependencyManager::get()->renderSolidCube(*batch, 1.0f, cubeColor); + DependencyManager::get()->renderSolidCubeInstance(*batch, transform, cubeColor); } else { if (getIsDashedLine()) { @@ -98,9 +97,9 @@ void Cube3DOverlay::render(RenderArgs* args) { geometryCache->renderDashedLine(*batch, bottomRightFar, topRightFar, cubeColor); } else { + batch->setModelTransform(Transform()); transform.setScale(dimensions); - batch->setModelTransform(transform); - DependencyManager::get()->renderWireCube(*batch, 1.0f, cubeColor); + DependencyManager::get()->renderWireCubeInstance(*batch, transform, cubeColor); } } } diff --git a/interface/src/ui/overlays/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp index 9712375209..3b503e87e8 100644 --- a/interface/src/ui/overlays/Sphere3DOverlay.cpp +++ b/interface/src/ui/overlays/Sphere3DOverlay.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -36,10 +37,15 @@ void Sphere3DOverlay::render(RenderArgs* args) { auto batch = args->_batch; if (batch) { + batch->setModelTransform(Transform()); + Transform transform = _transform; transform.postScale(getDimensions()); - batch->setModelTransform(transform); - DependencyManager::get()->renderSphere(*batch, 1.0f, SLICES, SLICES, sphereColor, _isSolid); + if (_isSolid) { + DependencyManager::get()->renderSolidSphereInstance(*batch, transform, sphereColor); + } else { + DependencyManager::get()->renderWireSphereInstance(*batch, transform, sphereColor); + } } } diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index b9ff69af52..187b25e75a 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -57,7 +57,9 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { if (_procedural->ready()) { batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well _procedural->prepare(batch, this->getDimensions()); - DependencyManager::get()->renderSolidCube(batch, 1.0f, _procedural->getColor(cubeColor)); + auto color = _procedural->getColor(cubeColor); + batch._glColor4f(color.r, color.g, color.b, color.a); + DependencyManager::get()->renderCube(batch); } else { DependencyManager::get()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor); } diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp index 2770c4edc2..6986025133 100644 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp @@ -23,8 +23,13 @@ void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, Render float puffedOut, glm::vec4& color) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; - batch.setModelTransform(entity->getTransformToCenter()); // we want to include the scale as well - DependencyManager::get()->renderWireCube(batch, 1.0f + puffedOut, color); + + auto xfm = entity->getTransformToCenter(); + if (puffedOut != 0.0) { + xfm.postScale(1.0 + puffedOut); + } + batch.setModelTransform(Transform()); // we want to include the scale as well + DependencyManager::get()->renderWireCubeInstance(batch, xfm, color); } void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) { diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 82257c67fb..63fbfff9cb 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -39,15 +39,7 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableSphereEntityItem::render"); Q_ASSERT(getType() == EntityTypes::Sphere); Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - batch.setModelTransform(getTransformToCenter()); // use a transform with scale, rotation, registration point and translation - // TODO: it would be cool to select different slices/stacks geometry based on the size of the sphere - // and the distance to the viewer. This would allow us to reduce the triangle count for smaller spheres - // that aren't close enough to see the tessellation and use larger triangle count for spheres that would - // expose that effect - static const int SLICES = 15, STACKS = 15; - if (!_procedural) { _procedural.reset(new Procedural(getUserData())); _procedural->_vertexSource = simple_vert; @@ -59,12 +51,17 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } + gpu::Batch& batch = *args->_batch; glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha()); if (_procedural->ready()) { + batch.setModelTransform(getTransformToCenter()); // use a transform with scale, rotation, registration point and translation _procedural->prepare(batch, getDimensions()); - DependencyManager::get()->renderSphere(batch, 0.5f, SLICES, STACKS, _procedural->getColor(sphereColor)); + auto color = _procedural->getColor(sphereColor); + batch._glColor4f(color.r, color.g, color.b, color.a); + DependencyManager::get()->renderSphere(batch); } else { - DependencyManager::get()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor); + batch.setModelTransform(Transform()); + DependencyManager::get()->renderSolidSphereInstance(batch, getTransformToCenter(), sphereColor); } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 930a684617..90aff03f55 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -121,15 +121,15 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; - batch.setModelTransform(getTransformToCenter()); - + batch.setModelTransform(Transform()); + + auto xfm = getTransformToCenter(); auto deferredLightingEffect = DependencyManager::get(); - if (getShapeType() == SHAPE_TYPE_SPHERE) { - const int SLICES = 15, STACKS = 15; - deferredLightingEffect->renderWireSphere(batch, 0.5f, SLICES, STACKS, DEFAULT_COLOR); + xfm.postScale(0.5); + deferredLightingEffect->renderWireSphereInstance(batch, xfm, DEFAULT_COLOR); } else { - deferredLightingEffect->renderWireCube(batch, 1.0f, DEFAULT_COLOR); + deferredLightingEffect->renderWireCubeInstance(batch, xfm, DEFAULT_COLOR); } break; } diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 6f69e8befc..0864414e5e 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1436,12 +1436,12 @@ void buildModelMesh(ExtractedMesh& extracted, const QString& url) { if (clusterIndicesSize) { mesh.addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, - gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW))); + gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW))); } if (clusterWeightsSize) { mesh.addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, model::BufferView(attribBuffer, clusterWeightsOffset, clusterWeightsSize, - gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW))); + gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW))); } diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index e5ec8525b6..e6e176be88 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -304,12 +304,16 @@ bool Batch::isSkyboxEnabled() const { return _enableSkybox; } -void Batch::setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function) { +void Batch::setupNamedCalls(const std::string& instanceName, size_t count, NamedBatchData::Function function) { NamedBatchData& instance = _namedData[instanceName]; - ++instance._count; + instance._count += count; instance._function = function; } +void Batch::setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function) { + setupNamedCalls(instanceName, 1, function); +} + BufferPointer Batch::getNamedBuffer(const std::string& instanceName, uint8_t index) { NamedBatchData& instance = _namedData[instanceName]; if (instance._buffers.size() <= index) { diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index c3bf6250c5..ec6fb26c34 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -62,8 +62,10 @@ public: Function _function; void process(Batch& batch) { + if (_function) { _function(batch, *this); } + } }; using NamedBatchDataMap = std::map; @@ -96,6 +98,7 @@ public: void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0, uint32 startInstance = 0); + void setupNamedCalls(const std::string& instanceName, size_t count, NamedBatchData::Function function); void setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function); BufferPointer getNamedBuffer(const std::string& instanceName, uint8_t index = 0); diff --git a/libraries/gpu/src/gpu/Format.cpp b/libraries/gpu/src/gpu/Format.cpp new file mode 100644 index 0000000000..a66fc19458 --- /dev/null +++ b/libraries/gpu/src/gpu/Format.cpp @@ -0,0 +1,21 @@ +// +// Created by Bradley Austin Davis on 2015/09/20 +// Copyright 2013-2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Format.h" + +using namespace gpu; + +const Element Element::COLOR_RGBA_32{ VEC4, NUINT8, RGBA }; +const Element Element::COLOR_RGBA{ VEC4, FLOAT, RGBA }; +const Element Element::VEC2F_UV{ VEC2, FLOAT, UV }; +const Element Element::VEC2F_XY{ VEC2, FLOAT, XY }; +const Element Element::VEC3F_XYZ{ VEC3, FLOAT, XYZ }; +const Element Element::VEC4F_XYZW{ VEC4, FLOAT, XYZW }; +const Element Element::INDEX_UINT16{ SCALAR, UINT16, INDEX }; +const Element Element::PART_DRAWCALL{ VEC4, UINT32, PART }; + diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index e16256574b..530db084a3 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -56,10 +56,8 @@ enum Type { INT8, UINT8, - NFLOAT, NINT32, NUINT32, - NHALF, NINT16, NUINT16, NINT8, @@ -68,6 +66,7 @@ enum Type { NUM_TYPES, BOOL = UINT8, + NORMALIZED_START = NINT32, }; // Array providing the size in bytes for a given scalar type static const int TYPE_SIZE[NUM_TYPES] = { @@ -79,10 +78,10 @@ static const int TYPE_SIZE[NUM_TYPES] = { 2, 1, 1, + + // normalized values 4, 4, - 4, - 2, 2, 2, 1, @@ -99,10 +98,9 @@ static const bool TYPE_IS_INTEGER[NUM_TYPES] = { true, true, - false, + // Normalized values true, true, - false, true, true, true, @@ -151,6 +149,7 @@ enum Semantic { RGB, RGBA, BGRA, + XY, XYZ, XYZW, QUAT, @@ -199,7 +198,7 @@ public: uint8 getLocationCount() const { return LOCATION_COUNT[(Dimension)_dimension]; } Type getType() const { return (Type)_type; } - bool isNormalized() const { return (getType() >= NFLOAT); } + bool isNormalized() const { return (getType() >= NORMALIZED_START); } bool isInteger() const { return TYPE_IS_INTEGER[getType()]; } uint32 getSize() const { return DIMENSION_COUNT[_dimension] * TYPE_SIZE[_type]; } @@ -215,10 +214,14 @@ public: } static const Element COLOR_RGBA_32; + static const Element COLOR_RGBA; + static const Element VEC2F_UV; + static const Element VEC2F_XY; static const Element VEC3F_XYZ; + static const Element VEC4F_XYZW; static const Element INDEX_UINT16; static const Element PART_DRAWCALL; - + protected: uint8 _semantic; uint8 _dimension : 4; diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 43c01d0337..62508f273c 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -127,7 +127,12 @@ void GLBackend::renderPassTransfer(Batch& batch) { const size_t numCommands = batch.getCommands().size(); const Batch::Commands::value_type* command = batch.getCommands().data(); const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data(); - + + for (auto& cached : batch._buffers._items) { + if (cached._data) { + syncGPUObject(*cached._data); + } + } // Reset the transform buffers _transform._cameras.resize(0); _transform._cameraOffsets.clear(); @@ -330,7 +335,7 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { uint32 startInstance = batch._params[paramOffset + 0]._uint; GLenum glType = _elementTypeToGLType[_input._indexBufferType]; - glDrawElementsInstanced(mode, numIndices, glType, nullptr, numInstances); + glDrawElementsInstanced(mode, numIndices, glType, reinterpret_cast(startIndex + _input._indexBufferOffset), numInstances); (void)CHECK_GL_ERROR(); } diff --git a/libraries/gpu/src/gpu/GLBackendShared.h b/libraries/gpu/src/gpu/GLBackendShared.h index 7ce54665be..21bd10a33a 100644 --- a/libraries/gpu/src/gpu/GLBackendShared.h +++ b/libraries/gpu/src/gpu/GLBackendShared.h @@ -34,10 +34,9 @@ static const GLenum _elementTypeToGLType[gpu::NUM_TYPES] = { GL_UNSIGNED_SHORT, GL_BYTE, GL_UNSIGNED_BYTE, - GL_FLOAT, + // Normalized values GL_INT, GL_UNSIGNED_INT, - GL_HALF_FLOAT, GL_SHORT, GL_UNSIGNED_SHORT, GL_BYTE, diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index d4e1db125d..dce5236868 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -156,7 +156,6 @@ public: texel.internalFormat = GL_DEPTH_COMPONENT32; break; } - case gpu::NFLOAT: case gpu::FLOAT: { texel.internalFormat = GL_DEPTH_COMPONENT32F; break; @@ -165,8 +164,7 @@ public: case gpu::INT16: case gpu::NUINT16: case gpu::NINT16: - case gpu::HALF: - case gpu::NHALF: { + case gpu::HALF: { texel.internalFormat = GL_DEPTH_COMPONENT16; break; } diff --git a/libraries/gpu/src/gpu/Resource.cpp b/libraries/gpu/src/gpu/Resource.cpp index 4cdbe8203a..c162b38b93 100644 --- a/libraries/gpu/src/gpu/Resource.cpp +++ b/libraries/gpu/src/gpu/Resource.cpp @@ -14,11 +14,6 @@ using namespace gpu; -const Element Element::COLOR_RGBA_32 = Element(VEC4, NUINT8, RGBA); -const Element Element::VEC3F_XYZ = Element(VEC3, FLOAT, XYZ); -const Element Element::INDEX_UINT16 = Element(SCALAR, UINT16, INDEX); -const Element Element::PART_DRAWCALL = Element(VEC4, UINT32, PART); - Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size) { if ( !dataAllocated ) { qWarning() << "Buffer::Sysmem::allocateMemory() : Must have a valid dataAllocated pointer."; diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index de5e4a7242..f330b0fd07 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -144,6 +144,11 @@ public: return append(sizeof(t), reinterpret_cast(&t)); } + template + Size append(const std::vector& t) { + return append(sizeof(T) * t.size(), reinterpret_cast(&t[0])); + } + // Access the sysmem object. const Sysmem& getSysmem() const { assert(_sysmem); return (*_sysmem); } Sysmem& editSysmem() { assert(_sysmem); return (*_sysmem); } diff --git a/libraries/gpu/src/gpu/Stream.cpp b/libraries/gpu/src/gpu/Stream.cpp index 634545b4dd..98d23ac266 100644 --- a/libraries/gpu/src/gpu/Stream.cpp +++ b/libraries/gpu/src/gpu/Stream.cpp @@ -15,6 +15,37 @@ using namespace gpu; +using ElementArray = std::array; + +const ElementArray& getDefaultElements() { + static ElementArray defaultElements{ + //POSITION = 0, + Element::VEC3F_XYZ, + //NORMAL = 1, + Element::VEC3F_XYZ, + //COLOR = 2, + Element::COLOR_RGBA_32, + //TEXCOORD0 = 3, + Element::VEC2F_UV, + //TANGENT = 4, + Element::VEC3F_XYZ, + //SKIN_CLUSTER_INDEX = 5, + Element::VEC4F_XYZW, + //SKIN_CLUSTER_WEIGHT = 6, + Element::VEC4F_XYZW, + //TEXCOORD1 = 7, + Element::VEC2F_UV, + //INSTANCE_SCALE = 8, + Element::VEC3F_XYZ, + //INSTANCE_TRANSLATE = 9, + Element::VEC3F_XYZ, + //INSTANCE_XFM = 10, + // FIXME make a matrix element + Element::VEC4F_XYZW + }; + return defaultElements; +} + void Stream::Format::evaluateCache() { _channels.clear(); _elementTotalSize = 0; @@ -34,6 +65,19 @@ bool Stream::Format::setAttribute(Slot slot, Slot channel, Element element, Offs return true; } +bool Stream::Format::setAttribute(Slot slot, Frequency frequency) { + _attributes[slot] = Attribute((InputSlot)slot, slot, getDefaultElements()[slot], 0, frequency); + evaluateCache(); + return true; +} + +bool Stream::Format::setAttribute(Slot slot, Slot channel, Frequency frequency) { + _attributes[slot] = Attribute((InputSlot)slot, channel, getDefaultElements()[slot], 0, frequency); + evaluateCache(); + return true; +} + + BufferStream::BufferStream() : _buffers(), _offsets(), diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index c0ad1ebe46..420aa50f72 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -11,12 +11,14 @@ #ifndef hifi_gpu_Stream_h #define hifi_gpu_Stream_h +#include +#include +#include + #include #include "Resource.h" #include "Format.h" -#include -#include namespace gpu { @@ -55,6 +57,8 @@ public: // Every thing that is needed to detail a stream attribute and how to interpret it class Attribute { public: + Attribute() {} + Attribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX) : _slot(slot), _channel(channel), @@ -62,21 +66,12 @@ public: _offset(offset), _frequency(frequency) {} - Attribute() : - _slot(POSITION), - _channel(0), - _element(), - _offset(0), - _frequency(PER_VERTEX) - {} - - Slot _slot; // Logical slot assigned to the attribute - Slot _channel; // index of the channel where to get the data from - Element _element; - - Offset _offset; - uint32 _frequency; + Slot _slot{ POSITION }; // Logical slot assigned to the attribute + Slot _channel{ POSITION }; // index of the channel where to get the data from + Element _element{ Element::VEC3F_XYZ }; + Offset _offset{ 0 }; + uint32 _frequency{ PER_VERTEX }; // Size of the uint32 getSize() const { return _element.getSize(); } @@ -113,6 +108,9 @@ public: uint32 getElementTotalSize() const { return _elementTotalSize; } bool setAttribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX); + bool setAttribute(Slot slot, Frequency frequency = PER_VERTEX); + bool setAttribute(Slot slot, Slot channel, Frequency frequency = PER_VERTEX); + protected: AttributeMap _attributes; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 6c7310509a..1db26eae3b 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -187,15 +187,8 @@ gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch return pipeline; } +void DeferredLightingEffect::renderWireSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color) { -void DeferredLightingEffect::renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) { - bindSimpleProgram(batch); - DependencyManager::get()->renderSphere(batch, radius, slices, stacks, color); -} - -void DeferredLightingEffect::renderWireSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) { - bindSimpleProgram(batch); - DependencyManager::get()->renderSphere(batch, radius, slices, stacks, color, false); } uint32_t toCompactColor(const glm::vec4& color) { @@ -206,39 +199,89 @@ uint32_t toCompactColor(const glm::vec4& color) { return compactColor; } -void DeferredLightingEffect::renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color) { - static const std::string INSTANCE_NAME = __FUNCTION__; - static const size_t TRANSFORM_BUFFER = 0; - static const size_t COLOR_BUFFER = 1; +static const size_t INSTANCE_TRANSFORM_BUFFER = 0; +static const size_t INSTANCE_COLOR_BUFFER = 1; + +template +void renderInstances(const std::string& name, gpu::Batch& batch, const Transform& xfm, const glm::vec4& color, F f) { { - gpu::BufferPointer instanceTransformBuffer = batch.getNamedBuffer(INSTANCE_NAME, TRANSFORM_BUFFER); + gpu::BufferPointer instanceTransformBuffer = batch.getNamedBuffer(name, INSTANCE_TRANSFORM_BUFFER); glm::mat4 xfmMat4; instanceTransformBuffer->append(xfm.getMatrix(xfmMat4)); - gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(INSTANCE_NAME, COLOR_BUFFER); + gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(name, INSTANCE_COLOR_BUFFER); auto compactColor = toCompactColor(color); instanceColorBuffer->append(compactColor); } - batch.setupNamedCalls(INSTANCE_NAME, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - auto pipeline = bindSimpleProgram(batch); + auto that = DependencyManager::get(); + batch.setupNamedCalls(name, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + auto pipeline = that->bindSimpleProgram(batch); auto location = pipeline->getProgram()->getUniforms().findLocation("Instanced"); batch._glUniform1i(location, 1); - DependencyManager::get()->renderSolidCubeInstances(batch, data._count, - data._buffers[TRANSFORM_BUFFER], data._buffers[COLOR_BUFFER]); + f(batch, data); batch._glUniform1i(location, 0); }); } -void DeferredLightingEffect::renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color) { - bindSimpleProgram(batch); - DependencyManager::get()->renderSolidCube(batch, size, color); +void DeferredLightingEffect::renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + renderInstances(INSTANCE_NAME, batch, xfm, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderSphereInstances(batch, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); } -void DeferredLightingEffect::renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color) { - bindSimpleProgram(batch); - DependencyManager::get()->renderWireCube(batch, size, color); +static auto startTime = usecTimestampNow(); + +void DeferredLightingEffect::renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + +#ifdef DEBUG_SHAPES + renderInstances(INSTANCE_NAME, batch, xfm, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + + auto usecs = usecTimestampNow(); + usecs -= startTime; + auto msecs = usecs / USECS_PER_MSEC; + float seconds = msecs; + seconds /= MSECS_PER_SECOND; + float fractionalSeconds = seconds - floor(seconds); + int shapeIndex = (int)seconds; + + GeometryCache::Shape shapes[] = { + GeometryCache::Cube, + GeometryCache::Tetrahedron, + GeometryCache::Sphere, + GeometryCache::Icosahedron, + GeometryCache::Line, + }; + + shapeIndex %= 5; + GeometryCache::Shape shape = shapes[shapeIndex]; + + if (fractionalSeconds > 0.5f) { + DependencyManager::get()->renderShapeInstances(batch, shape, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + } else { + DependencyManager::get()->renderWireShapeInstances(batch, shape, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + } + }); +#else + renderInstances(INSTANCE_NAME, batch, xfm, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderCubeInstances(batch, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); +#endif +} + +void DeferredLightingEffect::renderWireCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color) { + static const std::string INSTANCE_NAME = __FUNCTION__; + renderInstances(INSTANCE_NAME, batch, xfm, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + DependencyManager::get()->renderWireCubeInstances(batch, data._count, + data._buffers[INSTANCE_TRANSFORM_BUFFER], data._buffers[INSTANCE_COLOR_BUFFER]); + }); } void DeferredLightingEffect::renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, @@ -546,8 +589,10 @@ void DeferredLightingEffect::render(RenderArgs* args) { } else { Transform model; model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z)); + model.postScale(expandedRadius); batch.setModelTransform(model); - geometryCache->renderSphere(batch, expandedRadius, 32, 32, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); + batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + geometryCache->renderSphere(batch); } } } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 83bb4c215f..9c4809a82e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -40,24 +40,26 @@ public: gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, bool emmisive = false, bool depthBias = false); - /// Sets up the state necessary to render static untextured geometry with the simple program. - void bindInstanceProgram(gpu::Batch& batch, bool textured = false, bool culled = true, - bool emmisive = false, bool depthBias = false); + void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); + void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { + renderSolidSphereInstance(batch, xfm, glm::vec4(color, 1.0)); + } - //// Renders a solid sphere with the simple program. - void renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color); + void renderWireSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); + void renderWireSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { + renderWireSphereInstance(batch, xfm, glm::vec4(color, 1.0)); + } - //// Renders a wireframe sphere with the simple program. - void renderWireSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color); - - //// Renders a solid cube using instancing. Transform should include scaling. void renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); + void renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { + renderSolidCubeInstance(batch, xfm, glm::vec4(color, 1.0)); + } - //// Renders a solid cube with the simple program. - void renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color); + void renderWireCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); + void renderWireCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { + renderWireCubeInstance(batch, xfm, glm::vec4(color, 1.0)); + } - //// Renders a wireframe cube with the simple program. - void renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color); //// Renders a quad with the simple program. void renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, const glm::vec4& color); diff --git a/libraries/render-utils/src/Environment.cpp b/libraries/render-utils/src/Environment.cpp index 605f67f957..bffac32b0c 100644 --- a/libraries/render-utils/src/Environment.cpp +++ b/libraries/render-utils/src/Environment.cpp @@ -197,6 +197,9 @@ bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3 } void Environment::renderAtmosphere(gpu::Batch& batch, ViewFrustum& viewFrustum, const EnvironmentData& data) { + // FIXME atmosphere rendering is broken in some way, + // should probably be replaced by a procedual skybox and put on the marketplace + return; glm::vec3 center = data.getAtmosphereCenter(); @@ -252,5 +255,6 @@ void Environment::renderAtmosphere(gpu::Batch& batch, ViewFrustum& viewFrustum, batch._glUniform1f(locations[G_LOCATION], -0.990f); batch._glUniform1f(locations[G2_LOCATION], -0.990f * -0.990f); - DependencyManager::get()->renderSphere(batch,1.0f, 100, 50, glm::vec4(1.0f, 0.0f, 0.0f, 0.5f)); //Draw a unit sphere + batch._glColor4f(1.0f, 0.0f, 0.0f, 0.5f); + DependencyManager::get()->renderSphere(batch); //Draw a unit sphere } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index ea05df84ef..53eb8a454b 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -33,11 +33,432 @@ const int GeometryCache::UNKNOWN_ID = -1; -GeometryCache::GeometryCache() : - _nextID(0) -{ +static const uint FLOATS_PER_VERTEX = 3; +static const uint VERTICES_PER_TRIANGLE = 3; +static const uint TRIANGLES_PER_QUAD = 2; +static const uint CUBE_FACES = 6; +static const uint CUBE_VERTICES_PER_FACE = 4; +static const uint CUBE_VERTICES = CUBE_FACES * CUBE_VERTICES_PER_FACE; +static const uint CUBE_VERTEX_POINTS = CUBE_VERTICES * FLOATS_PER_VERTEX; +static const uint CUBE_INDICES = CUBE_FACES * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE; +static const uint SPHERE_LATITUDES = 24; +static const uint SPHERE_MERIDIANS = SPHERE_LATITUDES * 2; +static const uint SPHERE_INDICES = SPHERE_MERIDIANS * (SPHERE_LATITUDES - 1) * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE; + +static const gpu::Element POSITION_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; +static const gpu::Element NORMAL_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; +static const gpu::Element COLOR_ELEMENT{ gpu::VEC4, gpu::NUINT8, gpu::RGBA }; +static const gpu::Element TRANSFORM_ELEMENT{ gpu::MAT4, gpu::FLOAT, gpu::XYZW }; + +static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT; +static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT; + +static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals +static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3); + + +void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const VVertex& vertices) { + vertexBuffer->append(vertices); + + _positionView = gpu::BufferView(vertexBuffer, 0, + vertexBuffer->getSize(), SHAPE_VERTEX_STRIDE, POSITION_ELEMENT); + _normalView = gpu::BufferView(vertexBuffer, SHAPE_NORMALS_OFFSET, + vertexBuffer->getSize(), SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT); +} + +void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, const VIndex& indices, const VIndex& wireIndices) { + _indices = indexBuffer; + if (!indices.empty()) { + _indexOffset = indexBuffer->getSize(); + _indexCount = indices.size(); + indexBuffer->append(indices); + } + + if (!wireIndices.empty()) { + _wireIndexOffset = indexBuffer->getSize(); + _wireIndexCount = wireIndices.size(); + indexBuffer->append(wireIndices); + } +} + +void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const { + batch.setInputBuffer(gpu::Stream::POSITION, _positionView); + batch.setInputBuffer(gpu::Stream::NORMAL, _normalView); +} + +void GeometryCache::ShapeData::draw(gpu::Batch& batch) const { + if (_indexCount) { + setupBatch(batch); + batch.setIndexBuffer(gpu::UINT16, _indices, _indexOffset); + batch.drawIndexed(gpu::TRIANGLES, _indexCount); + } +} + +void GeometryCache::ShapeData::drawWire(gpu::Batch& batch) const { + if (_wireIndexCount) { + setupBatch(batch); + batch.setIndexBuffer(gpu::UINT16, _indices, _wireIndexOffset); + batch.drawIndexed(gpu::LINES, _wireIndexCount); + } +} + +void GeometryCache::ShapeData::drawInstances(gpu::Batch& batch, size_t count) const { + if (_indexCount) { + setupBatch(batch); + batch.setIndexBuffer(gpu::UINT16, _indices, _indexOffset); + batch.drawIndexedInstanced(count, gpu::TRIANGLES, _indexCount); + } +} + +void GeometryCache::ShapeData::drawWireInstances(gpu::Batch& batch, size_t count) const { + if (_wireIndexCount) { + setupBatch(batch); + batch.setIndexBuffer(gpu::UINT16, _indices, _wireIndexOffset); + batch.drawIndexedInstanced(count, gpu::LINES, _wireIndexCount); + } +} + +const VVertex& icosahedronVertices() { + static const float phi = (1.0 + sqrt(5.0)) / 2.0; + static const float a = 0.5; + static const float b = 1.0 / (2.0 * phi); + + static const VVertex vertices{ // + vec3(0, b, -a), vec3(-b, a, 0), vec3(b, a, 0), // + vec3(0, b, a), vec3(b, a, 0), vec3(-b, a, 0), // + vec3(0, b, a), vec3(-a, 0, b), vec3(0, -b, a), // + vec3(0, b, a), vec3(0, -b, a), vec3(a, 0, b), // + vec3(0, b, -a), vec3(a, 0, -b), vec3(0, -b, -a),// + vec3(0, b, -a), vec3(0, -b, -a), vec3(-a, 0, -b), // + vec3(0, -b, a), vec3(-b, -a, 0), vec3(b, -a, 0), // + vec3(0, -b, -a), vec3(b, -a, 0), vec3(-b, -a, 0), // + vec3(-b, a, 0), vec3(-a, 0, -b), vec3(-a, 0, b), // + vec3(-b, -a, 0), vec3(-a, 0, b), vec3(-a, 0, -b), // + vec3(b, a, 0), vec3(a, 0, b), vec3(a, 0, -b), // + vec3(b, -a, 0), vec3(a, 0, -b), vec3(a, 0, b), // + vec3(0, b, a), vec3(-b, a, 0), vec3(-a, 0, b), // + vec3(0, b, a), vec3(a, 0, b), vec3(b, a, 0), // + vec3(0, b, -a), vec3(-a, 0, -b), vec3(-b, a, 0), // + vec3(0, b, -a), vec3(b, a, 0), vec3(a, 0, -b), // + vec3(0, -b, -a), vec3(-b, -a, 0), vec3(-a, 0, -b), // + vec3(0, -b, -a), vec3(a, 0, -b), vec3(b, -a, 0), // + vec3(0, -b, a), vec3(-a, 0, b), vec3(-b, -a, 0), // + vec3(0, -b, a), vec3(b, -a, 0), vec3(a, 0, b) + }; // + return vertices; +} + +const VVertex& tetrahedronVertices() { + static const float a = 1.0f / sqrt(2.0f); + static const auto A = vec3(0, 1, a); + static const auto B = vec3(0, -1, a); + static const auto C = vec3(1, 0, -a); + static const auto D = vec3(-1, 0, -a); + static const VVertex vertices{ + A, B, C, + D, B, A, + C, D, A, + C, B, D, + }; + return vertices; +} + +VVertex tesselate(const VVertex& startingTriangles, int count) { + VVertex triangles = startingTriangles; + if (0 != (triangles.size() % 3)) { + throw std::runtime_error("Bad number of vertices for tesselation"); + } + + for (size_t i = 0; i < triangles.size(); ++i) { + triangles[i] = glm::normalize(triangles[i]); + } + + VVertex newTriangles; + while (count) { + newTriangles.clear(); + newTriangles.reserve(triangles.size() * 4); + for (size_t i = 0; i < triangles.size(); i += 3) { + const vec3& a = triangles[i]; + const vec3& b = triangles[i + 1]; + const vec3& c = triangles[i + 2]; + vec3 ab = glm::normalize(a + b); + vec3 bc = glm::normalize(b + c); + vec3 ca = glm::normalize(c + a); + + newTriangles.push_back(a); + newTriangles.push_back(ab); + newTriangles.push_back(ca); + + newTriangles.push_back(b); + newTriangles.push_back(bc); + newTriangles.push_back(ab); + + newTriangles.push_back(c); + newTriangles.push_back(ca); + newTriangles.push_back(bc); + + newTriangles.push_back(ab); + newTriangles.push_back(bc); + newTriangles.push_back(ca); + } + triangles.swap(newTriangles); + --count; + } + return triangles; +} + +// FIXME solids need per-face vertices, but smooth shaded +// components do not. Find a way to support using draw elements +// or draw arrays as appropriate +// Maybe special case cone and cylinder since they combine flat +// and smooth shading +void GeometryCache::buildShapes() { + auto vertexBuffer = std::make_shared(); + auto indexBuffer = std::make_shared(); + uint16_t startingIndex = 0; + + // Cube + startingIndex = _shapeVertices->getSize() / SHAPE_VERTEX_STRIDE; + { + ShapeData& shapeData = _shapes[Cube]; + VVertex vertices; + // front + vertices.push_back(vec3(1, 1, 1)); + vertices.push_back(vec3(0, 0, 1)); + vertices.push_back(vec3(-1, 1, 1)); + vertices.push_back(vec3(0, 0, 1)); + vertices.push_back(vec3(-1, -1, 1)); + vertices.push_back(vec3(0, 0, 1)); + vertices.push_back(vec3(1, -1, 1)); + vertices.push_back(vec3(0, 0, 1)); + + // right + vertices.push_back(vec3(1, 1, 1)); + vertices.push_back(vec3(1, 0, 0)); + vertices.push_back(vec3(1, -1, 1)); + vertices.push_back(vec3(1, 0, 0)); + vertices.push_back(vec3(1, -1, -1)); + vertices.push_back(vec3(1, 0, 0)); + vertices.push_back(vec3(1, 1, -1)); + vertices.push_back(vec3(1, 0, 0)); + + // top + vertices.push_back(vec3(1, 1, 1)); + vertices.push_back(vec3(0, 1, 0)); + vertices.push_back(vec3(1, 1, -1)); + vertices.push_back(vec3(0, 1, 0)); + vertices.push_back(vec3(-1, 1, -1)); + vertices.push_back(vec3(0, 1, 0)); + vertices.push_back(vec3(-1, 1, 1)); + vertices.push_back(vec3(0, 1, 0)); + + // left + vertices.push_back(vec3(-1, 1, 1)); + vertices.push_back(vec3(-1, 0, 0)); + vertices.push_back(vec3(-1, 1, -1)); + vertices.push_back(vec3(-1, 0, 0)); + vertices.push_back(vec3(-1, -1, -1)); + vertices.push_back(vec3(-1, 0, 0)); + vertices.push_back(vec3(-1, -1, 1)); + vertices.push_back(vec3(-1, 0, 0)); + + // bottom + vertices.push_back(vec3(-1, -1, -1)); + vertices.push_back(vec3(0, -1, 0)); + vertices.push_back(vec3(1, -1, -1)); + vertices.push_back(vec3(0, -1, 0)); + vertices.push_back(vec3(1, -1, 1)); + vertices.push_back(vec3(0, -1, 0)); + vertices.push_back(vec3(-1, -1, 1)); + vertices.push_back(vec3(0, -1, 0)); + + // back + vertices.push_back(vec3(1, -1, -1)); + vertices.push_back(vec3(0, 0, -1)); + vertices.push_back(vec3(-1, -1, -1)); + vertices.push_back(vec3(0, 0, -1)); + vertices.push_back(vec3(-1, 1, -1)); + vertices.push_back(vec3(0, 0, -1)); + vertices.push_back(vec3(1, 1, -1)); + vertices.push_back(vec3(0, 0, -1)); + + for (size_t i = 0; i < vertices.size(); ++i) { + if (0 == i % 2) { + vertices[i] *= 0.5f; + } + } + shapeData.setupVertices(_shapeVertices, vertices); + + VIndex indices{ + 0, 1, 2, 2, 3, 0, // front + 4, 5, 6, 6, 7, 4, // right + 8, 9, 10, 10, 11, 8, // top + 12, 13, 14, 14, 15, 12, // left + 16, 17, 18, 18, 19, 16, // bottom + 20, 21, 22, 22, 23, 20 // back + }; + for (int i = 0; i < indices.size(); ++i) { + indices[i] += startingIndex; + } + + VIndex wireIndices{ + 0, 1, 1, 2, 2, 3, 3, 0, // front + 20, 21, 21, 22, 22, 23, 23, 20, // back + 0, 23, 1, 22, 2, 21, 3, 20 // sides + }; + for (int i = 0; i < wireIndices.size(); ++i) { + indices[i] += startingIndex; + } + + shapeData.setupIndices(_shapeIndices, indices, wireIndices); + } + + // Tetrahedron + startingIndex = _shapeVertices->getSize() / SHAPE_VERTEX_STRIDE; + { + ShapeData& shapeData = _shapes[Tetrahedron]; + size_t vertexCount = 4; + VVertex vertices; + { + VVertex originalVertices = tetrahedronVertices(); + vertexCount = originalVertices.size(); + vertices.reserve(originalVertices.size() * 2); + for (size_t i = 0; i < originalVertices.size(); i += 3) { + vec3 faceNormal; + for (size_t j = 0; j < 3; ++j) { + faceNormal += originalVertices[i + j]; + } + faceNormal = glm::normalize(faceNormal); + for (size_t j = 0; j < 3; ++j) { + vertices.push_back(glm::normalize(originalVertices[i + j]) * 0.5f); + vertices.push_back(faceNormal); + } + } + } + shapeData.setupVertices(_shapeVertices, vertices); + + VIndex indices; + for (size_t i = 0; i < vertexCount; i += 3) { + for (size_t j = 0; j < 3; ++j) { + indices.push_back(i + j + startingIndex); + } + } + + VIndex wireIndices{ + 0, 1, 1, 2, 2, 0, + 0, 3, 1, 3, 2, 3, + }; + + for (int i = 0; i < wireIndices.size(); ++i) { + wireIndices[i] += startingIndex; + } + + shapeData.setupIndices(_shapeIndices, indices, wireIndices); + } + + // Sphere + // FIXME this uses way more vertices than required. Should find a way to calculate the indices + // using shared vertices for better vertex caching + startingIndex = _shapeVertices->getSize() / SHAPE_VERTEX_STRIDE; + { + ShapeData& shapeData = _shapes[Sphere]; + VVertex vertices; + VIndex indices; + { + VVertex originalVertices = tesselate(icosahedronVertices(), 3); + vertices.reserve(originalVertices.size() * 2); + for (size_t i = 0; i < originalVertices.size(); i += 3) { + for (int j = 0; j < 3; ++j) { + vertices.push_back(originalVertices[i + j] * 0.5f); + vertices.push_back(originalVertices[i + j]); + indices.push_back(i + j + startingIndex); + } + } + } + + shapeData.setupVertices(_shapeVertices, vertices); + // FIXME don't use solid indices for wire drawing. + shapeData.setupIndices(_shapeIndices, indices, indices); + } + + // Icosahedron + startingIndex = _shapeVertices->getSize() / SHAPE_VERTEX_STRIDE; + { + ShapeData& shapeData = _shapes[Icosahedron]; + + VVertex vertices; + VIndex indices; + { + const VVertex& originalVertices = icosahedronVertices(); + vertices.reserve(originalVertices.size() * 2); + for (size_t i = 0; i < originalVertices.size(); i += 3) { + vec3 faceNormal; + for (size_t j = 0; j < 3; ++j) { + faceNormal += originalVertices[i + j]; + } + faceNormal = glm::normalize(faceNormal); + for (int j = 0; j < 3; ++j) { + vertices.push_back(glm::normalize(originalVertices[i + j]) * 0.5f); + vertices.push_back(faceNormal); + indices.push_back(i + j + startingIndex); + } + } + } + + shapeData.setupVertices(_shapeVertices, vertices); + // FIXME don't use solid indices for wire drawing. + shapeData.setupIndices(_shapeIndices, indices, indices); + } + + //Triangle, + //Quad, + //Circle, + //Octahetron, + //Dodecahedron, + //Torus, + //Cone, + //Cylinder, + // Line + startingIndex = _shapeVertices->getSize() / SHAPE_VERTEX_STRIDE; + { + ShapeData& shapeData = _shapes[Line]; + shapeData.setupVertices(_shapeVertices, VVertex{ + vec3(-0.5, 0, 0), vec3(-0.5, 0, 0), + vec3(0.5f, 0, 0), vec3(0.5f, 0, 0) + }); + VIndex wireIndices; + wireIndices.push_back(0 + startingIndex); + wireIndices.push_back(1 + startingIndex); + + shapeData.setupIndices(_shapeIndices, VIndex(), wireIndices); + } +} + +gpu::Stream::FormatPointer& getSolidStreamFormat() { + if (!SOLID_STREAM_FORMAT) { + SOLID_STREAM_FORMAT = std::make_shared(); // 1 for everyone + SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT); + SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT); + } + return SOLID_STREAM_FORMAT; +} + +gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() { + if (!INSTANCED_SOLID_STREAM_FORMAT) { + INSTANCED_SOLID_STREAM_FORMAT = std::make_shared(); // 1 for everyone + INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT); + INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT); + INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE); + INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::INSTANCE_XFM, gpu::Stream::INSTANCE_XFM, TRANSFORM_ELEMENT, 0, gpu::Stream::PER_INSTANCE); + } + return INSTANCED_SOLID_STREAM_FORMAT; +} + + +GeometryCache::GeometryCache() { const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE); + buildShapes(); } GeometryCache::~GeometryCache() { @@ -56,255 +477,64 @@ QSharedPointer GeometryCache::createResource(const QUrl& url, const QS return QSharedPointer(); } -const int NUM_VERTICES_PER_TRIANGLE = 3; -const int NUM_TRIANGLES_PER_QUAD = 2; -const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD; -const int NUM_COORDS_PER_VERTEX = 3; - -void GeometryCache::renderSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color, bool solid, int id) { - bool registered = (id != UNKNOWN_ID); - - Vec2Pair radiusKey(glm::vec2(radius, slices), glm::vec2(stacks, 0)); - IntPair slicesStacksKey(slices, stacks); - Vec3Pair colorKey(glm::vec3(color.x, color.y, slices), glm::vec3(color.z, color.w, stacks)); - - int vertices = slices * (stacks - 1) + 2; - int indices = slices * (stacks - 1) * NUM_VERTICES_PER_TRIANGULATED_QUAD; - - if ((registered && (!_registeredSphereVertices.contains(id) || _lastRegisteredSphereVertices[id] != radiusKey)) - || (!registered && !_sphereVertices.contains(radiusKey))) { - - if (registered && _registeredSphereVertices.contains(id)) { - _registeredSphereVertices[id].reset(); - #ifdef WANT_DEBUG - qCDebug(renderutils) << "renderSphere()... RELEASING REGISTERED VERTICES BUFFER"; - #endif - } - - auto verticesBuffer = std::make_shared(); - if (registered) { - _registeredSphereVertices[id] = verticesBuffer; - _lastRegisteredSphereVertices[id] = radiusKey; - } else { - _sphereVertices[radiusKey] = verticesBuffer; - } - - GLfloat* vertexData = new GLfloat[vertices * NUM_COORDS_PER_VERTEX]; - GLfloat* vertex = vertexData; - - // south pole - *(vertex++) = 0.0f; - *(vertex++) = 0.0f; - *(vertex++) = -1.0f * radius; - - //add stacks vertices climbing up Y axis - for (int i = 1; i < stacks; i++) { - float phi = PI * (float)i / (float)(stacks) - PI_OVER_TWO; - float z = sinf(phi) * radius; - float stackRadius = cosf(phi) * radius; - - for (int j = 0; j < slices; j++) { - float theta = TWO_PI * (float)j / (float)slices; - - *(vertex++) = sinf(theta) * stackRadius; - *(vertex++) = cosf(theta) * stackRadius; - *(vertex++) = z; - } - } - - // north pole - *(vertex++) = 0.0f; - *(vertex++) = 0.0f; - *(vertex++) = 1.0f * radius; - - verticesBuffer->append(sizeof(GLfloat) * vertices * NUM_COORDS_PER_VERTEX, (gpu::Byte*) vertexData); - delete[] vertexData; - - #ifdef WANT_DEBUG - qCDebug(renderutils) << "GeometryCache::renderSphere()... --- CREATING VERTICES BUFFER"; - qCDebug(renderutils) << " radius:" << radius; - qCDebug(renderutils) << " slices:" << slices; - qCDebug(renderutils) << " stacks:" << stacks; - - qCDebug(renderutils) << " _sphereVertices.size():" << _sphereVertices.size(); - #endif - } - #ifdef WANT_DEBUG - else if (registered) { - qCDebug(renderutils) << "renderSphere()... REUSING PREVIOUSLY REGISTERED VERTICES BUFFER"; - } - #endif - - if ((registered && (!_registeredSphereIndices.contains(id) || _lastRegisteredSphereIndices[id] != slicesStacksKey)) - || (!registered && !_sphereIndices.contains(slicesStacksKey))) { - - if (registered && _registeredSphereIndices.contains(id)) { - _registeredSphereIndices[id].reset(); - #ifdef WANT_DEBUG - qCDebug(renderutils) << "renderSphere()... RELEASING REGISTERED INDICES BUFFER"; - #endif - } - - auto indicesBuffer = std::make_shared(); - if (registered) { - _registeredSphereIndices[id] = indicesBuffer; - _lastRegisteredSphereIndices[id] = slicesStacksKey; - } else { - _sphereIndices[slicesStacksKey] = indicesBuffer; - } - - GLushort* indexData = new GLushort[indices]; - GLushort* index = indexData; - - int indexCount = 0; - - // South cap - GLushort bottom = 0; - GLushort top = 1; - for (int i = 0; i < slices; i++) { - *(index++) = bottom; - *(index++) = top + i; - *(index++) = top + (i + 1) % slices; - - indexCount += 3; - } - - // (stacks - 2) ribbons - for (int i = 0; i < stacks - 2; i++) { - bottom = i * slices + 1; - top = bottom + slices; - for (int j = 0; j < slices; j++) { - int next = (j + 1) % slices; - - *(index++) = top + next; - *(index++) = bottom + j; - *(index++) = top + j; - - indexCount += 3; - - *(index++) = bottom + next; - *(index++) = bottom + j; - *(index++) = top + next; - - indexCount += 3; - - } - } - - // north cap - bottom = (stacks - 2) * slices + 1; - top = bottom + slices; - for (int i = 0; i < slices; i++) { - *(index++) = bottom + (i + 1) % slices; - *(index++) = bottom + i; - *(index++) = top; - - indexCount += 3; - - } - indicesBuffer->append(sizeof(GLushort) * indices, (gpu::Byte*) indexData); - delete[] indexData; - - #ifdef WANT_DEBUG - qCDebug(renderutils) << "GeometryCache::renderSphere()... --- CREATING INDICES BUFFER"; - qCDebug(renderutils) << " radius:" << radius; - qCDebug(renderutils) << " slices:" << slices; - qCDebug(renderutils) << " stacks:" << stacks; - qCDebug(renderutils) << "indexCount:" << indexCount; - qCDebug(renderutils) << " indices:" << indices; - qCDebug(renderutils) << " _sphereIndices.size():" << _sphereIndices.size(); - #endif - } - #ifdef WANT_DEBUG - else if (registered) { - qCDebug(renderutils) << "renderSphere()... REUSING PREVIOUSLY REGISTERED INDICES BUFFER"; - } - #endif - - if ((registered && (!_registeredSphereColors.contains(id) || _lastRegisteredSphereColors[id] != colorKey)) - || (!registered && !_sphereColors.contains(colorKey))) { - - if (registered && _registeredSphereColors.contains(id)) { - _registeredSphereColors[id].reset(); - #ifdef WANT_DEBUG - qCDebug(renderutils) << "renderSphere()... RELEASING REGISTERED COLORS BUFFER"; - #endif - } - - auto colorBuffer = std::make_shared(); - if (registered) { - _registeredSphereColors[id] = colorBuffer; - _lastRegisteredSphereColors[id] = colorKey; - } else { - _sphereColors[colorKey] = colorBuffer; - } - - int compactColor = ((int(color.x * 255.0f) & 0xFF)) | - ((int(color.y * 255.0f) & 0xFF) << 8) | - ((int(color.z * 255.0f) & 0xFF) << 16) | - ((int(color.w * 255.0f) & 0xFF) << 24); - - int* colorData = new int[vertices]; - int* colorDataAt = colorData; - - for(int v = 0; v < vertices; v++) { - *(colorDataAt++) = compactColor; - } - - colorBuffer->append(sizeof(int) * vertices, (gpu::Byte*) colorData); - delete[] colorData; - - #ifdef WANT_DEBUG - qCDebug(renderutils) << "GeometryCache::renderSphere()... --- CREATING COLORS BUFFER"; - qCDebug(renderutils) << " vertices:" << vertices; - qCDebug(renderutils) << " color:" << color; - qCDebug(renderutils) << " slices:" << slices; - qCDebug(renderutils) << " stacks:" << stacks; - qCDebug(renderutils) << " _sphereColors.size():" << _sphereColors.size(); - #endif - } - #ifdef WANT_DEBUG - else if (registered) { - qCDebug(renderutils) << "renderSphere()... REUSING PREVIOUSLY REGISTERED COLORS BUFFER"; - } - #endif - - gpu::BufferPointer verticesBuffer = registered ? _registeredSphereVertices[id] : _sphereVertices[radiusKey]; - gpu::BufferPointer indicesBuffer = registered ? _registeredSphereIndices[id] : _sphereIndices[slicesStacksKey]; - gpu::BufferPointer colorBuffer = registered ? _registeredSphereColors[id] : _sphereColors[colorKey]; - - const int VERTICES_SLOT = 0; - const int NORMALS_SLOT = 1; - const int COLOR_SLOT = 2; - static gpu::Stream::FormatPointer streamFormat; - static gpu::Element positionElement, normalElement, colorElement; - if (!streamFormat) { - streamFormat = std::make_shared(); // 1 for everyone - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); - positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element; - normalElement = streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element; - colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element; - } - - gpu::BufferView verticesView(verticesBuffer, positionElement); - gpu::BufferView normalsView(verticesBuffer, normalElement); - gpu::BufferView colorView(colorBuffer, colorElement); - - batch.setInputFormat(streamFormat); - batch.setInputBuffer(VERTICES_SLOT, verticesView); - batch.setInputBuffer(NORMALS_SLOT, normalsView); - batch.setInputBuffer(COLOR_SLOT, colorView); - batch.setIndexBuffer(gpu::UINT16, indicesBuffer, 0); - - if (solid) { - batch.drawIndexed(gpu::TRIANGLES, indices); - } else { - batch.drawIndexed(gpu::LINES, indices); - } +void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer) { + gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT); + batch.setInputBuffer(gpu::Stream::COLOR, colorView); + gpu::BufferView instanceXfmView(transformBuffer, 0, transformBuffer->getSize(), TRANSFORM_ELEMENT); + batch.setInputBuffer(gpu::Stream::INSTANCE_XFM, instanceXfmView); } +void GeometryCache::renderShape(gpu::Batch& batch, Shape shape) { + batch.setInputFormat(getSolidStreamFormat()); + _shapes[shape].draw(batch); +} + +void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape) { + batch.setInputFormat(getSolidStreamFormat()); + _shapes[shape].drawWire(batch); +} + +void GeometryCache::renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& transformBuffer, gpu::BufferPointer& colorBuffer) { + batch.setInputFormat(getInstancedSolidStreamFormat()); + setupBatchInstance(batch, transformBuffer, colorBuffer); + _shapes[shape].drawInstances(batch, count); +} + +void GeometryCache::renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& transformBuffer, gpu::BufferPointer& colorBuffer) { + batch.setInputFormat(getInstancedSolidStreamFormat()); + setupBatchInstance(batch, transformBuffer, colorBuffer); + _shapes[shape].drawWireInstances(batch, count); +} + +void GeometryCache::renderCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer) { + renderShapeInstances(batch, Cube, count, transformBuffer, colorBuffer); +} + +void GeometryCache::renderWireCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer) { + renderWireShapeInstances(batch, Cube, count, transformBuffer, colorBuffer); +} + +void GeometryCache::renderCube(gpu::Batch& batch) { + renderShape(batch, Cube); +} + +void GeometryCache::renderWireCube(gpu::Batch& batch) { + renderWireShape(batch, Cube); +} + +void GeometryCache::renderSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer) { + renderShapeInstances(batch, Sphere, count, transformBuffer, colorBuffer); +} + +void GeometryCache::renderSphere(gpu::Batch& batch) { + renderShape(batch, Sphere); +} + +void GeometryCache::renderWireSphere(gpu::Batch& batch) { + renderWireShape(batch, Sphere); +} + + void GeometryCache::renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color) { IntPair key(xDivisions, yDivisions); Vec3Pair colorKey(glm::vec3(color.x, color.y, yDivisions), glm::vec3(color.z, color.y, xDivisions)); @@ -689,243 +919,6 @@ void GeometryCache::renderVertices(gpu::Batch& batch, gpu::Primitive primitiveTy } } -static const int FLOATS_PER_VERTEX = 3; -static const int VERTICES_PER_TRIANGLE = 3; - -static const int CUBE_NUMBER_OF_FACES = 6; -static const int CUBE_VERTICES_PER_FACE = 4; -static const int CUBE_TRIANGLES_PER_FACE = 2; -static const int CUBE_VERTICES = CUBE_NUMBER_OF_FACES * CUBE_VERTICES_PER_FACE; -static const int CUBE_VERTEX_POINTS = CUBE_VERTICES * FLOATS_PER_VERTEX; -static const int CUBE_INDICES = CUBE_NUMBER_OF_FACES * CUBE_TRIANGLES_PER_FACE * VERTICES_PER_TRIANGLE; - -static const gpu::Element CUBE_POSITION_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; -static const gpu::Element CUBE_NORMAL_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; -static const gpu::Element CUBE_COLOR_ELEMENT{ gpu::VEC4, gpu::NUINT8, gpu::RGBA }; -static const gpu::Element INSTANCE_XFM_ELEMENT{ gpu::MAT4, gpu::FLOAT, gpu::XYZW }; - -gpu::BufferPointer GeometryCache::getCubeVertices(float size) { - if (!_solidCubeVertices.contains(size)) { - auto verticesBuffer = std::make_shared(); - _solidCubeVertices[size] = verticesBuffer; - - GLfloat* vertexData = new GLfloat[CUBE_VERTEX_POINTS * 2]; // vertices and normals - GLfloat* vertex = vertexData; - float halfSize = size / 2.0f; - - static GLfloat cannonicalVertices[CUBE_VERTEX_POINTS] = - { 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0,v1,v2,v3 (front) - 1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0,v3,v4,v5 (right) - 1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0,v5,v6,v1 (top) - -1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, // v1,v6,v7,v2 (left) - -1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, // v7,v4,v3,v2 (bottom) - 1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 }; // v4,v7,v6,v5 (back) - - // normal array - static GLfloat cannonicalNormals[CUBE_VERTEX_POINTS] = - { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0,v1,v2,v3 (front) - 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0,v3,v4,v5 (right) - 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0,v5,v6,v1 (top) - -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1,v6,v7,v2 (left) - 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7,v4,v3,v2 (bottom) - 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 }; // v4,v7,v6,v5 (back) - - - GLfloat* cannonicalVertex = &cannonicalVertices[0]; - GLfloat* cannonicalNormal = &cannonicalNormals[0]; - - for (int i = 0; i < CUBE_VERTICES; i++) { - // vertices - *(vertex++) = halfSize * *cannonicalVertex++; - *(vertex++) = halfSize * *cannonicalVertex++; - *(vertex++) = halfSize * *cannonicalVertex++; - - //normals - *(vertex++) = *cannonicalNormal++; - *(vertex++) = *cannonicalNormal++; - *(vertex++) = *cannonicalNormal++; - } - verticesBuffer->append(sizeof(GLfloat) * CUBE_VERTEX_POINTS * 2, (gpu::Byte*) vertexData); - } - - return _solidCubeVertices[size]; -} - -gpu::BufferPointer GeometryCache::getSolidCubeIndices() { - if (!_solidCubeIndexBuffer) { - static GLubyte cannonicalIndices[CUBE_INDICES] = { 0, 1, 2, 2, 3, 0, // front - 4, 5, 6, 6, 7, 4, // right - 8, 9,10, 10,11, 8, // top - 12,13,14, 14,15,12, // left - 16,17,18, 18,19,16, // bottom - 20,21,22, 22,23,20 }; // back - - auto indexBuffer = std::make_shared(); - _solidCubeIndexBuffer = indexBuffer; - - _solidCubeIndexBuffer->append(sizeof(cannonicalIndices), (gpu::Byte*) cannonicalIndices); - } - return _solidCubeIndexBuffer; -} - - -void GeometryCache::setupCubeVertices(gpu::Batch& batch, gpu::BufferPointer& verticesBuffer) { - static const int VERTEX_STRIDE = sizeof(GLfloat) * FLOATS_PER_VERTEX * 2; // vertices and normals - static const int NORMALS_OFFSET = sizeof(GLfloat) * FLOATS_PER_VERTEX; - - gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), VERTEX_STRIDE, CUBE_POSITION_ELEMENT); - gpu::BufferView normalsView(verticesBuffer, NORMALS_OFFSET, verticesBuffer->getSize(), VERTEX_STRIDE, CUBE_NORMAL_ELEMENT); - batch.setInputBuffer(gpu::Stream::POSITION, verticesView); - batch.setInputBuffer(gpu::Stream::NORMAL, normalsView); -} - -void GeometryCache::renderSolidCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer) { - static gpu::Stream::FormatPointer streamFormat; - if (!streamFormat) { - streamFormat = std::make_shared(); // 1 for everyone - streamFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, CUBE_POSITION_ELEMENT, 0); - streamFormat->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, CUBE_NORMAL_ELEMENT); - streamFormat->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, CUBE_COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE); - streamFormat->setAttribute(gpu::Stream::INSTANCE_XFM, gpu::Stream::INSTANCE_XFM, INSTANCE_XFM_ELEMENT, 0, gpu::Stream::PER_INSTANCE); - } - batch.setInputFormat(streamFormat); - - gpu::BufferView colorView(colorBuffer, CUBE_COLOR_ELEMENT); - batch.setInputBuffer(gpu::Stream::COLOR, colorView); - - gpu::BufferView instanceXfmView(transformBuffer, 0, transformBuffer->getSize(), INSTANCE_XFM_ELEMENT); - batch.setInputBuffer(gpu::Stream::INSTANCE_XFM, instanceXfmView); - - gpu::BufferPointer verticesBuffer = getCubeVertices(1.0); - setupCubeVertices(batch, verticesBuffer); - batch.setIndexBuffer(gpu::UINT8, getSolidCubeIndices(), 0); - batch.drawIndexedInstanced(count, gpu::TRIANGLES, CUBE_INDICES); -} - - -void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color) { - Vec2Pair colorKey(glm::vec2(color.x, color.y), glm::vec2(color.z, color.y)); - if (!_solidCubeColors.contains(colorKey)) { - auto colorBuffer = std::make_shared(); - _solidCubeColors[colorKey] = colorBuffer; - - int compactColor = ((int(color.x * 255.0f) & 0xFF)) | - ((int(color.y * 255.0f) & 0xFF) << 8) | - ((int(color.z * 255.0f) & 0xFF) << 16) | - ((int(color.w * 255.0f) & 0xFF) << 24); - int colors[CUBE_VERTICES] = { - compactColor, compactColor, compactColor, compactColor, - compactColor, compactColor, compactColor, compactColor, - compactColor, compactColor, compactColor, compactColor, - compactColor, compactColor, compactColor, compactColor, - compactColor, compactColor, compactColor, compactColor, - compactColor, compactColor, compactColor, compactColor - }; - colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); - } - gpu::BufferPointer colorBuffer = _solidCubeColors[colorKey]; - - static gpu::Stream::FormatPointer streamFormat; - if (!streamFormat) { - streamFormat = std::make_shared(); // 1 for everyone - streamFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, CUBE_POSITION_ELEMENT, 0); - streamFormat->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, CUBE_NORMAL_ELEMENT); - streamFormat->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, CUBE_COLOR_ELEMENT); - } - batch.setInputFormat(streamFormat); - - gpu::BufferView colorView(colorBuffer, CUBE_COLOR_ELEMENT); - batch.setInputBuffer(gpu::Stream::COLOR, colorView); - - gpu::BufferPointer verticesBuffer = getCubeVertices(size); - setupCubeVertices(batch, verticesBuffer); - - batch.setIndexBuffer(gpu::UINT8, getSolidCubeIndices(), 0); - batch.drawIndexed(gpu::TRIANGLES, CUBE_INDICES); -} - - -void GeometryCache::renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color) { - Vec2Pair colorKey(glm::vec2(color.x, color.y),glm::vec2(color.z, color.y)); - static const int WIRE_CUBE_VERTICES_PER_EDGE = 2; - static const int WIRE_CUBE_TOP_EDGES = 4; - static const int WIRE_CUBE_BOTTOM_EDGES = 4; - static const int WIRE_CUBE_SIDE_EDGES = 4; - static const int WIRE_CUBE_VERTICES = 8; - static const int WIRE_CUBE_INDICES = (WIRE_CUBE_TOP_EDGES + WIRE_CUBE_BOTTOM_EDGES + WIRE_CUBE_SIDE_EDGES) * WIRE_CUBE_VERTICES_PER_EDGE; - - if (!_cubeVerticies.contains(size)) { - auto verticesBuffer = std::make_shared(); - _cubeVerticies[size] = verticesBuffer; - - static const int WIRE_CUBE_VERTEX_POINTS = WIRE_CUBE_VERTICES * FLOATS_PER_VERTEX; - GLfloat* vertexData = new GLfloat[WIRE_CUBE_VERTEX_POINTS]; // only vertices, no normals because we're a wire cube - GLfloat* vertex = vertexData; - float halfSize = size / 2.0f; - - static GLfloat cannonicalVertices[] = - { 1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0, v1, v2, v3 (top) - 1,-1, 1, 1,-1,-1, -1,-1,-1, -1,-1, 1 // v4, v5, v6, v7 (bottom) - }; - - for (int i = 0; i < WIRE_CUBE_VERTEX_POINTS; i++) { - vertex[i] = cannonicalVertices[i] * halfSize; - } - - verticesBuffer->append(sizeof(GLfloat) * WIRE_CUBE_VERTEX_POINTS, (gpu::Byte*) vertexData); // I'm skeptical that this is right - } - - if (!_wireCubeIndexBuffer) { - static GLubyte cannonicalIndices[WIRE_CUBE_INDICES] = { - 0, 1, 1, 2, 2, 3, 3, 0, // (top) - 4, 5, 5, 6, 6, 7, 7, 4, // (bottom) - 0, 4, 1, 5, 2, 6, 3, 7, // (side edges) - }; - - auto indexBuffer = std::make_shared(); - _wireCubeIndexBuffer = indexBuffer; - - _wireCubeIndexBuffer->append(sizeof(cannonicalIndices), (gpu::Byte*) cannonicalIndices); - } - - if (!_cubeColors.contains(colorKey)) { - auto colorBuffer = std::make_shared(); - _cubeColors[colorKey] = colorBuffer; - - const int NUM_COLOR_SCALARS_PER_CUBE = 8; - int compactColor = ((int(color.x * 255.0f) & 0xFF)) | - ((int(color.y * 255.0f) & 0xFF) << 8) | - ((int(color.z * 255.0f) & 0xFF) << 16) | - ((int(color.w * 255.0f) & 0xFF) << 24); - int colors[NUM_COLOR_SCALARS_PER_CUBE] = { compactColor, compactColor, compactColor, compactColor, - compactColor, compactColor, compactColor, compactColor }; - - colorBuffer->append(sizeof(colors), (gpu::Byte*) colors); - } - gpu::BufferPointer verticesBuffer = _cubeVerticies[size]; - gpu::BufferPointer colorBuffer = _cubeColors[colorKey]; - - const int VERTICES_SLOT = 0; - const int COLOR_SLOT = 1; - static gpu::Stream::FormatPointer streamFormat; - static gpu::Element positionElement, colorElement; - if (!streamFormat) { - streamFormat = std::make_shared(); // 1 for everyone - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); - positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element; - colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element; - } - - gpu::BufferView verticesView(verticesBuffer, positionElement); - gpu::BufferView colorView(colorBuffer, colorElement); - - batch.setInputFormat(streamFormat); - batch.setInputBuffer(VERTICES_SLOT, verticesView); - batch.setInputBuffer(COLOR_SLOT, colorView); - batch.setIndexBuffer(gpu::UINT8, _wireCubeIndexBuffer, 0); - batch.drawIndexed(gpu::LINES, WIRE_CUBE_INDICES); -} void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id) { bool registered = (id != UNKNOWN_ID); @@ -1099,10 +1092,10 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co batch.draw(gpu::TRIANGLE_STRIP, 4, 0); } -void GeometryCache::renderUnitCube(gpu::Batch& batch) { - static const glm::vec4 color(1); - renderSolidCube(batch, 1, color); -} +//void GeometryCache::renderUnitCube(gpu::Batch& batch) { +// static const glm::vec4 color(1); +// renderSolidCube(batch, 1, color); +//} void GeometryCache::renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, int id) { static const glm::vec2 topLeft(-1, 1); @@ -2043,8 +2036,8 @@ static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBas // need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); } - if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); - if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); + if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW)); + if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW)); } else { int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); @@ -2076,8 +2069,8 @@ static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBas if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB)); if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); - if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); - if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); + if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW)); + if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW)); } } diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 9ba2658a9c..d911629001 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -12,6 +12,8 @@ #ifndef hifi_GeometryCache_h #define hifi_GeometryCache_h +#include + #include #include @@ -119,37 +121,59 @@ inline uint qHash(const Vec4PairVec4Pair& v, uint seed) { seed); } +using VVertex = std::vector; +using VIndex = std::vector; + /// Stores cached geometry. class GeometryCache : public ResourceCache, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY public: + enum Shape { + Line, + Triangle, + Quad, + Circle, + Cube, + Sphere, + Tetrahedron, + Octahetron, + Dodecahedron, + Icosahedron, + Torus, + Cone, + Cylinder, + + NUM_SHAPES, + }; + int allocateID() { return _nextID++; } static const int UNKNOWN_ID; virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, bool delayLoad, const void* extra); - gpu::BufferPointer getCubeVertices(float size); - void setupCubeVertices(gpu::Batch& batch, gpu::BufferPointer& verticesBuffer); + void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& transformBuffer, gpu::BufferPointer& colorBuffer); + void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& transformBuffer, gpu::BufferPointer& colorBuffer); + void renderShape(gpu::Batch& batch, Shape shape); + void renderWireShape(gpu::Batch& batch, Shape shape); - gpu::BufferPointer getSolidCubeIndices(); + void renderCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer); + void renderWireCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer); + void renderCube(gpu::Batch& batch); + void renderWireCube(gpu::Batch& batch); - void renderSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec3& color, bool solid = true, int id = UNKNOWN_ID) - { renderSphere(batch, radius, slices, stacks, glm::vec4(color, 1.0f), solid, id); } - - void renderSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color, bool solid = true, int id = UNKNOWN_ID); + void renderSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer); + void renderWireSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer); + void renderSphere(gpu::Batch& batch); + void renderWireSphere(gpu::Batch& batch); void renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color); void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id = UNKNOWN_ID); - void renderSolidCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer); - void renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color); - void renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color); void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID); - void renderUnitCube(gpu::Batch& batch); void renderUnitQuad(gpu::Batch& batch, const glm::vec4& color = glm::vec4(1), int id = UNKNOWN_ID); void renderQuad(gpu::Batch& batch, int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID) @@ -223,19 +247,41 @@ public: private: GeometryCache(); virtual ~GeometryCache(); + void buildShapes(); typedef QPair IntPair; typedef QPair VerticesIndices; + struct ShapeData { + size_t _indexOffset{ 0 }; + size_t _indexCount{ 0 }; + size_t _wireIndexOffset{ 0 }; + size_t _wireIndexCount{ 0 }; + + gpu::BufferView _positionView; + gpu::BufferView _normalView; + gpu::BufferPointer _indices; + + void setupVertices(gpu::BufferPointer& vertexBuffer, const VVertex& vertices); + void setupIndices(gpu::BufferPointer& indexBuffer, const VIndex& indices, const VIndex& wireIndices); + void setupBatch(gpu::Batch& batch) const; + void draw(gpu::Batch& batch) const; + void drawWire(gpu::Batch& batch) const; + void drawInstances(gpu::Batch& batch, size_t count) const; + void drawWireInstances(gpu::Batch& batch, size_t count) const; + }; + + using VShape = std::array; + + VShape _shapes; + + + gpu::PipelinePointer _standardDrawPipeline; gpu::PipelinePointer _standardDrawPipelineNoBlend; - QHash _cubeVerticies; - QHash _cubeColors; - gpu::BufferPointer _wireCubeIndexBuffer; - QHash _solidCubeVertices; - QHash _solidCubeColors; - gpu::BufferPointer _solidCubeIndexBuffer; + gpu::BufferPointer _shapeVertices{ std::make_shared() }; + gpu::BufferPointer _shapeIndices{ std::make_shared() }; class BatchItemDetails { public: @@ -257,7 +303,7 @@ private: QHash _coneVBOs; - int _nextID; + int _nextID{ 0 }; QHash _lastRegisteredQuad3DTexture; QHash _quad3DTextures; @@ -299,16 +345,6 @@ private: QHash _lastRegisteredAlternateGridBuffers; QHash _gridColors; - QHash _sphereVertices; - QHash _registeredSphereVertices; - QHash _lastRegisteredSphereVertices; - QHash _sphereIndices; - QHash _registeredSphereIndices; - QHash _lastRegisteredSphereIndices; - QHash _sphereColors; - QHash _registeredSphereColors; - QHash _lastRegisteredSphereColors; - QHash > _networkGeometry; }; diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index b27d10e312..ad9ed9bb4a 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -10,15 +10,22 @@ #include #include +#include #include +#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include #include #include @@ -26,17 +33,17 @@ #include #include -#include -#include -#include -#include -#include -#include +// Must come after GL headers +#include + +#include #include #include +#include +#include -#include "simple_frag.h" -#include "simple_vert.h" +#include "unlit_frag.h" +#include "unlit_vert.h" class RateCounter { std::vector times; @@ -74,173 +81,7 @@ public: } }; -#define MOVE_PARAM(name) decltype(name) && name - -struct BasicModel { - gpu::PipelinePointer pipeline; -// gpu::BufferPointer vertexBuffer; -// gpu::BufferPointer indexBuffer; -// gpu::BufferPointer normalBuffer; - - gpu::BufferView vertices; - gpu::BufferView normals; - gpu::BufferPointer indices; - - gpu::Stream::FormatPointer format; - - BasicModel (MOVE_PARAM(pipeline), MOVE_PARAM(vertices), MOVE_PARAM(normals), MOVE_PARAM(indices), MOVE_PARAM(format)) - : pipeline(pipeline), vertices(vertices), normals(normals), indices(indices), format(format) {} - -// BasicModel (gpu::PipelinePointer && pipeline, gpu::BufferPointer && buffer, gpu::Stream::FormatPointer && format) -// : pipeline(pipeline), buffer(buffer), format(format) {} -}; -typedef std::shared_ptr BasicModelPointer; -#undef MOVE_PARAM - -BasicModelPointer makeCube () { - // Axis-aligned cube, facing the user at +z - // coords == binary mapping of each index, with z inverted (front face faces camera, - // instead of away from the camera) - // - // -x,+y,-z ----------- +x,+y,-z - // ___--- | ___--- | - // -x,+y,+z --------- +x,+y,+z | - // | | | | - // | | | | - // | | | | - // | | | | - // | -x,-y,-z ------|---- +x,-y,-z - // | ___--- | ___---- - // -x,-y,+z --------- +x,-y,+z - // - float s = 1.0f; - const glm::vec3 raw_verts[8] = { - // x, y, z - { -s, -s, +s }, // 0b000 0x0 - { +s, -s, +s }, // 0b001 0x1 - { -s, +s, +s }, // 0b010 0x2 - { +s, +s, +s }, // 0b011 0x3 - { -s, -s, -s }, // 0b100 0x4 - { +s, -s, -s }, // 0b101 0x5 - { -s, +s, -s }, // 0b110 0x6 - { +s, +s, -s } // 0b111 0x7 - }; - const glm::vec3 raw_normals[6] = { - { 0.0f, 0.0f, +1.0f }, // x > 0: 1, 3, 5, 7 (N 0) - { 0.0f, 0.0f, -1.0f }, // x < 0: 0, 2, 4, 6 (N 1) - { 0.0f, +1.0f, 0.0f }, // y > 0: 2, 3, 6, 7 (N 2) - { 0.0f, -1.0f, 0.0f }, // y < 0: 0, 1, 4, 5 (N 3) - { +1.0f, 0.0f, 0.0f }, // z > 0: 0, 1, 2, 3 (N 4) - { -1.0f, 0.0f, 0.0f } // z < 0: 4, 5, 6, 7 (N 5) - }; - - const glm::vec3 cube_verts[24] = { - raw_verts[1], raw_verts[3], raw_verts[5], raw_verts[7], - raw_verts[0], raw_verts[2], raw_verts[4], raw_verts[6], - raw_verts[2], raw_verts[3], raw_verts[6], raw_verts[7], - raw_verts[0], raw_verts[1], raw_verts[4], raw_verts[5], - raw_verts[0], raw_verts[1], raw_verts[2], raw_verts[3], - raw_verts[4], raw_verts[5], raw_verts[6], raw_verts[7] - }; - const glm::vec3 cube_normals[24] = { - raw_normals[0], raw_normals[0], raw_normals[0], raw_normals[0], - raw_normals[1], raw_normals[1], raw_normals[1], raw_normals[1], - raw_normals[2], raw_normals[2], raw_normals[2], raw_normals[2], - raw_normals[3], raw_normals[3], raw_normals[3], raw_normals[3], - raw_normals[4], raw_normals[4], raw_normals[4], raw_normals[4], - raw_normals[5], raw_normals[5], raw_normals[5], raw_normals[5] - }; - - int16_t cube_indices_tris[36]; - for (int i = 0, k = 0; i < 36; k += 4) { - cube_indices_tris[i++] = k + 0; - cube_indices_tris[i++] = k + 3; - cube_indices_tris[i++] = k + 1; - cube_indices_tris[i++] = k + 0; - cube_indices_tris[i++] = k + 2; - cube_indices_tris[i++] = k + 3; - } - -// const int16_t cube_indices_tris[36] { -// 0, 3, 1, 0, 2, 3, -// }; - -// const glm::vec3 cube_normals[] = { -// { 0.0f, 0.0f, 1.0f }, -// { 0.0f, 0.0f, 1.0f }, -// { 0.0f, 0.0f, 1.0f }, -// { 0.0f, 0.0f, 1.0f }, -// { -1.0f, 0.0f, 0.0f }, -// { -1.0f, 0.0f, 0.0f }, -// { -1.0f, 0.0f, 0.0f }, -// { -1.0f, 0.0f, 0.0f }, -// }; -// const int16_t cube_indices[] = { -// 3, 1, 0, 2, 3, 0, -// 6, 2, 0, 4, 6, 0, -// }; - - gpu::Stream::FormatPointer format = std::make_shared(); - - assert(gpu::Stream::POSITION == 0 && gpu::Stream::NORMAL == 1); - const int BUFFER_SLOT = 0; - - format->setAttribute(gpu::Stream::POSITION, BUFFER_SLOT, gpu::Element::VEC3F_XYZ); - format->setAttribute(gpu::Stream::NORMAL, BUFFER_SLOT, gpu::Element::VEC3F_XYZ); - - auto vertexBuffer = std::make_shared(24 * sizeof(glm::vec3), (gpu::Byte*)cube_verts); - auto normalBuffer = std::make_shared(24 * sizeof(glm::vec3), (gpu::Byte*)cube_normals); - gpu::BufferPointer indexBuffer = std::make_shared(36 * sizeof(int16_t), (gpu::Byte*)cube_indices_tris); - - auto positionElement = format->getAttributes().at(gpu::Stream::POSITION)._element; - auto normalElement = format->getAttributes().at(gpu::Stream::NORMAL)._element; - - gpu::BufferView vertexView { vertexBuffer, positionElement }; - gpu::BufferView normalView { normalBuffer, normalElement }; - - // Create shaders - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex({ simple_vert })); - auto fs = gpu::ShaderPointer(gpu::Shader::createPixel({ simple_frag })); - auto shader = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); - - gpu::Shader::BindingSet bindings; - bindings.insert({ "lightPosition", 1 }); - - if (!gpu::Shader::makeProgram(*shader, bindings)) { - printf("Could not compile shader\n"); - if (!vs) - printf("bad vertex shader\n"); - if (!fs) - printf("bad fragment shader\n"); - if (!shader) - printf("bad shader program\n"); - exit(-1); - } - - auto state = std::make_shared(); -// state->setAntialiasedLineEnable(true); - state->setMultisampleEnable(true); - state->setDepthTest({ true }); - auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(shader, state)); - - return std::make_shared( - std::move(pipeline), - std::move(vertexView), - std::move(normalView), - std::move(indexBuffer), - std::move(format) - ); -} -void renderCube(gpu::Batch & batch, const BasicModel & cube) { - - batch.setPipeline(cube.pipeline); - batch.setInputFormat(cube.format); - batch.setInputBuffer(gpu::Stream::POSITION, cube.vertices); - batch.setInputBuffer(gpu::Stream::NORMAL, cube.normals); - batch.setIndexBuffer(gpu::INT16, cube.indices, 0); -// batch.drawIndexed(gpu::TRIANGLES, 12); - batch.draw(gpu::TRIANGLES, 24); -} +uint32_t toCompactColor(const glm::vec4& color); gpu::ShaderPointer makeShader(const std::string & vertexShaderSrc, const std::string & fragmentShaderSrc, const gpu::Shader::BindingSet & bindings) { auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(vertexShaderSrc)); @@ -253,6 +94,14 @@ gpu::ShaderPointer makeShader(const std::string & vertexShaderSrc, const std::st return shader; } +float getSeconds(quint64 start = 0) { + auto usecs = usecTimestampNow() - start; + auto msecs = usecs / USECS_PER_MSEC; + float seconds = (float)msecs / MSECS_PER_SECOND; + return seconds; +} + + // Creates an OpenGL window that renders a simple unlit scene using the gpu library and GeometryCache // Should eventually get refactored into something that supports multiple gpu backends. @@ -265,9 +114,9 @@ class QTestWindow : public QWindow { gpu::ContextPointer _context; gpu::PipelinePointer _pipeline; glm::mat4 _projectionMatrix; -// BasicModelPointer _cubeModel; RateCounter fps; QTime _time; + int _instanceLocation{ -1 }; protected: void renderText(); @@ -288,6 +137,7 @@ public: format.setVersion(4, 1); format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); format.setOption(QSurfaceFormat::DebugContext); + format.setSwapInterval(0); setFormat(format); @@ -301,23 +151,21 @@ public: gpu::Context::init(); _context = std::make_shared(); - auto shader = makeShader(simple_vert, simple_frag, gpu::Shader::BindingSet {}); + auto shader = makeShader(unlit_vert, unlit_frag, gpu::Shader::BindingSet{}); auto state = std::make_shared(); state->setMultisampleEnable(true); state->setDepthTest(gpu::State::DepthTest { true }); _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(shader, state)); - + _instanceLocation = _pipeline->getProgram()->getUniforms().findLocation("Instanced"); // Clear screen gpu::Batch batch; batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 1.0, 0.0, 0.5, 1.0 }); _context->render(batch); -// _cubeModel = makeCube(); - DependencyManager::set(); + DependencyManager::set(); - setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); _time.start(); @@ -327,6 +175,8 @@ public: } void draw() { + static auto startTime = usecTimestampNow(); + if (!isVisible()) { return; } @@ -342,37 +192,81 @@ public: glm::vec3 unitscale { 1.0f }; glm::vec3 up { 0.0f, 1.0f, 0.0f }; - glm::vec3 cam_pos { 1.5f * sinf(t), 0.0f, 2.0f }; -// glm::vec3 camera_focus { 5.0f * cosf(t * 0.1f), 0.0f, 0.0f }; - glm::vec3 camera_focus { 0.0f, 0.0f, 0.0f }; - glm::quat cam_rotation; - // glm::quat cam_rotation = glm::quat_cast(glm::lookAt(cam_pos, camera_focus, up)); - // cam_rotation.w = -cam_rotation.w; - // printf("cam rotation: %f %f %f %f\n", cam_rotation.x, cam_rotation.y, cam_rotation.z, cam_rotation.w); - Transform cam_transform { cam_rotation, unitscale, cam_pos }; - - batch.setViewTransform(cam_transform); + glm::vec3 camera_position { 1.5f * sinf(t), 0.0f, 1.5f * cos(t) }; + + static const vec3 camera_focus(0); + static const vec3 camera_up(0, 1, 0); + glm::mat4 camera = glm::inverse(glm::lookAt(camera_position, camera_focus, up)); + batch.setViewTransform(camera); batch.setPipeline(_pipeline); - + batch.setModelTransform(Transform()); + auto geometryCache = DependencyManager::get(); // Render grid on xz plane (not the optimal way to do things, but w/e) // Note: GeometryCache::renderGrid will *not* work, as it is apparenly unaffected by batch rotations and renders xy only - batch.setModelTransform(Transform()); + static const std::string GRID_INSTANCE = "Grid"; + static auto compactColor1 = toCompactColor(vec4{ 0.35f, 0.25f, 0.15f, 1.0f }); + static auto compactColor2 = toCompactColor(vec4{ 0.15f, 0.25f, 0.35f, 1.0f }); + auto transformBuffer = batch.getNamedBuffer(GRID_INSTANCE, 0); + auto colorBuffer = batch.getNamedBuffer(GRID_INSTANCE, 1); for (int i = 0; i < 100; ++i) { - geometryCache->renderLine(batch, { -100.0f, -1.0f, -50.0f + float(i) }, { 100.0f, -1.0f, -50.0f + float(i) }, { 0.35f, 0.25f, 0.15f, 1.0f }); + { + glm::mat4 transform = glm::translate(mat4(), vec3(0, -1, -50 + i)); + transform = glm::scale(transform, vec3(100, 1, 1)); + transformBuffer->append(transform); + colorBuffer->append(compactColor1); + } + + { + glm::mat4 transform = glm::mat4_cast(quat(vec3(0, PI / 2.0f, 0))); + transform = glm::translate(transform, vec3(0, -1, -50 + i)); + transform = glm::scale(transform, vec3(100, 1, 1)); + transformBuffer->append(transform); + colorBuffer->append(compactColor2); + } } - for (int i = 0; i < 100; ++i) { - geometryCache->renderLine(batch, { -50.0f + float(i), -1.0f, -100.0f}, { -50.0f + float(i), -1.0f, 100.0f }, { 0.15f, 0.25f, 0.35f, 1.0f }); - } - + + batch.setupNamedCalls(GRID_INSTANCE, 200, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + batch.setViewTransform(camera); + batch.setModelTransform(Transform()); + batch.setPipeline(_pipeline); + auto& xfm = data._buffers[0]; + auto& color = data._buffers[1]; + batch._glUniform1i(_instanceLocation, 1); + geometryCache->renderWireShapeInstances(batch, GeometryCache::Line, data._count, xfm, color); + batch._glUniform1i(_instanceLocation, 0); + }); + + + // Render unlit cube + sphere - geometryCache->renderUnitCube(batch); - geometryCache->renderWireCube(batch, 1.0f, { 0.4f, 0.4f, 0.7f, 1.0f }); - - batch.setModelTransform(Transform().setTranslation({ 1.5f, -0.5f, -0.5f })); - geometryCache->renderSphere(batch, 0.5f, 50, 50, { 0.8f, 0.25f, 0.25f }); + + static GeometryCache::Shape SHAPE[] = { + GeometryCache::Cube, + GeometryCache::Sphere, + GeometryCache::Tetrahedron, + GeometryCache::Icosahedron, + }; + + static auto startUsecs = usecTimestampNow(); + float seconds = getSeconds(startUsecs); + seconds /= 4.0; + int shapeIndex = ((int)seconds) % 4; + bool wire = seconds - floor(seconds) > 0.5f; + batch.setModelTransform(Transform()); + batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f); + + if (wire) { + geometryCache->renderWireShape(batch, SHAPE[shapeIndex]); + } else { + geometryCache->renderShape(batch, SHAPE[shapeIndex]); + } + batch.setModelTransform(Transform().setScale(1.05f)); + batch._glColor4f(1, 1, 1, 1); + geometryCache->renderWireCube(batch); + _context->render(batch); _qGlContext->swapBuffers(this); diff --git a/tests/gpu-test/src/simple.slf b/tests/gpu-test/src/unlit.slf similarity index 94% rename from tests/gpu-test/src/simple.slf rename to tests/gpu-test/src/unlit.slf index 31d33a73e4..350190180a 100644 --- a/tests/gpu-test/src/simple.slf +++ b/tests/gpu-test/src/unlit.slf @@ -20,7 +20,6 @@ in vec3 _normal; in vec3 _color; void main(void) { - Material material = getMaterial(); packDeferredFragment( normalize(_normal.xyz), glowIntensity, diff --git a/tests/gpu-test/src/simple.slv b/tests/gpu-test/src/unlit.slv similarity index 64% rename from tests/gpu-test/src/simple.slv rename to tests/gpu-test/src/unlit.slv index 99f404eaec..3271d0ee90 100644 --- a/tests/gpu-test/src/simple.slv +++ b/tests/gpu-test/src/unlit.slv @@ -19,6 +19,7 @@ <$declareStandardTransform()$> // the interpolated normal +uniform bool Instanced = false; out vec3 _normal; out vec3 _color; @@ -31,6 +32,12 @@ void main(void) { // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> - <$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$> + if (Instanced) { + <$transformInstancedModelToClipPos(cam, obj, inPosition, gl_Position)$> + <$transformInstancedModelToEyeDir(cam, obj, inNormal.xyz, _normal)$> + } else { + <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> + <$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$> + } + _normal = vec3(0.0, 0.0, 1.0); } \ No newline at end of file