1982 lines · 79.7 KB · C++
RawDownload
////  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 <FSTReader.h>#include <NumericalConstants.h>#include <shared/Shapes.h> #include "TextureCache.h"#include "RenderUtilsLogging.h" #include "gpu/StandardShaderLib.h" #include "model/TextureMap.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_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 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 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 normalsstatic const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);static const gpu::Type SHAPE_INDEX_TYPE = gpu::UINT32;static const uint SHAPE_INDEX_SIZE = sizeof(gpu::uint32); 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) {    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 geometry::IndexVector& indices, const geometry::IndexVector& wireIndices) {    _indices = indexBuffer;    if (!indices.empty()) {        _indexOffset = indexBuffer->getSize() / SHAPE_INDEX_SIZE;        _indexCount = indices.size();        indexBuffer->append(indices);    }     if (!wireIndices.empty()) {        _wireIndexOffset = indexBuffer->getSize() / SHAPE_INDEX_SIZE;        _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);    batch.setIndexBuffer(SHAPE_INDEX_TYPE, _indices, 0);} void GeometryCache::ShapeData::draw(gpu::Batch& batch) const {    if (_indexCount) {        setupBatch(batch);        batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)_indexCount, (gpu::uint32)_indexOffset);    }} void GeometryCache::ShapeData::drawWire(gpu::Batch& batch) const {    if (_wireIndexCount) {        setupBatch(batch);        batch.drawIndexed(gpu::LINES, (gpu::uint32)_wireIndexCount, (gpu::uint32)_wireIndexOffset);    }} void GeometryCache::ShapeData::drawInstances(gpu::Batch& batch, size_t count) const {    if (_indexCount) {        setupBatch(batch);        batch.drawIndexedInstanced((gpu::uint32)count, gpu::TRIANGLES, (gpu::uint32)_indexCount, (gpu::uint32)_indexOffset);    }} void GeometryCache::ShapeData::drawWireInstances(gpu::Batch& batch, size_t count) const {    if (_wireIndexCount) {        setupBatch(batch);        batch.drawIndexedInstanced((gpu::uint32)count, gpu::LINES, (gpu::uint32)_wireIndexCount, (gpu::uint32)_wireIndexOffset);    }} static const size_t ICOSAHEDRON_TO_SPHERE_TESSELATION_COUNT = 3; size_t GeometryCache::getShapeTriangleCount(Shape shape) {    return _shapes[shape]._indexCount / 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;    Index baseVertex = (Index)(vertexBuffer->getSize() / SHAPE_VERTEX_STRIDE);    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);     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;    Index baseVertex = (Index)(vertexBuffer->getSize() / SHAPE_VERTEX_STRIDE);     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);     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) {    using namespace geometry;    Index baseVertex = (Index)(vertexBuffer->getSize() / SHAPE_VERTEX_STRIDE);    VertexVector vertices;    IndexVector solidIndices, wireIndices;     // Top and bottom faces    std::vector<vec3> shape = polygon<N>();    for (const vec3& v : shape) {        vertices.push_back(vec3(v.x, 0.5f, v.z));        vertices.push_back(vec3(0, 1, 0));    }    for (const vec3& v : shape) {        vertices.push_back(vec3(v.x, -0.5f, v.z));        vertices.push_back(vec3(0, -1, 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 = vec3(left.x, 0.5f, left.z);        vec3 topRight = 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);} // 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 shadingvoid GeometryCache::buildShapes() {    using namespace geometry;    auto vertexBuffer = std::make_shared<gpu::Buffer>();    auto indexBuffer = std::make_shared<gpu::Buffer>();    // Cube     setupFlatShape(_shapes[Cube], geometry::cube(), _shapeVertices, _shapeIndices);    // Tetrahedron    setupFlatShape(_shapes[Tetrahedron], geometry::tetrahedron(), _shapeVertices, _shapeIndices);    // Icosahedron    setupFlatShape(_shapes[Icosahedron], geometry::icosahedron(), _shapeVertices, _shapeIndices);    // Octahedron    setupFlatShape(_shapes[Octahedron], geometry::octahedron(), _shapeVertices, _shapeIndices);    // Dodecahedron    setupFlatShape(_shapes[Dodecahedron], geometry::dodecahedron(), _shapeVertices, _shapeIndices);     // Sphere    // FIXME this uses way more vertices than required.  Should find a way to calculate the indices    // using shared vertices for better vertex caching    auto sphere = geometry::tesselate(geometry::icosahedron(), ICOSAHEDRON_TO_SPHERE_TESSELATION_COUNT);    sphere.fitDimension(1.0f);    setupSmoothShape(_shapes[Sphere], sphere, _shapeVertices, _shapeIndices);     // Line    {        Index baseVertex = (Index)(_shapeVertices->getSize() / SHAPE_VERTEX_STRIDE);        ShapeData& shapeData = _shapes[Line];        shapeData.setupVertices(_shapeVertices, VertexVector {            vec3(-0.5, 0, 0), vec3(-0.5f, 0, 0),            vec3(0.5f, 0, 0), vec3(0.5f, 0, 0)        });        IndexVector wireIndices;        // Only two indices        wireIndices.push_back(0 + baseVertex);        wireIndices.push_back(1 + baseVertex);        shapeData.setupIndices(_shapeIndices, IndexVector(), wireIndices);    }     // Not implememented yet:     //Triangle,    extrudePolygon<3>(_shapes[Triangle], _shapeVertices, _shapeIndices);    //Hexagon,    extrudePolygon<6>(_shapes[Hexagon], _shapeVertices, _shapeIndices);    //Octagon,    extrudePolygon<8>(_shapes[Octagon], _shapeVertices, _shapeIndices);     //Quad,    //Circle,    //Torus,    //Cone,    //Cylinder,} gpu::Stream::FormatPointer& getSolidStreamFormat() {    if (!SOLID_STREAM_FORMAT) {        SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 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<gpu::Stream::Format>(); // 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);    }    return INSTANCED_SOLID_STREAM_FORMAT;} render::ShapePipelinePointer GeometryCache::_simpleOpaquePipeline;render::ShapePipelinePointer GeometryCache::_simpleTransparentPipeline;render::ShapePipelinePointer GeometryCache::_simpleWirePipeline; GeometryCache::GeometryCache() :_nextID(0) {    buildShapes();    GeometryCache::_simpleOpaquePipeline =        std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, false), nullptr,            [](const render::ShapePipeline&, gpu::Batch& batch) {                // Set the defaults needed for a simple program                batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,                    DependencyManager::get<TextureCache>()->getWhiteTexture());                batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,                    DependencyManager::get<TextureCache>()->getNormalFittingTexture());            }        );    GeometryCache::_simpleTransparentPipeline =        std::make_shared<render::ShapePipeline>(getSimplePipeline(false, true, true, false), nullptr,            [](const render::ShapePipeline&, gpu::Batch& batch) {                // Set the defaults needed for a simple program                batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,                    DependencyManager::get<TextureCache>()->getWhiteTexture());                batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,                    DependencyManager::get<TextureCache>()->getNormalFittingTexture());            }        );    GeometryCache::_simpleWirePipeline =        std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, true), nullptr,            [](const render::ShapePipeline&, gpu::Batch& batch) {});} GeometryCache::~GeometryCache() {#ifdef WANT_DEBUG    qCDebug(renderutils) << "GeometryCache::~GeometryCache()... ";    qCDebug(renderutils) << "    _registeredLine3DVBOs.size():" << _registeredLine3DVBOs.size();    qCDebug(renderutils) << "    _line3DVBOs.size():" << _line3DVBOs.size();    qCDebug(renderutils) << "    BatchItemDetails... population:" << GeometryCache::BatchItemDetails::population;#endif //def WANT_DEBUG} void GeometryCache::releaseID(int id) {    _registeredQuad3DTextures.remove(id);    _lastRegisteredQuad2DTexture.remove(id);    _registeredQuad2DTextures.remove(id);    _lastRegisteredQuad3D.remove(id);    _registeredQuad3D.remove(id);     _lastRegisteredQuad2D.remove(id);    _registeredQuad2D.remove(id);     _lastRegisteredBevelRects.remove(id);    _registeredBevelRects.remove(id);     _lastRegisteredLine3D.remove(id);    _registeredLine3DVBOs.remove(id);     _lastRegisteredLine2D.remove(id);    _registeredLine2DVBOs.remove(id);     _registeredVertices.remove(id);     _lastRegisteredDashedLines.remove(id);    _registeredDashedLines.remove(id);     _lastRegisteredGridBuffer.remove(id);    _registeredGridBuffers.remove(id);} void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer) {    gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT);    batch.setInputBuffer(gpu::Stream::COLOR, colorView);} 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& colorBuffer) {    batch.setInputFormat(getInstancedSolidStreamFormat());    setupBatchInstance(batch, colorBuffer);    _shapes[shape].drawInstances(batch, count);} void GeometryCache::renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer) {    batch.setInputFormat(getInstancedSolidStreamFormat());    setupBatchInstance(batch, colorBuffer);    _shapes[shape].drawWireInstances(batch, count);} void GeometryCache::renderCube(gpu::Batch& batch) {    renderShape(batch, Cube);}

Lines 1–500 of 1982.