void ApplicationCompositor::drawSphereSection(gpu::Batch& batch) {
    buildHemiVertices(_textureFov, _textureAspectRatio, 80, 80);
    static const int VERTEX_DATA_SLOT = 0;
    static const int TEXTURE_DATA_SLOT = 1;
    static const int COLOR_DATA_SLOT = 2;
    gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone
    streamFormat->setAttribute(gpu::Stream::POSITION, VERTEX_DATA_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
    streamFormat->setAttribute(gpu::Stream::TEXCOORD, TEXTURE_DATA_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
    streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_DATA_SLOT, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::RGBA));
    batch.setInputFormat(streamFormat);

    static const int VERTEX_STRIDE = sizeof(vec3) + sizeof(vec2) + sizeof(vec4);
    gpu::BufferView posView(_hemiVertices, 0, _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
    gpu::BufferView uvView(_hemiVertices, sizeof(vec3), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::TEXCOORD)._element);
    gpu::BufferView colView(_hemiVertices, sizeof(vec3) + sizeof(vec2), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
    batch.setInputBuffer(VERTEX_DATA_SLOT, posView);
    batch.setInputBuffer(TEXTURE_DATA_SLOT, uvView);
    batch.setInputBuffer(COLOR_DATA_SLOT, colView);
    batch.setIndexBuffer(gpu::UINT16, _hemiIndices, 0);
    batch.drawIndexed(gpu::TRIANGLES, _hemiIndexCount);
}
Beispiel #2
0
void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) {

    if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
        static gpu::PipelinePointer thePipeline;
        static gpu::BufferPointer theBuffer;
        static gpu::Stream::FormatPointer theFormat;
        static gpu::BufferPointer theConstants;
        int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader
        if (!thePipeline) {
            auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert)));
            auto skyFS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(Skybox_frag)));
            auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyVS, skyFS));

            gpu::Shader::BindingSet bindings;
            bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), 0));
            if (!gpu::Shader::makeProgram(*skyShader, bindings)) {

            }

            SKYBOX_CONSTANTS_SLOT = skyShader->getBuffers().findLocation("skyboxBuffer");
            if (SKYBOX_CONSTANTS_SLOT == gpu::Shader::INVALID_LOCATION) {
                SKYBOX_CONSTANTS_SLOT = skyShader->getUniforms().findLocation("skyboxBuffer");
            }
            
            auto skyState = gpu::StatePointer(new gpu::State());

            thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));
        
            const float CLIP = 1.0;
            const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}};
            theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices));
        
            theFormat.reset(new gpu::Stream::Format());
            theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
        
            auto color = glm::vec4(1.0f);
            theConstants.reset(new gpu::Buffer(sizeof(color), (const gpu::Byte*) &color));
        }

        glm::mat4 projMat;
        viewFrustum.evalProjectionMatrix(projMat);

        Transform viewTransform;
        viewFrustum.evalViewTransform(viewTransform);

        if (glm::all(glm::equal(skybox.getColor(), glm::vec3(0.0f)))) { 
            auto color = glm::vec4(1.0f);
            theConstants->setSubData(0, sizeof(color), (const gpu::Byte*) &color);
        } else {
            theConstants->setSubData(0, sizeof(Color), (const gpu::Byte*) &skybox.getColor());
        }

        batch.setProjectionTransform(projMat);
        batch.setViewTransform(viewTransform);
        batch.setModelTransform(Transform()); // only for Mac
        batch.setPipeline(thePipeline);
        batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
        batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize());
        batch.setInputFormat(theFormat);
        batch.setUniformTexture(0, skybox.getCubemap());
        batch.draw(gpu::TRIANGLE_STRIP, 4);
    } else {
        // skybox has no cubemap, just clear the color buffer
        auto color = skybox.getColor();
        batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(skybox.getColor(),1.0f), 0.f, 0); 
    }
}
void ApplicationCompositor::buildHemiVertices(
    const float fov, const float aspectRatio, const int slices, const int stacks) {
    static float textureFOV = 0.0f, textureAspectRatio = 1.0f;
    if (textureFOV == fov && textureAspectRatio == aspectRatio) {
        return;
    }

    textureFOV = fov;
    textureAspectRatio = aspectRatio;

    auto geometryCache = DependencyManager::get<GeometryCache>();

    _hemiVertices = gpu::BufferPointer(new gpu::Buffer());
    _hemiIndices = gpu::BufferPointer(new gpu::Buffer());


    if (fov >= PI) {
        qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
    }

    //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
    
    vec3 pos; 
    vec2 uv;
    // Compute vertices positions and texture UV coordinate
    // Create and write to buffer
    for (int i = 0; i < stacks; i++) {
        uv.y = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f
        // abs(theta) <= fov / 2.0f
        float pitch = -fov * (uv.y - 0.5f);
        for (int j = 0; j < slices; j++) {
            uv.x = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f
            // abs(phi) <= fov * aspectRatio / 2.0f
            float yaw = -fov * aspectRatio * (uv.x - 0.5f);
            pos = getPoint(yaw, pitch);
            static const vec4 color(1);
            _hemiVertices->append(sizeof(pos), (gpu::Byte*)&pos);
            _hemiVertices->append(sizeof(vec2), (gpu::Byte*)&uv);
            _hemiVertices->append(sizeof(vec4), (gpu::Byte*)&color);
        }
    }
    
    // Compute number of indices needed
    static const int VERTEX_PER_TRANGLE = 3;
    static const int TRIANGLE_PER_RECTANGLE = 2;
    int numberOfRectangles = (slices - 1) * (stacks - 1);
    _hemiIndexCount = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE;
    
    // Compute indices order
    std::vector<GLushort> indices;
    for (int i = 0; i < stacks - 1; i++) {
        for (int j = 0; j < slices - 1; j++) {
            GLushort bottomLeftIndex = i * slices + j;
            GLushort bottomRightIndex = bottomLeftIndex + 1;
            GLushort topLeftIndex = bottomLeftIndex + slices;
            GLushort topRightIndex = topLeftIndex + 1;
            // FIXME make a z-order curve for better vertex cache locality
            indices.push_back(topLeftIndex);
            indices.push_back(bottomLeftIndex);
            indices.push_back(topRightIndex);

            indices.push_back(topRightIndex);
            indices.push_back(bottomLeftIndex);
            indices.push_back(bottomRightIndex);
        }
    }
    _hemiIndices->append(sizeof(GLushort) * indices.size(), (gpu::Byte*)&indices[0]);
}
Beispiel #4
0
    void draw() {
        // Attempting to draw before we're visible and have a valid size will
        // produce GL errors.
        if (!isVisible() || _size.width() <= 0 || _size.height() <= 0) {
            return;
        }
        makeCurrent();
        
        gpu::Batch batch;
        batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 0.0f, 0.0f, 0.0f, 1.0f });
        batch.clearDepthFramebuffer(1e4);
        batch.setViewportTransform({ 0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio() });
        batch.setProjectionTransform(_projectionMatrix);
        
        float t = _time.elapsed() * 1e-3f;
        glm::vec3 unitscale { 1.0f };
        glm::vec3 up { 0.0f, 1.0f, 0.0f };

        float distance = 3.0f;
        glm::vec3 camera_position{ distance * sinf(t), 0.0f, distance * cosf(t) };

        static const vec3 camera_focus(0);
        static const vec3 camera_up(0, 1, 0);
        glm::mat4 camera = glm::inverse(glm::lookAt(camera_position, camera_focus, up));
        batch.setViewTransform(camera);
        batch.setPipeline(_pipeline);
        batch.setModelTransform(Transform());

        auto geometryCache = DependencyManager::get<GeometryCache>();

        // Render grid on xz plane (not the optimal way to do things, but w/e)
        // Note: GeometryCache::renderGrid will *not* work, as it is apparenly unaffected by batch rotations and renders xy only
        {
            static const std::string GRID_INSTANCE = "Grid";
            static auto compactColor1 = toCompactColor(vec4{ 0.35f, 0.25f, 0.15f, 1.0f });
            static auto compactColor2 = toCompactColor(vec4{ 0.15f, 0.25f, 0.35f, 1.0f });
            static std::vector<glm::mat4> transforms;
            static gpu::BufferPointer colorBuffer;
            if (!transforms.empty()) {
                transforms.reserve(200);
                colorBuffer = std::make_shared<gpu::Buffer>();
                for (int i = 0; i < 100; ++i) {
                    {
                        glm::mat4 transform = glm::translate(mat4(), vec3(0, -1, -50 + i));
                        transform = glm::scale(transform, vec3(100, 1, 1));
                        transforms.push_back(transform);
                        colorBuffer->append(compactColor1);
                    }

                    {
                        glm::mat4 transform = glm::mat4_cast(quat(vec3(0, PI / 2.0f, 0)));
                        transform = glm::translate(transform, vec3(0, -1, -50 + i));
                        transform = glm::scale(transform, vec3(100, 1, 1));
                        transforms.push_back(transform);
                        colorBuffer->append(compactColor2);
                    }
                }
            }

            auto pipeline = geometryCache->getSimplePipeline();
            for (auto& transform : transforms) {
                batch.setModelTransform(transform);
                batch.setupNamedCalls(GRID_INSTANCE, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
                    batch.setViewTransform(camera);
                    batch.setPipeline(_pipeline);
                    geometryCache->renderWireShapeInstances(batch, GeometryCache::Line, data.count(), colorBuffer);
                });
            }
        }

        {
            static const size_t ITEM_COUNT = 1000;
            static const float SHAPE_INTERVAL = (PI * 2.0f) / ITEM_COUNT;
            static const float ITEM_INTERVAL = SHAPE_INTERVAL / TYPE_COUNT;

            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 std::vector<Transform> transforms;
            static std::vector<vec4> colors;
            static gpu::BufferPointer indirectBuffer;
            static gpu::BufferPointer transformBuffer;
            static gpu::BufferPointer colorBuffer;
            static gpu::BufferView colorView; 
            static gpu::BufferView instanceXfmView; 

            if (!transformBuffer) {
                transformBuffer = std::make_shared<gpu::Buffer>();
                colorBuffer = std::make_shared<gpu::Buffer>();
                indirectBuffer = std::make_shared<gpu::Buffer>();

                static const float ITEM_RADIUS = 20;
                static const vec3 ITEM_TRANSLATION{ 0, 0, -ITEM_RADIUS };
                for (size_t i = 0; i < TYPE_COUNT; ++i) {
                    GeometryCache::Shape shape = SHAPE[i];
                    GeometryCache::ShapeData shapeData = geometryCache->_shapes[shape];
                    {
                        gpu::Batch::DrawIndexedIndirectCommand indirectCommand;
                        indirectCommand._count = (uint)shapeData._indexCount;
                        indirectCommand._instanceCount = ITEM_COUNT;
                        indirectCommand._baseInstance = (uint)(i * ITEM_COUNT);
                        indirectCommand._firstIndex = (uint)shapeData._indexOffset / 2;
                        indirectCommand._baseVertex = 0;
                        indirectBuffer->append(indirectCommand);
                    }

                    //indirectCommand._count
                    float startingInterval = ITEM_INTERVAL * i;
                    for (size_t j = 0; j < ITEM_COUNT; ++j) {
                        float theta = j * SHAPE_INTERVAL + startingInterval;
                        auto transform = glm::rotate(mat4(), theta, Vectors::UP);
                        transform = glm::rotate(transform, (randFloat() - 0.5f) * PI / 4.0f, Vectors::UNIT_X);
                        transform = glm::translate(transform, ITEM_TRANSLATION);
                        transform = glm::scale(transform, vec3(randFloat() / 2.0f + 0.5f));
                        transformBuffer->append(transform);
                        transforms.push_back(transform);
                        auto color = vec4{ randomColorValue(64), randomColorValue(64), randomColorValue(64), 255 };
                        color /= 255.0f;
                        colors.push_back(color);
                        colorBuffer->append(toCompactColor(color));
                    }
                }
                colorView = gpu::BufferView(colorBuffer, COLOR_ELEMENT);
                instanceXfmView = gpu::BufferView(transformBuffer, TRANSFORM_ELEMENT);
            }

#if 1
            GeometryCache::ShapeData shapeData = geometryCache->_shapes[GeometryCache::Icosahedron];
            {
                batch.setViewTransform(camera);
                batch.setModelTransform(Transform());
                batch.setPipeline(_pipeline);
                batch.setInputFormat(getInstancedSolidStreamFormat());
                batch.setInputBuffer(gpu::Stream::COLOR, colorView);
                batch.setIndirectBuffer(indirectBuffer);
                shapeData.setupBatch(batch);
                batch.multiDrawIndexedIndirect(TYPE_COUNT, gpu::TRIANGLES);
            }
#else
            batch.setViewTransform(camera);
            batch.setPipeline(_pipeline);
            for (size_t i = 0; i < TYPE_COUNT; ++i) {
                GeometryCache::Shape shape = SHAPE[i];
                for (size_t j = 0; j < ITEM_COUNT; ++j) {
                    int index = i * ITEM_COUNT + j;
                    batch.setModelTransform(transforms[index]);
                    const vec4& color = colors[index];
                    batch._glColor4f(color.r, color.g, color.b, 1.0);
                    geometryCache->renderShape(batch, shape);
                }
            }
#endif
        }

        // Render unlit cube + sphere
        static auto startUsecs = usecTimestampNow(); 
        float seconds = getSeconds(startUsecs);

        seconds /= 4.0f;
        int shapeIndex = ((int)seconds) % TYPE_COUNT;
        bool wire = (seconds - floorf(seconds) > 0.5f);
        batch.setModelTransform(Transform());
        batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f);

        if (wire) {
            geometryCache->renderWireShape(batch, SHAPE[shapeIndex]);
        } else {
            geometryCache->renderShape(batch, SHAPE[shapeIndex]);
        }
        
        batch.setModelTransform(Transform().setScale(2.05f));
        batch._glColor4f(1, 1, 1, 1);
        geometryCache->renderWireCube(batch);

        _context->render(batch);
        _qGlContext.swapBuffers(this);
        
        fps.increment();
        if (fps.elapsed() >= 0.5f) {
            qDebug() << "FPS: " << fps.rate();
            fps.reset();
        }
    }