Bradley Austin DavisFixing lighting and atmospheree12e4ec11 years agoHistory
2122 lines · 89.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 <gpu/GLBackend.h> #include "TextureCache.h"#include "RenderUtilsLogging.h" #include "standardTransformPNTC_vert.h"#include "standardDrawTexture_frag.h" #include "gpu/StandardShaderLib.h" //#define WANT_DEBUG const int GeometryCache::UNKNOWN_ID = -1; 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 normalsstatic 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 shadingvoid GeometryCache::buildShapes() {    auto vertexBuffer = std::make_shared<gpu::Buffer>();    auto indexBuffer = std::make_shared<gpu::Buffer>();    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]));                    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]);                    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]));                    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<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);        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() {    #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} QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,                                                        bool delayLoad, const void* extra) {    // NetworkGeometry is no longer a subclass of Resource, but requires this method because, it is pure virtual.    assert(false);    return QSharedPointer<Resource>();} 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);

Lines 1–500 of 2122.