//// GeometryCache.cpp// interface/src/renderer//// Created by Andrzej Kapolka on 6/21/13.// Copyright 2013 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 "GeometryCache.h" #include <qmath.h>#include <cmath> #include <QtCore/QThreadPool>#include <QtCore/QFileInfo>#include <QtNetwork/QNetworkReply> #include <shared/Shapes.h>#include <shared/PlatformHacks.h> #include <FSTReader.h>#include <NumericalConstants.h> #include "TextureCache.h"#include "RenderUtilsLogging.h"#include "StencilMaskPass.h"#include "FadeEffect.h" #include "gpu/StandardShaderLib.h" #include "graphics/TextureMap.h"#include "render/Args.h" #include "standardTransformPNTC_vert.h"#include "standardDrawTexture_frag.h" #include "simple_vert.h"#include "simple_textured_frag.h"#include "simple_textured_unlit_frag.h"#include "simple_fade_vert.h"#include "simple_textured_fade_frag.h"#include "simple_textured_unlit_fade_frag.h"#include "simple_opaque_web_browser_frag.h"#include "simple_transparent_web_browser_frag.h"#include "glowLine_vert.h"#include "glowLine_frag.h" #include "grid_frag.h" //#define WANT_DEBUG // @note: Originally size entity::NUM_SHAPES// As of Commit b93e91b9, render-utils no longer retains knowledge of// entity lib, and thus doesn't know about entity::NUM_SHAPES. Should// the enumerations be altered, this will need to be updated.// @see ShapeEntityItem.hstatic std::array<GeometryCache::Shape, (GeometryCache::NUM_SHAPES - 1)> MAPPING{ { GeometryCache::Triangle, GeometryCache::Quad, GeometryCache::Hexagon, GeometryCache::Octagon, GeometryCache::Circle, GeometryCache::Cube, GeometryCache::Sphere, GeometryCache::Tetrahedron, GeometryCache::Octahedron, GeometryCache::Dodecahedron, GeometryCache::Icosahedron, GeometryCache::Torus, GeometryCache::Cone, GeometryCache::Cylinder,} }; /**jsdoc* <p>{@link Entities} and {@link Overlays} may have the following geometrical shapes:</p>* <table>* <thead>* <tr><th>Value</th><th>Description</th></tr>* </thead>* <tbody>* <tr><td><code>Line</code></td><td>A 1D line oriented in 3 dimensions.</td></tr>* <tr><td><code>Triangle</code></td><td>A triangular prism.</td></tr>* <tr><td><code>Quad</code></td><td>A 2D square oriented in 3 dimensions.</tr>* <tr><td><code>Hexagon</code></td><td>A hexagonal prism.</td></tr>* <tr><td><code>Octagon</code></td><td>An octagonal prism.</td></tr>* <tr><td><code>Circle</code></td><td>A 2D circle oriented in 3 dimensions.</td></td></tr>* <tr><td><code>Cube</code></td><td>A cube.</td></tr>* <tr><td><code>Sphere</code></td><td>A sphere.</td></tr>* <tr><td><code>Tetrahedron</code></td><td>A tetrahedron.</td></tr>* <tr><td><code>Octahedron</code></td><td>An octahedron.</td></tr>* <tr><td><code>Dodecahedron</code></td><td>A dodecahedron.</td></tr>* <tr><td><code>Icosahedron</code></td><td>An icosahedron.</td></tr>* <tr><td><code>Torus</code></td><td>A torus. <em>Not implemented.</em></td></tr>* <tr><td><code>Cone</code></td><td>A cone.</td></tr>* <tr><td><code>Cylinder</code></td><td>A cylinder.</td></tr>* </tbody>* </table>* @typedef {string} Shape*/static const std::array<const char * const, GeometryCache::NUM_SHAPES> GEOCACHE_SHAPE_STRINGS{ { "Line", "Triangle", "Quad", "Hexagon", "Octagon", "Circle", "Cube", "Sphere", "Tetrahedron", "Octahedron", "Dodecahedron", "Icosahedron", "Torus", "Cone", "Cylinder" } }; const int GeometryCache::UNKNOWN_ID = -1; static const int VERTICES_PER_TRIANGLE = 3; 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 TEXCOORD4_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::XYZW }; static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT;static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT;static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT; static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normalsstatic const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3); void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) { auto geometryCache = DependencyManager::get<GeometryCache>(); const GeometryCache::Shape geometryShape = GeometryCache::getShapeForEntityShape( entityShape ); const GeometryCache::ShapeData * shapeData = geometryCache->getShapeData( geometryShape ); if (!shapeData){ //--EARLY EXIT--( data isn't ready for some reason... ) return; } const gpu::BufferView & shapeVerts = shapeData->_positionView; const gpu::BufferView::Size numItems = shapeVerts.getNumElements(); outPointList.reserve((int)numItems); QVector<glm::vec3> uniqueVerts; uniqueVerts.reserve((int)numItems); const float MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED = 1.0e-6f; //< 1mm^2 for (gpu::BufferView::Index i = 0; i < (gpu::BufferView::Index)numItems; ++i) { const int numUniquePoints = (int)uniqueVerts.size(); const geometry::Vec &curVert = shapeVerts.get<geometry::Vec>(i); bool isUniquePoint = true; for (int uniqueIndex = 0; uniqueIndex < numUniquePoints; ++uniqueIndex) { const geometry::Vec knownVert = uniqueVerts[uniqueIndex]; const float distToKnownPoint = glm::length2(knownVert - curVert); if (distToKnownPoint <= MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED) { isUniquePoint = false; break; } } if (!isUniquePoint) { //--EARLY ITERATION EXIT-- continue; } uniqueVerts.push_back(curVert); outPointList.push_back(curVert * entityExtents); }} template <size_t SIDES>std::vector<vec3> polygon() { std::vector<vec3> result; result.reserve(SIDES); double angleIncrement = 2.0 * M_PI / SIDES; for (size_t i = 0; i < SIDES; i++) { double angle = (double)i * angleIncrement; result.push_back(vec3{ cos(angle) * 0.5, 0.0, sin(angle) * 0.5 }); } return result;} void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices) { gpu::Buffer::Size offset = vertexBuffer->getSize(); vertexBuffer->append(vertices); gpu::Buffer::Size viewSize = vertices.size() * sizeof(glm::vec3); _positionView = gpu::BufferView(vertexBuffer, offset, viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT); _normalView = gpu::BufferView(vertexBuffer, offset + SHAPE_NORMALS_OFFSET, viewSize, SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT);} void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices) { gpu::Buffer::Size offset = indexBuffer->getSize(); if (!indices.empty()) { for (uint32_t i = 0; i < indices.size(); ++i) { indexBuffer->append((uint16_t)indices[i]); } } gpu::Size viewSize = indices.size() * sizeof(uint16_t); _indicesView = gpu::BufferView(indexBuffer, offset, viewSize, gpu::Element::INDEX_UINT16); offset = indexBuffer->getSize(); if (!wireIndices.empty()) { for (uint32_t i = 0; i < wireIndices.size(); ++i) { indexBuffer->append((uint16_t)wireIndices[i]); } } viewSize = wireIndices.size() * sizeof(uint16_t); _wireIndicesView = gpu::BufferView(indexBuffer, offset, viewSize, gpu::Element::INDEX_UINT16);} void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const { batch.setInputBuffer(gpu::Stream::POSITION, _positionView); batch.setInputBuffer(gpu::Stream::NORMAL, _normalView); batch.setIndexBuffer(_indicesView);} void GeometryCache::ShapeData::draw(gpu::Batch& batch) const { uint32_t numIndices = (uint32_t)_indicesView.getNumElements(); if (numIndices > 0) { setupBatch(batch); batch.drawIndexed(gpu::TRIANGLES, numIndices, 0); }} void GeometryCache::ShapeData::drawWire(gpu::Batch& batch) const { uint32_t numIndices = (uint32_t)_wireIndicesView.getNumElements(); if (numIndices > 0) { batch.setInputBuffer(gpu::Stream::POSITION, _positionView); batch.setInputBuffer(gpu::Stream::NORMAL, _normalView); batch.setIndexBuffer(_wireIndicesView); batch.drawIndexed(gpu::LINES, numIndices, 0); }} void GeometryCache::ShapeData::drawInstances(gpu::Batch& batch, size_t count) const { uint32_t numIndices = (uint32_t)_indicesView.getNumElements(); if (numIndices > 0) { setupBatch(batch); batch.drawIndexedInstanced((gpu::uint32)count, gpu::TRIANGLES, numIndices, 0); }} void GeometryCache::ShapeData::drawWireInstances(gpu::Batch& batch, size_t count) const { uint32_t numIndices = (uint32_t)_wireIndicesView.getNumElements(); if (numIndices > 0) { batch.setInputBuffer(gpu::Stream::POSITION, _positionView); batch.setInputBuffer(gpu::Stream::NORMAL, _normalView); batch.setIndexBuffer(_wireIndicesView); batch.drawIndexedInstanced((gpu::uint32)count, gpu::LINES, numIndices, 0); }} static const size_t ICOSAHEDRON_TO_SPHERE_TESSELATION_COUNT = 3; size_t GeometryCache::getShapeTriangleCount(Shape shape) { return _shapes[shape]._indicesView.getNumElements() / VERTICES_PER_TRIANGLE;} size_t GeometryCache::getSphereTriangleCount() { return getShapeTriangleCount(Sphere);} size_t GeometryCache::getCubeTriangleCount() { return getShapeTriangleCount(Cube);} using IndexPair = uint64_t;using IndexPairs = std::unordered_set<IndexPair>; static IndexPair indexToken(geometry::Index a, geometry::Index b) { if (a > b) { std::swap(a, b); } return (((IndexPair)a) << 32) | ((IndexPair)b);} template <size_t N>void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { using namespace geometry; VertexVector vertices; IndexVector solidIndices, wireIndices; IndexPairs wireSeenIndices; size_t faceCount = shape.faces.size(); size_t faceIndexCount = triangulatedFaceIndexCount<N>(); vertices.reserve(N * faceCount * 2); solidIndices.reserve(faceIndexCount * faceCount); Index baseVertex = 0; for (size_t f = 0; f < faceCount; f++) { const Face<N>& face = shape.faces[f]; // Compute the face normal vec3 faceNormal = shape.getFaceNormal(f); // Create the vertices for the face for (Index i = 0; i < N; i++) { Index originalIndex = face[i]; vertices.push_back(shape.vertices[originalIndex]); vertices.push_back(faceNormal); } // Create the wire indices for unseen edges for (Index i = 0; i < N; i++) { Index a = i; Index b = (i + 1) % N; auto token = indexToken(face[a], face[b]); if (0 == wireSeenIndices.count(token)) { wireSeenIndices.insert(token); wireIndices.push_back(a + baseVertex); wireIndices.push_back(b + baseVertex); } } // Create the solid face indices for (Index i = 0; i < N - 2; i++) { solidIndices.push_back(0 + baseVertex); solidIndices.push_back(i + 1 + baseVertex); solidIndices.push_back(i + 2 + baseVertex); } baseVertex += (Index)N; } shapeData.setupVertices(vertexBuffer, vertices); shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);} template <size_t N>void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { using namespace geometry; VertexVector vertices; vertices.reserve(shape.vertices.size() * 2); for (const auto& vertex : shape.vertices) { vertices.push_back(vertex); vertices.push_back(vertex); } IndexVector solidIndices, wireIndices; IndexPairs wireSeenIndices; size_t faceCount = shape.faces.size(); size_t faceIndexCount = triangulatedFaceIndexCount<N>(); solidIndices.reserve(faceIndexCount * faceCount); Index baseVertex = 0; for (size_t f = 0; f < faceCount; f++) { const Face<N>& face = shape.faces[f]; // Create the wire indices for unseen edges for (Index i = 0; i < N; i++) { Index a = face[i]; Index b = face[(i + 1) % N]; auto token = indexToken(a, b); if (0 == wireSeenIndices.count(token)) { wireSeenIndices.insert(token); wireIndices.push_back(a + baseVertex); wireIndices.push_back(b + baseVertex); } } // Create the solid face indices for (Index i = 0; i < N - 2; i++) { solidIndices.push_back(face[i] + baseVertex); solidIndices.push_back(face[i + 1] + baseVertex); solidIndices.push_back(face[i + 2] + baseVertex); } } shapeData.setupVertices(vertexBuffer, vertices); shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);} template <uint32_t N>void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) { using namespace geometry; VertexVector vertices; IndexVector solidIndices, wireIndices; // Top (if not conical) and bottom faces std::vector<vec3> shape = polygon<N>(); if (isConical) { for (uint32_t i = 0; i < N; i++) { vertices.push_back(vec3(0.0f, 0.5f, 0.0f)); vertices.push_back(vec3(0.0f, 1.0f, 0.0f)); } } else { for (const vec3& v : shape) { vertices.push_back(vec3(v.x, 0.5f, v.z)); vertices.push_back(vec3(0.0f, 1.0f, 0.0f)); } } for (const vec3& v : shape) { vertices.push_back(vec3(v.x, -0.5f, v.z)); vertices.push_back(vec3(0.0f, -1.0f, 0.0f)); } Index baseVertex = 0; for (uint32_t i = 2; i < N; i++) { solidIndices.push_back(baseVertex + 0); solidIndices.push_back(baseVertex + i); solidIndices.push_back(baseVertex + i - 1); solidIndices.push_back(baseVertex + N); solidIndices.push_back(baseVertex + i + N - 1); solidIndices.push_back(baseVertex + i + N); } for (uint32_t i = 1; i <= N; i++) { wireIndices.push_back(baseVertex + (i % N)); wireIndices.push_back(baseVertex + i - 1); wireIndices.push_back(baseVertex + (i % N) + N); wireIndices.push_back(baseVertex + (i - 1) + N); } // Now do the sides baseVertex += 2 * N; for (uint32_t i = 0; i < N; i++) { vec3 left = shape[i]; vec3 right = shape[(i + 1) % N]; vec3 normal = glm::normalize(left + right); vec3 topLeft = (isConical ? vec3(0.0f, 0.5f, 0.0f) : vec3(left.x, 0.5f, left.z)); vec3 topRight = (isConical ? vec3(0.0f, 0.5f, 0.0f) : vec3(right.x, 0.5f, right.z)); vec3 bottomLeft = vec3(left.x, -0.5f, left.z); vec3 bottomRight = vec3(right.x, -0.5f, right.z); vertices.push_back(topLeft); vertices.push_back(normal); vertices.push_back(bottomLeft); vertices.push_back(normal); vertices.push_back(topRight); vertices.push_back(normal); vertices.push_back(bottomRight); vertices.push_back(normal); solidIndices.push_back(baseVertex + 0); solidIndices.push_back(baseVertex + 2); solidIndices.push_back(baseVertex + 1); solidIndices.push_back(baseVertex + 1); solidIndices.push_back(baseVertex + 2); solidIndices.push_back(baseVertex + 3); wireIndices.push_back(baseVertex + 0); wireIndices.push_back(baseVertex + 1); wireIndices.push_back(baseVertex + 3); wireIndices.push_back(baseVertex + 2); baseVertex += 4; } shapeData.setupVertices(vertexBuffer, vertices); shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);} void drawCircle(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { // Draw a circle with radius 1/4th the size of the bounding box using namespace geometry; VertexVector vertices; IndexVector solidIndices, wireIndices; const int NUM_CIRCLE_VERTICES = 64; std::vector<vec3> shape = polygon<NUM_CIRCLE_VERTICES>(); for (const vec3& v : shape) { vertices.push_back(vec3(v.x, 0.0f, v.z)); vertices.push_back(vec3(0.0f, 0.0f, 0.0f)); } Index baseVertex = 0; for (uint32_t i = 2; i < NUM_CIRCLE_VERTICES; i++) { solidIndices.push_back(baseVertex + 0); solidIndices.push_back(baseVertex + i); solidIndices.push_back(baseVertex + i - 1); solidIndices.push_back(baseVertex + NUM_CIRCLE_VERTICES); solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES - 1); solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES); } for (uint32_t i = 1; i <= NUM_CIRCLE_VERTICES; i++) { wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES)); wireIndices.push_back(baseVertex + i - 1); wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES) + NUM_CIRCLE_VERTICES); wireIndices.push_back(baseVertex + (i - 1) + NUM_CIRCLE_VERTICES); } shapeData.setupVertices(vertexBuffer, vertices); shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);}Lines 1–500 of 2455. Load more
// // GeometryCache.cpp // interface/src/renderer // // Created by Andrzej Kapolka on 6/21/13. // Copyright 2013 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 "GeometryCache.h" #include <qmath.h> #include <cmath> #include <QtCore/QThreadPool> #include <QtCore/QFileInfo> #include <QtNetwork/QNetworkReply> #include <shared/Shapes.h> #include <shared/PlatformHacks.h> #include <FSTReader.h> #include <NumericalConstants.h> #include "TextureCache.h" #include "RenderUtilsLogging.h" #include "StencilMaskPass.h" #include "FadeEffect.h" #include "gpu/StandardShaderLib.h" #include "graphics/TextureMap.h" #include "render/Args.h" #include "standardTransformPNTC_vert.h" #include "standardDrawTexture_frag.h" #include "simple_vert.h" #include "simple_textured_frag.h" #include "simple_textured_unlit_frag.h" #include "simple_fade_vert.h" #include "simple_textured_fade_frag.h" #include "simple_textured_unlit_fade_frag.h" #include "simple_opaque_web_browser_frag.h" #include "simple_transparent_web_browser_frag.h" #include "glowLine_vert.h" #include "glowLine_frag.h" #include "grid_frag.h" //#define WANT_DEBUG // @note: Originally size entity::NUM_SHAPES // As of Commit b93e91b9, render-utils no longer retains knowledge of // entity lib, and thus doesn't know about entity::NUM_SHAPES. Should // the enumerations be altered, this will need to be updated. // @see ShapeEntityItem.h static std::array<GeometryCache::Shape, (GeometryCache::NUM_SHAPES - 1)> MAPPING{ { GeometryCache::Triangle, GeometryCache::Quad, GeometryCache::Hexagon, GeometryCache::Octagon, GeometryCache::Circle, GeometryCache::Cube, GeometryCache::Sphere, GeometryCache::Tetrahedron, GeometryCache::Octahedron, GeometryCache::Dodecahedron, GeometryCache::Icosahedron, GeometryCache::Torus, GeometryCache::Cone, GeometryCache::Cylinder, } }; /**jsdoc * <p>{@link Entities} and {@link Overlays} may have the following geometrical shapes:</p> * <table> * <thead> * <tr><th>Value</th><th>Description</th></tr> * </thead> * <tbody> * <tr><td><code>Line</code></td><td>A 1D line oriented in 3 dimensions.</td></tr> * <tr><td><code>Triangle</code></td><td>A triangular prism.</td></tr> * <tr><td><code>Quad</code></td><td>A 2D square oriented in 3 dimensions.</tr> * <tr><td><code>Hexagon</code></td><td>A hexagonal prism.</td></tr> * <tr><td><code>Octagon</code></td><td>An octagonal prism.</td></tr> * <tr><td><code>Circle</code></td><td>A 2D circle oriented in 3 dimensions.</td></td></tr> * <tr><td><code>Cube</code></td><td>A cube.</td></tr> * <tr><td><code>Sphere</code></td><td>A sphere.</td></tr> * <tr><td><code>Tetrahedron</code></td><td>A tetrahedron.</td></tr> * <tr><td><code>Octahedron</code></td><td>An octahedron.</td></tr> * <tr><td><code>Dodecahedron</code></td><td>A dodecahedron.</td></tr> * <tr><td><code>Icosahedron</code></td><td>An icosahedron.</td></tr> * <tr><td><code>Torus</code></td><td>A torus. <em>Not implemented.</em></td></tr> * <tr><td><code>Cone</code></td><td>A cone.</td></tr> * <tr><td><code>Cylinder</code></td><td>A cylinder.</td></tr> * </tbody> * </table> * @typedef {string} Shape */ static const std::array<const char * const, GeometryCache::NUM_SHAPES> GEOCACHE_SHAPE_STRINGS{ { "Line", "Triangle", "Quad", "Hexagon", "Octagon", "Circle", "Cube", "Sphere", "Tetrahedron", "Octahedron", "Dodecahedron", "Icosahedron", "Torus", "Cone", "Cylinder" } }; const int GeometryCache::UNKNOWN_ID = -1; static const int VERTICES_PER_TRIANGLE = 3; 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 TEXCOORD4_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::XYZW }; static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT; static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT; static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_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::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) { auto geometryCache = DependencyManager::get<GeometryCache>(); const GeometryCache::Shape geometryShape = GeometryCache::getShapeForEntityShape( entityShape ); const GeometryCache::ShapeData * shapeData = geometryCache->getShapeData( geometryShape ); if (!shapeData){ //--EARLY EXIT--( data isn't ready for some reason... ) return; } const gpu::BufferView & shapeVerts = shapeData->_positionView; const gpu::BufferView::Size numItems = shapeVerts.getNumElements(); outPointList.reserve((int)numItems); QVector<glm::vec3> uniqueVerts; uniqueVerts.reserve((int)numItems); const float MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED = 1.0e-6f; //< 1mm^2 for (gpu::BufferView::Index i = 0; i < (gpu::BufferView::Index)numItems; ++i) { const int numUniquePoints = (int)uniqueVerts.size(); const geometry::Vec &curVert = shapeVerts.get<geometry::Vec>(i); bool isUniquePoint = true; for (int uniqueIndex = 0; uniqueIndex < numUniquePoints; ++uniqueIndex) { const geometry::Vec knownVert = uniqueVerts[uniqueIndex]; const float distToKnownPoint = glm::length2(knownVert - curVert); if (distToKnownPoint <= MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED) { isUniquePoint = false; break; } } if (!isUniquePoint) { //--EARLY ITERATION EXIT-- continue; } uniqueVerts.push_back(curVert); outPointList.push_back(curVert * entityExtents); } } template <size_t SIDES> std::vector<vec3> polygon() { std::vector<vec3> result; result.reserve(SIDES); double angleIncrement = 2.0 * M_PI / SIDES; for (size_t i = 0; i < SIDES; i++) { double angle = (double)i * angleIncrement; result.push_back(vec3{ cos(angle) * 0.5, 0.0, sin(angle) * 0.5 }); } return result; } void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices) { gpu::Buffer::Size offset = vertexBuffer->getSize(); vertexBuffer->append(vertices); gpu::Buffer::Size viewSize = vertices.size() * sizeof(glm::vec3); _positionView = gpu::BufferView(vertexBuffer, offset, viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT); _normalView = gpu::BufferView(vertexBuffer, offset + SHAPE_NORMALS_OFFSET, viewSize, SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT); } void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices) { gpu::Buffer::Size offset = indexBuffer->getSize(); if (!indices.empty()) { for (uint32_t i = 0; i < indices.size(); ++i) { indexBuffer->append((uint16_t)indices[i]); } } gpu::Size viewSize = indices.size() * sizeof(uint16_t); _indicesView = gpu::BufferView(indexBuffer, offset, viewSize, gpu::Element::INDEX_UINT16); offset = indexBuffer->getSize(); if (!wireIndices.empty()) { for (uint32_t i = 0; i < wireIndices.size(); ++i) { indexBuffer->append((uint16_t)wireIndices[i]); } } viewSize = wireIndices.size() * sizeof(uint16_t); _wireIndicesView = gpu::BufferView(indexBuffer, offset, viewSize, gpu::Element::INDEX_UINT16); } void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const { batch.setInputBuffer(gpu::Stream::POSITION, _positionView); batch.setInputBuffer(gpu::Stream::NORMAL, _normalView); batch.setIndexBuffer(_indicesView); } void GeometryCache::ShapeData::draw(gpu::Batch& batch) const { uint32_t numIndices = (uint32_t)_indicesView.getNumElements(); if (numIndices > 0) { setupBatch(batch); batch.drawIndexed(gpu::TRIANGLES, numIndices, 0); } } void GeometryCache::ShapeData::drawWire(gpu::Batch& batch) const { uint32_t numIndices = (uint32_t)_wireIndicesView.getNumElements(); if (numIndices > 0) { batch.setInputBuffer(gpu::Stream::POSITION, _positionView); batch.setInputBuffer(gpu::Stream::NORMAL, _normalView); batch.setIndexBuffer(_wireIndicesView); batch.drawIndexed(gpu::LINES, numIndices, 0); } } void GeometryCache::ShapeData::drawInstances(gpu::Batch& batch, size_t count) const { uint32_t numIndices = (uint32_t)_indicesView.getNumElements(); if (numIndices > 0) { setupBatch(batch); batch.drawIndexedInstanced((gpu::uint32)count, gpu::TRIANGLES, numIndices, 0); } } void GeometryCache::ShapeData::drawWireInstances(gpu::Batch& batch, size_t count) const { uint32_t numIndices = (uint32_t)_wireIndicesView.getNumElements(); if (numIndices > 0) { batch.setInputBuffer(gpu::Stream::POSITION, _positionView); batch.setInputBuffer(gpu::Stream::NORMAL, _normalView); batch.setIndexBuffer(_wireIndicesView); batch.drawIndexedInstanced((gpu::uint32)count, gpu::LINES, numIndices, 0); } } static const size_t ICOSAHEDRON_TO_SPHERE_TESSELATION_COUNT = 3; size_t GeometryCache::getShapeTriangleCount(Shape shape) { return _shapes[shape]._indicesView.getNumElements() / VERTICES_PER_TRIANGLE; } size_t GeometryCache::getSphereTriangleCount() { return getShapeTriangleCount(Sphere); } size_t GeometryCache::getCubeTriangleCount() { return getShapeTriangleCount(Cube); } using IndexPair = uint64_t; using IndexPairs = std::unordered_set<IndexPair>; static IndexPair indexToken(geometry::Index a, geometry::Index b) { if (a > b) { std::swap(a, b); } return (((IndexPair)a) << 32) | ((IndexPair)b); } template <size_t N> void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { using namespace geometry; VertexVector vertices; IndexVector solidIndices, wireIndices; IndexPairs wireSeenIndices; size_t faceCount = shape.faces.size(); size_t faceIndexCount = triangulatedFaceIndexCount<N>(); vertices.reserve(N * faceCount * 2); solidIndices.reserve(faceIndexCount * faceCount); Index baseVertex = 0; for (size_t f = 0; f < faceCount; f++) { const Face<N>& face = shape.faces[f]; // Compute the face normal vec3 faceNormal = shape.getFaceNormal(f); // Create the vertices for the face for (Index i = 0; i < N; i++) { Index originalIndex = face[i]; vertices.push_back(shape.vertices[originalIndex]); vertices.push_back(faceNormal); } // Create the wire indices for unseen edges for (Index i = 0; i < N; i++) { Index a = i; Index b = (i + 1) % N; auto token = indexToken(face[a], face[b]); if (0 == wireSeenIndices.count(token)) { wireSeenIndices.insert(token); wireIndices.push_back(a + baseVertex); wireIndices.push_back(b + baseVertex); } } // Create the solid face indices for (Index i = 0; i < N - 2; i++) { solidIndices.push_back(0 + baseVertex); solidIndices.push_back(i + 1 + baseVertex); solidIndices.push_back(i + 2 + baseVertex); } baseVertex += (Index)N; } shapeData.setupVertices(vertexBuffer, vertices); shapeData.setupIndices(indexBuffer, solidIndices, wireIndices); } template <size_t N> void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { using namespace geometry; VertexVector vertices; vertices.reserve(shape.vertices.size() * 2); for (const auto& vertex : shape.vertices) { vertices.push_back(vertex); vertices.push_back(vertex); } IndexVector solidIndices, wireIndices; IndexPairs wireSeenIndices; size_t faceCount = shape.faces.size(); size_t faceIndexCount = triangulatedFaceIndexCount<N>(); solidIndices.reserve(faceIndexCount * faceCount); Index baseVertex = 0; for (size_t f = 0; f < faceCount; f++) { const Face<N>& face = shape.faces[f]; // Create the wire indices for unseen edges for (Index i = 0; i < N; i++) { Index a = face[i]; Index b = face[(i + 1) % N]; auto token = indexToken(a, b); if (0 == wireSeenIndices.count(token)) { wireSeenIndices.insert(token); wireIndices.push_back(a + baseVertex); wireIndices.push_back(b + baseVertex); } } // Create the solid face indices for (Index i = 0; i < N - 2; i++) { solidIndices.push_back(face[i] + baseVertex); solidIndices.push_back(face[i + 1] + baseVertex); solidIndices.push_back(face[i + 2] + baseVertex); } } shapeData.setupVertices(vertexBuffer, vertices); shapeData.setupIndices(indexBuffer, solidIndices, wireIndices); } template <uint32_t N> void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) { using namespace geometry; VertexVector vertices; IndexVector solidIndices, wireIndices; // Top (if not conical) and bottom faces std::vector<vec3> shape = polygon<N>(); if (isConical) { for (uint32_t i = 0; i < N; i++) { vertices.push_back(vec3(0.0f, 0.5f, 0.0f)); vertices.push_back(vec3(0.0f, 1.0f, 0.0f)); } } else { for (const vec3& v : shape) { vertices.push_back(vec3(v.x, 0.5f, v.z)); vertices.push_back(vec3(0.0f, 1.0f, 0.0f)); } } for (const vec3& v : shape) { vertices.push_back(vec3(v.x, -0.5f, v.z)); vertices.push_back(vec3(0.0f, -1.0f, 0.0f)); } Index baseVertex = 0; for (uint32_t i = 2; i < N; i++) { solidIndices.push_back(baseVertex + 0); solidIndices.push_back(baseVertex + i); solidIndices.push_back(baseVertex + i - 1); solidIndices.push_back(baseVertex + N); solidIndices.push_back(baseVertex + i + N - 1); solidIndices.push_back(baseVertex + i + N); } for (uint32_t i = 1; i <= N; i++) { wireIndices.push_back(baseVertex + (i % N)); wireIndices.push_back(baseVertex + i - 1); wireIndices.push_back(baseVertex + (i % N) + N); wireIndices.push_back(baseVertex + (i - 1) + N); } // Now do the sides baseVertex += 2 * N; for (uint32_t i = 0; i < N; i++) { vec3 left = shape[i]; vec3 right = shape[(i + 1) % N]; vec3 normal = glm::normalize(left + right); vec3 topLeft = (isConical ? vec3(0.0f, 0.5f, 0.0f) : vec3(left.x, 0.5f, left.z)); vec3 topRight = (isConical ? vec3(0.0f, 0.5f, 0.0f) : vec3(right.x, 0.5f, right.z)); vec3 bottomLeft = vec3(left.x, -0.5f, left.z); vec3 bottomRight = vec3(right.x, -0.5f, right.z); vertices.push_back(topLeft); vertices.push_back(normal); vertices.push_back(bottomLeft); vertices.push_back(normal); vertices.push_back(topRight); vertices.push_back(normal); vertices.push_back(bottomRight); vertices.push_back(normal); solidIndices.push_back(baseVertex + 0); solidIndices.push_back(baseVertex + 2); solidIndices.push_back(baseVertex + 1); solidIndices.push_back(baseVertex + 1); solidIndices.push_back(baseVertex + 2); solidIndices.push_back(baseVertex + 3); wireIndices.push_back(baseVertex + 0); wireIndices.push_back(baseVertex + 1); wireIndices.push_back(baseVertex + 3); wireIndices.push_back(baseVertex + 2); baseVertex += 4; } shapeData.setupVertices(vertexBuffer, vertices); shapeData.setupIndices(indexBuffer, solidIndices, wireIndices); } void drawCircle(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { // Draw a circle with radius 1/4th the size of the bounding box using namespace geometry; VertexVector vertices; IndexVector solidIndices, wireIndices; const int NUM_CIRCLE_VERTICES = 64; std::vector<vec3> shape = polygon<NUM_CIRCLE_VERTICES>(); for (const vec3& v : shape) { vertices.push_back(vec3(v.x, 0.0f, v.z)); vertices.push_back(vec3(0.0f, 0.0f, 0.0f)); } Index baseVertex = 0; for (uint32_t i = 2; i < NUM_CIRCLE_VERTICES; i++) { solidIndices.push_back(baseVertex + 0); solidIndices.push_back(baseVertex + i); solidIndices.push_back(baseVertex + i - 1); solidIndices.push_back(baseVertex + NUM_CIRCLE_VERTICES); solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES - 1); solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES); } for (uint32_t i = 1; i <= NUM_CIRCLE_VERTICES; i++) { wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES)); wireIndices.push_back(baseVertex + i - 1); wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES) + NUM_CIRCLE_VERTICES); wireIndices.push_back(baseVertex + (i - 1) + NUM_CIRCLE_VERTICES); } shapeData.setupVertices(vertexBuffer, vertices); shapeData.setupIndices(indexBuffer, solidIndices, wireIndices); }