Moved heightmap to vks namespace (Refs #260)
This commit is contained in:
parent
c1575e4fe5
commit
7f1c376550
2 changed files with 184 additions and 181 deletions
|
|
@ -14,134 +14,136 @@
|
||||||
#include "VulkanDevice.hpp"
|
#include "VulkanDevice.hpp"
|
||||||
#include "VulkanBuffer.hpp"
|
#include "VulkanBuffer.hpp"
|
||||||
|
|
||||||
namespace vkTools
|
namespace vks
|
||||||
{
|
{
|
||||||
class HeightMap
|
namespace utils
|
||||||
{
|
{
|
||||||
private:
|
class HeightMap
|
||||||
uint16_t *heightdata;
|
|
||||||
uint32_t dim;
|
|
||||||
uint32_t scale;
|
|
||||||
|
|
||||||
vks::VulkanDevice *device = nullptr;
|
|
||||||
VkQueue copyQueue = VK_NULL_HANDLE;
|
|
||||||
public:
|
|
||||||
enum Topology { topologyTriangles, topologyQuads };
|
|
||||||
|
|
||||||
float heightScale = 1.0f;
|
|
||||||
float uvScale = 1.0f;
|
|
||||||
|
|
||||||
vks::Buffer vertexBuffer;
|
|
||||||
vks::Buffer indexBuffer;
|
|
||||||
|
|
||||||
struct Vertex {
|
|
||||||
glm::vec3 pos;
|
|
||||||
glm::vec3 normal;
|
|
||||||
glm::vec2 uv;
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t vertexBufferSize = 0;
|
|
||||||
size_t indexBufferSize = 0;
|
|
||||||
uint32_t indexCount = 0;
|
|
||||||
|
|
||||||
HeightMap(vks::VulkanDevice *device, VkQueue copyQueue)
|
|
||||||
{
|
{
|
||||||
this->device = device;
|
private:
|
||||||
this->copyQueue = copyQueue;
|
uint16_t *heightdata;
|
||||||
};
|
uint32_t dim;
|
||||||
|
uint32_t scale;
|
||||||
|
|
||||||
~HeightMap()
|
vks::VulkanDevice *device = nullptr;
|
||||||
{
|
VkQueue copyQueue = VK_NULL_HANDLE;
|
||||||
vertexBuffer.destroy();
|
public:
|
||||||
indexBuffer.destroy();
|
enum Topology { topologyTriangles, topologyQuads };
|
||||||
delete[] heightdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getHeight(uint32_t x, uint32_t y)
|
float heightScale = 1.0f;
|
||||||
{
|
float uvScale = 1.0f;
|
||||||
glm::ivec2 rpos = glm::ivec2(x, y) * glm::ivec2(scale);
|
|
||||||
rpos.x = std::max(0, std::min(rpos.x, (int)dim - 1));
|
|
||||||
rpos.y = std::max(0, std::min(rpos.y, (int)dim - 1));
|
|
||||||
rpos /= glm::ivec2(scale);
|
|
||||||
return *(heightdata + (rpos.x + rpos.y * dim) * scale) / 65535.0f * heightScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
vks::Buffer vertexBuffer;
|
||||||
void loadFromFile(const std::string filename, uint32_t patchsize, glm::vec3 scale, Topology topology, AAssetManager* assetManager)
|
vks::Buffer indexBuffer;
|
||||||
#else
|
|
||||||
void loadFromFile(const std::string filename, uint32_t patchsize, glm::vec3 scale, Topology topology)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
assert(device);
|
|
||||||
assert(copyQueue != VK_NULL_HANDLE);
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
struct Vertex {
|
||||||
AAsset* asset = AAssetManager_open(assetManager, filename.c_str(), AASSET_MODE_STREAMING);
|
glm::vec3 pos;
|
||||||
assert(asset);
|
glm::vec3 normal;
|
||||||
size_t size = AAsset_getLength(asset);
|
glm::vec2 uv;
|
||||||
assert(size > 0);
|
};
|
||||||
void *textureData = malloc(size);
|
|
||||||
AAsset_read(asset, textureData, size);
|
|
||||||
AAsset_close(asset);
|
|
||||||
gli::texture2d heightTex(gli::load((const char*)textureData, size));
|
|
||||||
free(textureData);
|
|
||||||
#else
|
|
||||||
gli::texture2d heightTex(gli::load(filename));
|
|
||||||
#endif
|
|
||||||
dim = static_cast<uint32_t>(heightTex.extent().x);
|
|
||||||
heightdata = new uint16_t[dim * dim];
|
|
||||||
memcpy(heightdata, heightTex.data(), heightTex.size());
|
|
||||||
this->scale = dim / patchsize;
|
|
||||||
this->heightScale = scale.y;
|
|
||||||
|
|
||||||
// Generate vertices
|
size_t vertexBufferSize = 0;
|
||||||
|
size_t indexBufferSize = 0;
|
||||||
|
uint32_t indexCount = 0;
|
||||||
|
|
||||||
Vertex * vertices = new Vertex[patchsize * patchsize * 4];
|
HeightMap(vks::VulkanDevice *device, VkQueue copyQueue)
|
||||||
|
|
||||||
const float wx = 2.0f;
|
|
||||||
const float wy = 2.0f;
|
|
||||||
|
|
||||||
for (uint32_t x = 0; x < patchsize; x++)
|
|
||||||
{
|
{
|
||||||
for (uint32_t y = 0; y < patchsize; y++)
|
this->device = device;
|
||||||
{
|
this->copyQueue = copyQueue;
|
||||||
uint32_t index = (x + y * patchsize);
|
};
|
||||||
vertices[index].pos[0] = (x * wx + wx / 2.0f - (float)patchsize * wx / 2.0f) * scale.x;
|
|
||||||
vertices[index].pos[1] = -getHeight(x, y);
|
~HeightMap()
|
||||||
vertices[index].pos[2] = (y * wy + wy / 2.0f - (float)patchsize * wy / 2.0f) * scale.z;
|
{
|
||||||
vertices[index].uv = glm::vec2((float)x / patchsize, (float)y / patchsize) * uvScale;
|
vertexBuffer.destroy();
|
||||||
}
|
indexBuffer.destroy();
|
||||||
|
delete[] heightdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t y = 0; y < patchsize; y++)
|
float getHeight(uint32_t x, uint32_t y)
|
||||||
{
|
{
|
||||||
|
glm::ivec2 rpos = glm::ivec2(x, y) * glm::ivec2(scale);
|
||||||
|
rpos.x = std::max(0, std::min(rpos.x, (int)dim - 1));
|
||||||
|
rpos.y = std::max(0, std::min(rpos.y, (int)dim - 1));
|
||||||
|
rpos /= glm::ivec2(scale);
|
||||||
|
return *(heightdata + (rpos.x + rpos.y * dim) * scale) / 65535.0f * heightScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
void loadFromFile(const std::string filename, uint32_t patchsize, glm::vec3 scale, Topology topology, AAssetManager* assetManager)
|
||||||
|
#else
|
||||||
|
void loadFromFile(const std::string filename, uint32_t patchsize, glm::vec3 scale, Topology topology)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
assert(device);
|
||||||
|
assert(copyQueue != VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
AAsset* asset = AAssetManager_open(assetManager, filename.c_str(), AASSET_MODE_STREAMING);
|
||||||
|
assert(asset);
|
||||||
|
size_t size = AAsset_getLength(asset);
|
||||||
|
assert(size > 0);
|
||||||
|
void *textureData = malloc(size);
|
||||||
|
AAsset_read(asset, textureData, size);
|
||||||
|
AAsset_close(asset);
|
||||||
|
gli::texture2d heightTex(gli::load((const char*)textureData, size));
|
||||||
|
free(textureData);
|
||||||
|
#else
|
||||||
|
gli::texture2d heightTex(gli::load(filename));
|
||||||
|
#endif
|
||||||
|
dim = static_cast<uint32_t>(heightTex.extent().x);
|
||||||
|
heightdata = new uint16_t[dim * dim];
|
||||||
|
memcpy(heightdata, heightTex.data(), heightTex.size());
|
||||||
|
this->scale = dim / patchsize;
|
||||||
|
this->heightScale = scale.y;
|
||||||
|
|
||||||
|
// Generate vertices
|
||||||
|
|
||||||
|
Vertex * vertices = new Vertex[patchsize * patchsize * 4];
|
||||||
|
|
||||||
|
const float wx = 2.0f;
|
||||||
|
const float wy = 2.0f;
|
||||||
|
|
||||||
for (uint32_t x = 0; x < patchsize; x++)
|
for (uint32_t x = 0; x < patchsize; x++)
|
||||||
{
|
{
|
||||||
float dx = getHeight(x < patchsize - 1 ? x + 1 : x, y) - getHeight(x > 0 ? x - 1 : x, y);
|
for (uint32_t y = 0; y < patchsize; y++)
|
||||||
if (x == 0 || x == patchsize - 1)
|
{
|
||||||
dx *= 2.0f;
|
uint32_t index = (x + y * patchsize);
|
||||||
|
vertices[index].pos[0] = (x * wx + wx / 2.0f - (float)patchsize * wx / 2.0f) * scale.x;
|
||||||
float dy = getHeight(x, y < patchsize - 1 ? y + 1 : y) - getHeight(x, y > 0 ? y - 1 : y);
|
vertices[index].pos[1] = -getHeight(x, y);
|
||||||
if (y == 0 || y == patchsize - 1)
|
vertices[index].pos[2] = (y * wy + wy / 2.0f - (float)patchsize * wy / 2.0f) * scale.z;
|
||||||
dy *= 2.0f;
|
vertices[index].uv = glm::vec2((float)x / patchsize, (float)y / patchsize) * uvScale;
|
||||||
|
}
|
||||||
glm::vec3 A = glm::vec3(1.0f, 0.0f, dx);
|
|
||||||
glm::vec3 B = glm::vec3(0.0f, 1.0f, dy);
|
|
||||||
|
|
||||||
glm::vec3 normal = (glm::normalize(glm::cross(A, B)) + 1.0f) * 0.5f;
|
|
||||||
|
|
||||||
vertices[x + y * patchsize].normal = glm::vec3(normal.x, normal.z, normal.y);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Generate indices
|
for (uint32_t y = 0; y < patchsize; y++)
|
||||||
|
{
|
||||||
|
for (uint32_t x = 0; x < patchsize; x++)
|
||||||
|
{
|
||||||
|
float dx = getHeight(x < patchsize - 1 ? x + 1 : x, y) - getHeight(x > 0 ? x - 1 : x, y);
|
||||||
|
if (x == 0 || x == patchsize - 1)
|
||||||
|
dx *= 2.0f;
|
||||||
|
|
||||||
const uint32_t w = (patchsize - 1);
|
float dy = getHeight(x, y < patchsize - 1 ? y + 1 : y) - getHeight(x, y > 0 ? y - 1 : y);
|
||||||
uint32_t *indices;
|
if (y == 0 || y == patchsize - 1)
|
||||||
|
dy *= 2.0f;
|
||||||
switch (topology)
|
|
||||||
{
|
glm::vec3 A = glm::vec3(1.0f, 0.0f, dx);
|
||||||
// Indices for triangles
|
glm::vec3 B = glm::vec3(0.0f, 1.0f, dy);
|
||||||
|
|
||||||
|
glm::vec3 normal = (glm::normalize(glm::cross(A, B)) + 1.0f) * 0.5f;
|
||||||
|
|
||||||
|
vertices[x + y * patchsize].normal = glm::vec3(normal.x, normal.z, normal.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate indices
|
||||||
|
|
||||||
|
const uint32_t w = (patchsize - 1);
|
||||||
|
uint32_t *indices;
|
||||||
|
|
||||||
|
switch (topology)
|
||||||
|
{
|
||||||
|
// Indices for triangles
|
||||||
case topologyTriangles:
|
case topologyTriangles:
|
||||||
{
|
{
|
||||||
indices = new uint32_t[w * w * 6];
|
indices = new uint32_t[w * w * 6];
|
||||||
|
|
@ -183,72 +185,73 @@ namespace vkTools
|
||||||
indexBufferSize = (w * w * 4) * sizeof(uint32_t);
|
indexBufferSize = (w * w * 4) * sizeof(uint32_t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(indexBufferSize > 0);
|
||||||
|
|
||||||
|
vertexBufferSize = (patchsize * patchsize * 4) * sizeof(Vertex);
|
||||||
|
|
||||||
|
// Generate Vulkan buffers
|
||||||
|
|
||||||
|
vks::Buffer vertexStaging, indexStaging;
|
||||||
|
|
||||||
|
// Create staging buffers
|
||||||
|
device->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
&vertexStaging,
|
||||||
|
vertexBufferSize,
|
||||||
|
vertices);
|
||||||
|
|
||||||
|
device->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
&indexStaging,
|
||||||
|
indexBufferSize,
|
||||||
|
indices);
|
||||||
|
|
||||||
|
// Device local (target) buffer
|
||||||
|
device->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
|
&vertexBuffer,
|
||||||
|
vertexBufferSize);
|
||||||
|
|
||||||
|
device->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
|
&indexBuffer,
|
||||||
|
indexBufferSize);
|
||||||
|
|
||||||
|
// Copy from staging buffers
|
||||||
|
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
|
|
||||||
|
VkBufferCopy copyRegion = {};
|
||||||
|
|
||||||
|
copyRegion.size = vertexBufferSize;
|
||||||
|
vkCmdCopyBuffer(
|
||||||
|
copyCmd,
|
||||||
|
vertexStaging.buffer,
|
||||||
|
vertexBuffer.buffer,
|
||||||
|
1,
|
||||||
|
©Region);
|
||||||
|
|
||||||
|
copyRegion.size = indexBufferSize;
|
||||||
|
vkCmdCopyBuffer(
|
||||||
|
copyCmd,
|
||||||
|
indexStaging.buffer,
|
||||||
|
indexBuffer.buffer,
|
||||||
|
1,
|
||||||
|
©Region);
|
||||||
|
|
||||||
|
device->flushCommandBuffer(copyCmd, copyQueue, true);
|
||||||
|
|
||||||
|
vkDestroyBuffer(device->logicalDevice, vertexStaging.buffer, nullptr);
|
||||||
|
vkFreeMemory(device->logicalDevice, vertexStaging.memory, nullptr);
|
||||||
|
vkDestroyBuffer(device->logicalDevice, indexStaging.buffer, nullptr);
|
||||||
|
vkFreeMemory(device->logicalDevice, indexStaging.memory, nullptr);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
assert(indexBufferSize > 0);
|
}
|
||||||
|
|
||||||
vertexBufferSize = (patchsize * patchsize * 4) * sizeof(Vertex);
|
|
||||||
|
|
||||||
// Generate Vulkan buffers
|
|
||||||
|
|
||||||
vks::Buffer vertexStaging, indexStaging;
|
|
||||||
|
|
||||||
// Create staging buffers
|
|
||||||
device->createBuffer(
|
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
||||||
&vertexStaging,
|
|
||||||
vertexBufferSize,
|
|
||||||
vertices);
|
|
||||||
|
|
||||||
device->createBuffer(
|
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
||||||
&indexStaging,
|
|
||||||
indexBufferSize,
|
|
||||||
indices);
|
|
||||||
|
|
||||||
// Device local (target) buffer
|
|
||||||
device->createBuffer(
|
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
||||||
&vertexBuffer,
|
|
||||||
vertexBufferSize);
|
|
||||||
|
|
||||||
device->createBuffer(
|
|
||||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
||||||
&indexBuffer,
|
|
||||||
indexBufferSize);
|
|
||||||
|
|
||||||
// Copy from staging buffers
|
|
||||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
|
||||||
|
|
||||||
VkBufferCopy copyRegion = {};
|
|
||||||
|
|
||||||
copyRegion.size = vertexBufferSize;
|
|
||||||
vkCmdCopyBuffer(
|
|
||||||
copyCmd,
|
|
||||||
vertexStaging.buffer,
|
|
||||||
vertexBuffer.buffer,
|
|
||||||
1,
|
|
||||||
©Region);
|
|
||||||
|
|
||||||
copyRegion.size = indexBufferSize;
|
|
||||||
vkCmdCopyBuffer(
|
|
||||||
copyCmd,
|
|
||||||
indexStaging.buffer,
|
|
||||||
indexBuffer.buffer,
|
|
||||||
1,
|
|
||||||
©Region);
|
|
||||||
|
|
||||||
device->flushCommandBuffer(copyCmd, copyQueue, true);
|
|
||||||
|
|
||||||
vkDestroyBuffer(device->logicalDevice, vertexStaging.buffer, nullptr);
|
|
||||||
vkFreeMemory(device->logicalDevice, vertexStaging.memory, nullptr);
|
|
||||||
vkDestroyBuffer(device->logicalDevice, indexStaging.buffer, nullptr);
|
|
||||||
vkFreeMemory(device->logicalDevice, indexStaging.memory, nullptr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ public:
|
||||||
vks::Texture2D source;
|
vks::Texture2D source;
|
||||||
} textures;
|
} textures;
|
||||||
|
|
||||||
vkTools::HeightMap *heightMap = nullptr;
|
vks::utils::HeightMap *heightMap = nullptr;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
VkPipelineVertexInputStateCreateInfo inputState;
|
VkPipelineVertexInputStateCreateInfo inputState;
|
||||||
|
|
@ -660,11 +660,11 @@ public:
|
||||||
// Generate a terrain quad patch for feeding to the tessellation control shader
|
// Generate a terrain quad patch for feeding to the tessellation control shader
|
||||||
void generateTerrain()
|
void generateTerrain()
|
||||||
{
|
{
|
||||||
heightMap = new vkTools::HeightMap(vulkanDevice, queue);
|
heightMap = new vks::utils::HeightMap(vulkanDevice, queue);
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
heightMap->loadFromFile(getAssetPath() + "textures/terrain_heightmap_r16.ktx", 128, glm::vec3(2.0f, 48.0f, 2.0f), vkTools::HeightMap::topologyTriangles, androidApp->activity->assetManager);
|
heightMap->loadFromFile(getAssetPath() + "textures/terrain_heightmap_r16.ktx", 128, glm::vec3(2.0f, 48.0f, 2.0f), vks::utils::HeightMap::topologyTriangles, androidApp->activity->assetManager);
|
||||||
#else
|
#else
|
||||||
heightMap->loadFromFile(getAssetPath() + "textures/terrain_heightmap_r16.ktx", 128, glm::vec3(2.0f, 48.0f, 2.0f), vkTools::HeightMap::topologyTriangles);
|
heightMap->loadFromFile(getAssetPath() + "textures/terrain_heightmap_r16.ktx", 128, glm::vec3(2.0f, 48.0f, 2.0f), vks::utils::HeightMap::topologyTriangles);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue