Changeset f00ee54 in opengl-game


Ignore:
Timestamp:
Aug 25, 2019, 12:58:06 AM (5 years ago)
Author:
Dmitry Portnoy <dmp1488@…>
Branches:
feature/imgui-sdl, master, points-test
Children:
721e8be
Parents:
d53ef6a
Message:

Refactor the code to allow different graphics pipelines to use different Vertex structs and different uniform and vertex attributes

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • shaders/overlay.frag

    rd53ef6a rf00ee54  
    44layout(binding = 0) uniform sampler2D uiTexSampler;
    55
    6 layout(location = 0) in vec3 fragColor;
    7 layout(location = 1) in vec2 fragTexCoord;
    8 layout(location = 2) flat in uint isOverlay;
     6layout(location = 0) in vec2 fragTexCoord;
    97
    108layout(location = 0) out vec4 outColor;
     
    1210void main() {
    1311   outColor = texture(uiTexSampler, fragTexCoord);
    14 
    15    if (isOverlay == 1) {
    16       outColor = texture(uiTexSampler, fragTexCoord);
    17    } else {
    18       outColor = vec4(fragColor * texture(uiTexSampler, fragTexCoord).rgb, 1.0);
    19    }
    2012}
  • shaders/overlay.vert

    rd53ef6a rf00ee54  
    33
    44layout(location = 0) in vec3 inPosition;
    5 layout(location = 1) in vec3 inColor;
    6 layout(location = 2) in vec2 inTexCoord;
     5layout(location = 1) in vec2 inTexCoord;
    76
    8 layout(location = 0) out vec3 fragColor;
    9 layout(location = 1) out vec2 fragTexCoord;
    10 layout(location = 2) out uint isOverlay;
     7layout(location = 0) out vec2 fragTexCoord;
    118
    129void main() {
    13    if (gl_VertexIndex < 0) {
    14       fragColor = inColor;
    15       isOverlay = 0;
    16    } else {
    17       fragColor = inColor;
    18       isOverlay = 1;
    19    }
     10   fragTexCoord = inTexCoord;
    2011
    21    fragTexCoord = inTexCoord;
    2212   gl_Position = vec4(inPosition, 1.0);
    2313}
  • shaders/scene.frag

    rd53ef6a rf00ee54  
    33
    44layout(binding = 1) uniform sampler2D texSampler;
    5 layout(binding = 2) uniform sampler2D uiTexSampler;
    65
    76layout(location = 0) in vec3 fragColor;
    87layout(location = 1) in vec2 fragTexCoord;
    9 layout(location = 2) flat in uint isOverlay;
    108
    119layout(location = 0) out vec4 outColor;
    1210
    1311void main() {
    14    if (isOverlay == 1) {
    15       outColor = texture(uiTexSampler, fragTexCoord);
    16    } else {
    17       outColor = vec4(fragColor * texture(texSampler, fragTexCoord).rgb, 1.0);
    18    }
     12   outColor = vec4(fragColor * texture(texSampler, fragTexCoord).rgb, 1.0);
    1913}
  • shaders/scene.vert

    rd53ef6a rf00ee54  
    1414layout(location = 0) out vec3 fragColor;
    1515layout(location = 1) out vec2 fragTexCoord;
    16 layout(location = 2) out uint isOverlay;
    1716
    1817void main() {
    19    if (gl_VertexIndex < 8) {
    20       gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
    21       fragColor = inColor;
    22       isOverlay = 0;
    23    } else {
    24       gl_Position = vec4(inPosition, 1.0);
    25       fragColor = vec3(1.0, 1.0, 1.0);
    26       isOverlay = 1;
    27    }
     18   fragColor = inColor;
     19   fragTexCoord = inTexCoord;
    2820
    29    fragTexCoord = inTexCoord;
     21   gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
    3022}
  • vulkan-game.cpp

    rd53ef6a rf00ee54  
    1 /*
    2 DESIGN GUIDE
    3 
    4 -I should store multiple buffers (e.g. vertex and index buffers) in the same VkBuffer and use offsets into it
    5 -For specifying a separate transform for each model, I can specify a descriptorCount > ` in the ubo layout binding
    6 -Name class instance variables that are pointers (and possibly other pointer variables as well) like pVarName
    7 */
    8 
    9 #include "game-gui-glfw.hpp"
    10 
    11 #include "game-gui-sdl.hpp"
     1#define STB_IMAGE_IMPLEMENTATION
     2#include "stb_image.h" // TODO: Probably switch to SDL_image
    123
    134//#define _USE_MATH_DEFINES // Will be needed when/if I need to # include <cmath>
     
    156#define GLM_FORCE_RADIANS
    167#define GLM_FORCE_DEPTH_ZERO_TO_ONE
     8
    179#include <glm/glm.hpp>
    1810#include <glm/gtc/matrix_transform.hpp>
    19 
    20 #define STB_IMAGE_IMPLEMENTATION
    21 #include "stb_image.h" // TODO: Probably switch to SDL_image
    2211
    2312#include <iostream>
     
    3019#include <chrono>
    3120
     21#include "utils.h"
     22
     23#include "game-gui-glfw.hpp"
     24#include "game-gui-sdl.hpp"
     25
    3226using namespace std;
    33 
    34 // TODO: Maybe add asserts for testing
     27using namespace glm;
    3528
    3629const int SCREEN_WIDTH = 800;
     
    7265   glm::vec3 color;
    7366   glm::vec2 texCoord;
    74 
    75    static VkVertexInputBindingDescription getBindingDescription() {
    76       VkVertexInputBindingDescription bindingDescription = {};
    77 
    78       // Since there is only one array of vertex data, we use binding = 0
    79       // I'll probably do that for the foreseeable future
    80       // I can calculate the stride myself given info about all the varying attributes
    81 
    82       // In new-game.cpp, it looks like I had a C++ struct for each shader type anyway,
    83       // so I can use the same pattern for this as well probably
    84 
    85       bindingDescription.binding = 0;
    86       bindingDescription.stride = sizeof(Vertex);
    87       bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
    88 
    89       return bindingDescription;
    90    }
    91 
    92    static array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions() {
    93       array<VkVertexInputAttributeDescription, 3> attributeDescriptions = {};
    94 
    95       attributeDescriptions[0].binding = 0;
    96       attributeDescriptions[0].location = 0;
    97       attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
    98       attributeDescriptions[0].offset = offsetof(Vertex, pos);
    99 
    100       attributeDescriptions[1].binding = 0;
    101       attributeDescriptions[1].location = 1;
    102       attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
    103       attributeDescriptions[1].offset = offsetof(Vertex, color);
    104 
    105       attributeDescriptions[2].binding = 0;
    106       attributeDescriptions[2].location = 2;
    107       attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
    108       attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
    109 
    110       return attributeDescriptions;
    111    }
    11267};
    11368
     69struct OverlayVertex {
     70   glm::vec3 pos;
     71   glm::vec2 texCoord;
     72};
     73
    11474struct UniformBufferObject {
    115    alignas(16) glm::mat4 model;
    116    alignas(16) glm::mat4 view;
    117    alignas(16) glm::mat4 proj;
     75   alignas(16) mat4 model;
     76   alignas(16) mat4 view;
     77   alignas(16) mat4 proj;
    11878};
    11979
     
    12282   VkPipeline pipeline;
    12383
     84   VkVertexInputBindingDescription bindingDescription;
     85   vector<VkVertexInputAttributeDescription> attributeDescriptions;
     86
    12487   VkDescriptorPool descriptorPool;
    12588   VkDescriptorSetLayout descriptorSetLayout;
    12689   vector<VkDescriptorSet> descriptorSets;
    12790
     91   size_t numVertices; // Currently unused
    12892   VkBuffer vertexBuffer;
    12993   VkDeviceMemory vertexBufferMemory;
    130    size_t numVertices;
    131 
     94
     95   size_t numIndices;
    13296   VkBuffer indexBuffer;
    13397   VkDeviceMemory indexBufferMemory;
    134    size_t numIndices;
    13598};
    13699
     
    345308         createTextureSampler();
    346309
    347          createSceneDescriptorSetLayout(scenePipeline);
    348          createOverlayDescriptorSetLayout(overlayPipeline);
    349 
    350          createShaderBuffers(scenePipeline, {
     310         vector<Vertex> sceneVertices = {
    351311            {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}},
    352312            {{ 0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}},
     
    358318            {{ 0.5f,  0.5f,  0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
    359319            {{-0.5f,  0.5f,  0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}}
    360          }, {
     320         };
     321         vector<uint16_t> sceneIndices = {
    361322            0, 1, 2, 2, 3, 0,
    362323            4, 5, 6, 6, 7, 4
    363          });
    364 
    365          createShaderBuffers(overlayPipeline, {
    366             {{-1.0f,  1.0f,  0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 1.0f}},
    367             {{ 1.0f,  1.0f,  0.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f}},
    368             {{ 1.0f, -1.0f,  0.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, 0.0f}},
    369             {{-1.0f, -1.0f,  0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}
    370          }, {
    371             0, 1, 2, 2,3, 0
    372          });
     324         };
     325
     326         initGraphicsPipelineInfo(scenePipeline,
     327            sceneVertices.data(), sizeof(Vertex), sceneVertices.size(),
     328            sceneIndices.data(), sizeof(uint16_t), sceneIndices.size());
     329
     330         addAttributeDescription(scenePipeline, VK_FORMAT_R32G32B32_SFLOAT, offset_of(&Vertex::pos));
     331         addAttributeDescription(scenePipeline, VK_FORMAT_R32G32B32_SFLOAT, offset_of(&Vertex::color));
     332         addAttributeDescription(scenePipeline, VK_FORMAT_R32G32_SFLOAT, offset_of(&Vertex::texCoord));
     333
     334         createSceneDescriptorSetLayout(scenePipeline);
     335
     336
     337         vector<OverlayVertex> overlayVertices = {
     338            {{-1.0f,  1.0f,  0.0f}, {0.0f, 1.0f}},
     339            {{ 1.0f,  1.0f,  0.0f}, {1.0f, 1.0f}},
     340            {{ 1.0f, -1.0f,  0.0f}, {1.0f, 0.0f}},
     341            {{-1.0f, -1.0f,  0.0f}, {0.0f, 0.0f}}
     342         };
     343         vector<uint16_t> overlayIndices = {
     344            0, 1, 2, 2, 3, 0
     345         };
     346
     347         initGraphicsPipelineInfo(overlayPipeline,
     348            overlayVertices.data(), sizeof(OverlayVertex), overlayVertices.size(),
     349            overlayIndices.data(), sizeof(uint16_t), overlayIndices.size());
     350
     351         addAttributeDescription(overlayPipeline, VK_FORMAT_R32G32B32_SFLOAT, offset_of(&OverlayVertex::pos));
     352         addAttributeDescription(overlayPipeline, VK_FORMAT_R32G32_SFLOAT, offset_of(&OverlayVertex::texCoord));
     353
     354         createOverlayDescriptorSetLayout(overlayPipeline);
    373355
    374356         createBufferResources();
     
    706688            };
    707689
    708             actualExtent.width = max(capabilities.minImageExtent.width, min(capabilities.maxImageExtent.width, actualExtent.width));
    709             actualExtent.height = max(capabilities.minImageExtent.height, min(capabilities.maxImageExtent.height, actualExtent.height));
     690            actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
     691            actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
    710692
    711693            return actualExtent;
     
    794776         samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
    795777
    796          VkDescriptorSetLayoutBinding overlaySamplerLayoutBinding = {};
    797          overlaySamplerLayoutBinding.binding = 2;
    798          overlaySamplerLayoutBinding.descriptorCount = 1;
    799          overlaySamplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
    800          overlaySamplerLayoutBinding.pImmutableSamplers = nullptr;
    801          overlaySamplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
    802 
    803          array<VkDescriptorSetLayoutBinding, 3> bindings = { uboLayoutBinding, samplerLayoutBinding, overlaySamplerLayoutBinding };
     778         array<VkDescriptorSetLayoutBinding, 2> bindings = { uboLayoutBinding, samplerLayoutBinding };
    804779         VkDescriptorSetLayoutCreateInfo layoutInfo = {};
    805780         layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
     
    831806      }
    832807
     808      void initGraphicsPipelineInfo(GraphicsPipelineInfo& info,
     809            const void* vertexData, int vertexSize, size_t numVertices,
     810            const void* indexData, int indexSize, size_t numIndices) {
     811         // Since there is only one array of vertex data, we use binding = 0
     812         // I'll probably do that for the foreseeable future
     813         // I can calculate the stride myself given info about all the varying attributes
     814
     815         info.bindingDescription.binding = 0;
     816         info.bindingDescription.stride = vertexSize;
     817         info.bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
     818
     819         info.numVertices = numVertices;
     820         createVertexBuffer(info, vertexData, vertexSize * numVertices);
     821
     822         info.numIndices = numIndices;
     823         createIndexBuffer(info, indexData, indexSize * numIndices);
     824      }
     825
     826      void addAttributeDescription(GraphicsPipelineInfo& info, VkFormat format, size_t offset) {
     827         VkVertexInputAttributeDescription attributeDesc = {};
     828
     829         attributeDesc.binding = 0;
     830         attributeDesc.location = info.attributeDescriptions.size();
     831         attributeDesc.format = format;
     832         attributeDesc.offset = offset;
     833
     834         info.attributeDescriptions.push_back(attributeDesc);
     835      }
     836
    833837      void createGraphicsPipeline(string vertShaderFile, string fragShaderFile, GraphicsPipelineInfo& info) {
    834838         auto vertShaderCode = readFile(vertShaderFile);
     
    855859         vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
    856860
    857          auto bindingDescription = Vertex::getBindingDescription();
    858          auto attributeDescriptions = Vertex::getAttributeDescriptions();
    859 
    860861         vertexInputInfo.vertexBindingDescriptionCount = 1;
    861          vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
    862          vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
    863          vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
     862         vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(info.attributeDescriptions.size());
     863         vertexInputInfo.pVertexBindingDescriptions = &info.bindingDescription;
     864         vertexInputInfo.pVertexAttributeDescriptions = info.attributeDescriptions.data();
    864865
    865866         VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
     
    11471148
    11481149      void populateImageFromSDLTexture(SDL_Texture* texture, VkImage& image) {
    1149          int a, w, h, pitch;
     1150         int a, w, h;
    11501151
    11511152         SDL_QueryTexture(texture, nullptr, &a, &w, &h);
     
    13651366      }
    13661367
    1367       void createShaderBuffers(GraphicsPipelineInfo& info, const vector<Vertex>& vertices, const vector<uint16_t>& indices) {
    1368          createVertexBuffer(info.vertexBuffer, info.vertexBufferMemory, vertices);
    1369          info.numVertices = vertices.size();
    1370 
    1371          createIndexBuffer(info.indexBuffer, info.indexBufferMemory, indices);
    1372          info.numIndices = indices.size();
    1373       }
    1374 
    1375       void createVertexBuffer(VkBuffer& vertexBuffer, VkDeviceMemory& vertexBufferMemory,
    1376             const vector<Vertex>& vertices) {
    1377          VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
    1378 
     1368      void createVertexBuffer(GraphicsPipelineInfo& info, const void* vertexData, VkDeviceSize bufferSize) {
    13791369         VkBuffer stagingBuffer;
    13801370         VkDeviceMemory stagingBufferMemory;
     
    13851375         void* data;
    13861376         vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
    1387          memcpy(data, vertices.data(), (size_t) bufferSize);
     1377         memcpy(data, vertexData, (size_t) bufferSize);
    13881378         vkUnmapMemory(device, stagingBufferMemory);
    13891379
    13901380         createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
    1391             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);
    1392 
    1393          copyBuffer(stagingBuffer, vertexBuffer, bufferSize);
     1381            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, info.vertexBuffer, info.vertexBufferMemory);
     1382
     1383         copyBuffer(stagingBuffer, info.vertexBuffer, bufferSize);
    13941384
    13951385         vkDestroyBuffer(device, stagingBuffer, nullptr);
     
    13971387      }
    13981388
    1399       void createIndexBuffer(VkBuffer& indexBuffer, VkDeviceMemory& indexBufferMemory,
    1400             const vector<uint16_t>& indices) {
    1401          VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();
    1402 
     1389      void createIndexBuffer(GraphicsPipelineInfo& info, const void* indexData, VkDeviceSize bufferSize) {
    14031390         VkBuffer stagingBuffer;
    14041391         VkDeviceMemory stagingBufferMemory;
     
    14091396         void* data;
    14101397         vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
    1411          memcpy(data, indices.data(), (size_t) bufferSize);
     1398         memcpy(data, indexData, (size_t) bufferSize);
    14121399         vkUnmapMemory(device, stagingBufferMemory);
    14131400
    14141401         createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
    1415             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
    1416 
    1417          copyBuffer(stagingBuffer, indexBuffer, bufferSize);
     1402            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, info.indexBuffer, info.indexBufferMemory);
     1403
     1404         copyBuffer(stagingBuffer, info.indexBuffer, bufferSize);
    14181405
    14191406         vkDestroyBuffer(device, stagingBuffer, nullptr);
     
    15171504
    15181505      void createSceneDescriptorPool(GraphicsPipelineInfo& info) {
    1519          array<VkDescriptorPoolSize, 3> poolSizes = {};
     1506         array<VkDescriptorPoolSize, 2> poolSizes = {};
    15201507         poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
    15211508         poolSizes[0].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
    15221509         poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
    15231510         poolSizes[1].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
    1524          poolSizes[2].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
    1525          poolSizes[2].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
    15261511
    15271512         VkDescriptorPoolCreateInfo poolInfo = {};
     
    15611546            imageInfo.sampler = textureSampler;
    15621547
    1563             VkDescriptorImageInfo overlayImageInfo = {};
    1564             overlayImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
    1565             overlayImageInfo.imageView = sdlOverlayImageView;
    1566             overlayImageInfo.sampler = textureSampler;
    1567 
    1568             array<VkWriteDescriptorSet, 3> descriptorWrites = {};
     1548            array<VkWriteDescriptorSet, 2> descriptorWrites = {};
    15691549
    15701550            descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
     
    15881568            descriptorWrites[1].pTexelBufferView = nullptr;
    15891569
    1590             descriptorWrites[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    1591             descriptorWrites[2].dstSet = info.descriptorSets[i];
    1592             descriptorWrites[2].dstBinding = 2;
    1593             descriptorWrites[2].dstArrayElement = 0;
    1594             descriptorWrites[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
    1595             descriptorWrites[2].descriptorCount = 1;
    1596             descriptorWrites[2].pBufferInfo = nullptr;
    1597             descriptorWrites[2].pImageInfo = &overlayImageInfo;
    1598             descriptorWrites[2].pTexelBufferView = nullptr;
    1599 
    16001570            vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
    16011571         }
     
    16851655
    16861656            array<VkClearValue, 2> clearValues = {};
    1687             clearValues[0].color = { 0.0f, 0.0f, 0.0f, 1.0f };
     1657            clearValues[0].color = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
    16881658            clearValues[1].depthStencil = { 1.0f, 0 };
    16891659
     
    18711841
    18721842         UniformBufferObject ubo = {};
    1873          ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
    1874          ubo.view = glm::lookAt(glm::vec3(0.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    1875          ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f);
     1843         ubo.model = rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
     1844         ubo.view = lookAt(glm::vec3(0.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
     1845         ubo.proj = perspective(radians(45.0f), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f);
    18761846         ubo.proj[1][1] *= -1; // flip the y-axis so that +y is up
    18771847
Note: See TracChangeset for help on using the changeset viewer.