1743 lines · 70.4 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 <cmath> #include <QNetworkReply>#include <QThreadPool> #include <FSTReader.h>#include <NumericalConstants.h> #include "TextureCache.h"#include "RenderUtilsLogging.h" #include "standardTransformPNTC_vert.h"#include "standardDrawTexture_frag.h" #include "gpu/StandardShaderLib.h" #include "model/TextureMap.h" //#define WANT_DEBUG const int GeometryCache::UNKNOWN_ID = -1;  static const int VERTICES_PER_TRIANGLE = 3; //static const uint FLOATS_PER_VERTEX = 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 normalsstatic const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);static const gpu::Type SHAPE_INDEX_TYPE = gpu::UINT16;static const uint SHAPE_INDEX_SIZE = sizeof(gpu::uint16); void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const 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 IndexVector& indices, const 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);    }} const VertexVector& icosahedronVertices() {    static const float phi = (1.0f + sqrtf(5.0f)) / 2.0f;    static const float a = 0.5f;    static const float b = 1.0f / (2.0f * phi);     static const VertexVector 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 VertexVector& tetrahedronVertices() {    static const float a = 1.0f / sqrtf(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 VertexVector vertices{        A, B, C,        D, B, A,        C, D, A,        C, B, D,    };    return vertices;} static const size_t TESSELTATION_MULTIPLIER = 4;static const size_t ICOSAHEDRON_TO_SPHERE_TESSELATION_COUNT = 3;static const size_t VECTOR_TO_VECTOR_WITH_NORMAL_MULTIPLER = 2;  VertexVector tesselate(const VertexVector& startingTriangles, int count) {    VertexVector 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]);    }     VertexVector newTriangles;    while (count) {        newTriangles.clear();        // Tesselation takes one triangle and makes it into 4 triangles        // See https://en.wikipedia.org/wiki/Space-filling_tree#/media/File:Space_Filling_Tree_Tri_iter_1_2_3.png        newTriangles.reserve(triangles.size() * TESSELTATION_MULTIPLIER);        for (size_t i = 0; i < triangles.size(); i += VERTICES_PER_TRIANGLE) {            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;} 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);}  // 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() {    auto vertexBuffer = std::make_shared<gpu::Buffer>();    auto indexBuffer = std::make_shared<gpu::Buffer>();    size_t startingIndex = 0;        // Cube     startingIndex = _shapeVertices->getSize() / SHAPE_VERTEX_STRIDE;    {        ShapeData& shapeData = _shapes[Cube];        VertexVector 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));         static const size_t VERTEX_FORMAT_SIZE = 2;        static const size_t VERTEX_OFFSET = 0;         for (size_t i = 0; i < vertices.size(); ++i) {            auto vertexIndex = i;            // Make a unit cube by having the vertices (at index N)             // while leaving the normals (at index N + 1) alone            if (VERTEX_OFFSET == vertexIndex % VERTEX_FORMAT_SIZE) {                vertices[vertexIndex] *= 0.5f;            }        }        shapeData.setupVertices(_shapeVertices, vertices);         IndexVector 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 (auto& index : indices) {            index += (uint16_t)startingIndex;        }         IndexVector 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 (size_t i = 0; i < wireIndices.size(); ++i) {            indices[i] += (uint16_t)startingIndex;        }         shapeData.setupIndices(_shapeIndices, indices, wireIndices);    }     // Tetrahedron    startingIndex = _shapeVertices->getSize() / SHAPE_VERTEX_STRIDE;    {        ShapeData& shapeData = _shapes[Tetrahedron];        size_t vertexCount = 4;        VertexVector vertices;        {            VertexVector originalVertices = tetrahedronVertices();            vertexCount = originalVertices.size();            vertices.reserve(originalVertices.size() * VECTOR_TO_VECTOR_WITH_NORMAL_MULTIPLER);            for (size_t i = 0; i < originalVertices.size(); i += VERTICES_PER_TRIANGLE) {                auto triangleStartIndex = i;                vec3 faceNormal;                for (size_t j = 0; j < VERTICES_PER_TRIANGLE; ++j) {                    auto triangleVertexIndex = j;                    auto vertexIndex = triangleStartIndex + triangleVertexIndex;                    faceNormal += originalVertices[vertexIndex];                }                faceNormal = glm::normalize(faceNormal);                for (size_t j = 0; j < VERTICES_PER_TRIANGLE; ++j) {                    auto triangleVertexIndex = j;                    auto vertexIndex = triangleStartIndex + triangleVertexIndex;                    vertices.push_back(glm::normalize(originalVertices[vertexIndex]));                    vertices.push_back(faceNormal);                }            }        }        shapeData.setupVertices(_shapeVertices, vertices);         IndexVector indices;        for (size_t i = 0; i < vertexCount; i += VERTICES_PER_TRIANGLE) {            auto triangleStartIndex = i;            for (size_t j = 0; j < VERTICES_PER_TRIANGLE; ++j) {                auto triangleVertexIndex = j;                auto vertexIndex = triangleStartIndex + triangleVertexIndex;                indices.push_back((uint16_t)(vertexIndex + startingIndex));            }        }         IndexVector wireIndices{            0, 1, 1, 2, 2, 0,            0, 3, 1, 3, 2, 3,        };         for (size_t i = 0; i < wireIndices.size(); ++i) {            wireIndices[i] += (uint16_t)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];        VertexVector vertices;        IndexVector indices;        {            VertexVector originalVertices = tesselate(icosahedronVertices(), ICOSAHEDRON_TO_SPHERE_TESSELATION_COUNT);            vertices.reserve(originalVertices.size() * VECTOR_TO_VECTOR_WITH_NORMAL_MULTIPLER);            for (size_t i = 0; i < originalVertices.size(); i += VERTICES_PER_TRIANGLE) {                auto triangleStartIndex = i;                for (int j = 0; j < VERTICES_PER_TRIANGLE; ++j) {                    auto triangleVertexIndex = j;                    auto vertexIndex = triangleStartIndex + triangleVertexIndex;                    const auto& vertex = originalVertices[i + j];                    // Spheres use the same values for vertices and normals                    vertices.push_back(vertex);                    vertices.push_back(vertex);                    indices.push_back((uint16_t)(vertexIndex + 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];         VertexVector vertices;        IndexVector indices;        {            const VertexVector& originalVertices = icosahedronVertices();            vertices.reserve(originalVertices.size() * VECTOR_TO_VECTOR_WITH_NORMAL_MULTIPLER);            for (size_t i = 0; i < originalVertices.size(); i += 3) {                auto triangleStartIndex = i;                vec3 faceNormal;                for (int j = 0; j < VERTICES_PER_TRIANGLE; ++j) {                    auto triangleVertexIndex = j;                    auto vertexIndex = triangleStartIndex + triangleVertexIndex;                    faceNormal += originalVertices[vertexIndex];                }                faceNormal = glm::normalize(faceNormal);                for (int j = 0; j < VERTICES_PER_TRIANGLE; ++j) {                    auto triangleVertexIndex = j;                    auto vertexIndex = triangleStartIndex + triangleVertexIndex;                    vertices.push_back(glm::normalize(originalVertices[vertexIndex]));                    vertices.push_back(faceNormal);                    indices.push_back((uint16_t)(vertexIndex + startingIndex));                }            }        }         shapeData.setupVertices(_shapeVertices, vertices);        // FIXME don't use solid indices for wire drawing.          shapeData.setupIndices(_shapeIndices, indices, indices);    }     // Line    startingIndex = _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 + (uint16_t)startingIndex);        wireIndices.push_back(1 + (uint16_t)startingIndex);         shapeData.setupIndices(_shapeIndices, IndexVector(), wireIndices);    }     // Not implememented yet:     //Triangle,    //Quad,    //Circle,    //Octahetron,    //Dodecahedron,    //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);

Lines 1–500 of 1743.