2501 lines · 103.5 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 <shared/Shapes.h>#include <shared/PlatformHacks.h> #include <FSTReader.h>#include <NumericalConstants.h>#include <graphics/TextureMap.h>#include <graphics/BufferViewHelpers.h>#include <render/Args.h>#include <shaders/Shaders.h>#include <graphics/ShaderConstants.h> #include "render-utils/ShaderConstants.h"#include "TextureCache.h"#include "RenderUtilsLogging.h"#include "StencilMaskPass.h"#include "FadeEffect.h"   #include "DeferredLightingEffect.h" namespace gr {    using graphics::slot::texture::Texture;    using graphics::slot::buffer::Buffer;} namespace ru {    using render_utils::slot::texture::Texture;    using render_utils::slot::buffer::Buffer;} #if defined(USE_GLES)static bool DISABLE_DEFERRED = true;#elsestatic const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" };static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);#endif //#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,} }; 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 TEXCOORD0_ELEMENT { gpu::VEC2, gpu::FLOAT, gpu::UV };static const gpu::Element TANGENT_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 gpu::Stream::FormatPointer WIRE_STREAM_FORMAT;static gpu::Stream::FormatPointer INSTANCED_WIRE_STREAM_FORMAT;static gpu::Stream::FormatPointer INSTANCED_WIRE_FADE_STREAM_FORMAT; static const uint SHAPE_VERTEX_STRIDE = sizeof(GeometryCache::ShapeVertex); // position, normal, texcoords, tangentstatic const uint SHAPE_NORMALS_OFFSET = offsetof(GeometryCache::ShapeVertex, normal);static const uint SHAPE_TEXCOORD0_OFFSET = offsetof(GeometryCache::ShapeVertex, uv);static const uint SHAPE_TANGENT_OFFSET = offsetof(GeometryCache::ShapeVertex, tangent); 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 std::vector<ShapeVertex>& vertices) {    gpu::Buffer::Size offset = vertexBuffer->getSize();    vertexBuffer->append(vertices);     gpu::Buffer::Size viewSize = vertices.size() * sizeof(ShapeVertex);     _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);    _texCoordView = gpu::BufferView(vertexBuffer, offset + SHAPE_TEXCOORD0_OFFSET,        viewSize, SHAPE_VERTEX_STRIDE, TEXCOORD0_ELEMENT);    _tangentView = gpu::BufferView(vertexBuffer, offset + SHAPE_TANGENT_OFFSET,        viewSize, SHAPE_VERTEX_STRIDE, TANGENT_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.setInputBuffer(gpu::Stream::TEXCOORD, _texCoordView);    batch.setInputBuffer(gpu::Stream::TANGENT, _tangentView);    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;    std::vector<GeometryCache::ShapeVertex> vertices;    IndexVector solidIndices, wireIndices;    IndexPairs wireSeenIndices;     size_t faceCount = shape.faces.size();    size_t faceIndexCount = triangulatedFaceIndexCount<N>();     vertices.reserve(N * faceCount);    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);         // Find two points on this face with the same Y tex coords, and find the vector going from the one with the smaller X tex coord to the one with the larger X tex coord        vec3 faceTangent = vec3(0.0f);        Index i1 = 0;        Index i2 = i1 + 1;        while (i1 < N) {            if (shape.texCoords[f * N + i1].y == shape.texCoords[f * N + i2].y) {                break;            }            if (i2 == N - 1) {                i1++;                i2 = i1 + 1;            } else {                i2++;            }        }         if (i1 < N && i2 < N) {            vec3 p1 = shape.vertices[face[i1]];            vec3 p2 = shape.vertices[face[i2]];            faceTangent = glm::normalize(p1 - p2);            if (shape.texCoords[f * N + i1].x < shape.texCoords[f * N + i2].x) {                faceTangent *= -1.0f;            }        }         // Create the vertices for the face        for (Index i = 0; i < N; i++) {            Index originalIndex = face[i];            vertices.emplace_back(shape.vertices[originalIndex], faceNormal, shape.texCoords[f * N + i], faceTangent);        }         // 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);} vec2 calculateSphereTexCoord(const vec3& vertex) {    float u = 1.0f - (std::atan2(-vertex.z, -vertex.x) / ((float)M_PI) + 1.0f) * 0.5f;    if (vertex.y == 1.0f || vertex.y == -1.0f) {        // Remember points at the top so we don't treat them as being along the seam        u = NAN;    }    float v = 0.5f - std::asin(vertex.y) / (float)M_PI;    return vec2(u, v);} const float M_PI_TIMES_2 = 2.0f * (float)M_PI; vec3 calculateSphereTangent(float u) {    float phi = u * M_PI_TIMES_2;    return -glm::normalize(glm::vec3(glm::sin(phi), 0.0f, glm::cos(phi)));} template <size_t N>void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {    using namespace geometry;     std::vector<GeometryCache::ShapeVertex> vertices;    vertices.reserve(shape.vertices.size());    for (const auto& vertex : shape.vertices) {        // We'll fill in the correct tangents later, once we correct the UVs        vertices.emplace_back(vertex, vertex, calculateSphereTexCoord(vertex), vec3(0.0f));    }     // We need to fix up the sphere's UVs because it's actually a tesselated icosahedron.  See http://mft-dev.dk/uv-mapping-sphere/    size_t faceCount = shape.faces.size();    for (size_t f = 0; f < faceCount; f++) {        // Fix zipper        {            float& u1 = vertices[shape.faces[f][0]].uv.x;            float& u2 = vertices[shape.faces[f][1]].uv.x;            float& u3 = vertices[shape.faces[f][2]].uv.x;             if (glm::isnan(u1)) {                u1 = (u2 + u3) / 2.0f;            }            if (glm::isnan(u2)) {                u2 = (u1 + u3) / 2.0f;            }            if (glm::isnan(u3)) {                u3 = (u1 + u2) / 2.0f;            }             const float U_THRESHOLD = 0.25f;            float max = glm::max(u1, glm::max(u2, u3));            float min = glm::min(u1, glm::min(u2, u3));             if (max - min > U_THRESHOLD) {                if (u1 < U_THRESHOLD) {                    u1 += 1.0f;                }                if (u2 < U_THRESHOLD) {                    u2 += 1.0f;                }                if (u3 < U_THRESHOLD) {                    u3 += 1.0f;                }            }        }         // Fix swirling at poles        for (Index i = 0; i < N; i++) {            Index originalIndex = shape.faces[f][i];            if (shape.vertices[originalIndex].y == 1.0f || shape.vertices[originalIndex].y == -1.0f) {                float uSum = 0.0f;                for (Index i2 = 1; i2 <= N - 1; i2++) {                    float u = vertices[shape.faces[f][(i + i2) % N]].uv.x;                    uSum += u;                }                uSum /= (float)(N - 1);                vertices[originalIndex].uv.x = uSum;                break;            }        }         // Fill in tangents        for (Index i = 0; i < N; i++) {            vec3 tangent = calculateSphereTangent(vertices[shape.faces[f][i]].uv.x);            vertices[shape.faces[f][i]].tangent = tangent;        }    }     IndexVector solidIndices, wireIndices;    IndexPairs wireSeenIndices;     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;    std::vector<GeometryCache::ShapeVertex> 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.emplace_back(vec3(0.0f, 0.5f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec2((float)i / (float)N, 1.0f), vec3(0.0f));        }    } else {        for (const vec3& v : shape) {            vertices.emplace_back(vec3(v.x, 0.5f, v.z), vec3(0.0f, 1.0f, 0.0f), vec2(v.x, v.z) + vec2(0.5f), vec3(1.0f, 0.0f, 0.0f));        }    }    for (const vec3& v : shape) {        vertices.emplace_back(vec3(v.x, -0.5f, v.z), vec3(0.0f, -1.0f, 0.0f), vec2(-v.x, v.z) + vec2(0.5f), vec3(-1.0f, 0.0f, 0.0f));    }

Lines 1–500 of 2501.