#include #include #include float Terrain::getHeight(int32_t x, int32_t y) { if (x < 0) x += 64; if (y < 0) y += 64; x %= 64; y %= 64; float xf = x; float yf = y; xf /= 64.0; xf *= heightmap_tex->extent.width; yf /= 64.0; yf *= heightmap_tex->extent.height; return static_cast(heightmap_tex->image_data[static_cast(static_cast(yf) * heightmap_tex->extent.width + xf) * 4]) / 256.0f * 15.0f; } Terrain::Terrain(vk::PhysicalDevice phys_dev, vk::Device dev, Texture& tex) : phys_dev(phys_dev), dev(dev) { /* tell Texture() not to free so we can apply our sobel filter */ heightmap_tex = &tex; const auto patch_size = 64_u32; const auto uv_scale = 1.0f; const auto vertex_count = patch_size * patch_size; vertices.resize(vertex_count); for (size_t x = 0; x < patch_size; x++) for (size_t y = 0; y < patch_size; y++) vertices[x + y*patch_size] = (glTFVertex { .pos = glm::vec3( 2.0f * x + 1.0f - patch_size, 0.0f, 2.0f * y + 1.0f - patch_size), .uv = glm::vec2(static_cast(x)/patch_size, static_cast(y) / patch_size) * uv_scale, }); /* use sobel filters to get normal: * X sobel: * +----+----+----+ * | +1 | +0 | -1 | * +----+----+----+ * | +2 | +0 | -2 | * +----+----+----+ * | +1 | +0 | -1 | * +----+----+----+ * Y sobel: * +----+----+----+ * | +1 | +2 | +1 | * +----+----+----+ * | +0 | +0 | +0 | * +----+----+----+ * | -1 | -2 | -1 | * +----+----+----+ */ for(auto x = 0_i32; x < patch_size; x++) for (auto y = 0_i32; y < patch_size; y++) { float moores_heights[3][3] = { { getHeight(x - 1, y - 1), getHeight(x - 1, y), getHeight(x - 1, y + 1) }, { getHeight(x + 0, y - 1), getHeight(x + 0, y), getHeight(x + 0, y + 1) }, { getHeight(x + 1, y - 1), getHeight(x + 1, y), getHeight(x + 1, y + 1) }, }; // auto normal = glm::vec3( // /* x gets X sobel filter */ // moores_heights[0][0] + 2.0f * moores_heights[0][1] + moores_heights[0][2] // - moores_heights[2][0] - 2.0f * moores_heights[2][1] - moores_heights[2][2], // 0.0, // /* z gets Y sobel filter */ // moores_heights[0][0] + 2.0f * moores_heights[1][0] + moores_heights[2][0] // - moores_heights[0][2] - 2.0f * moores_heights[1][2] - moores_heights[2][2] // ); auto relx = glm::vec3(2.0, getHeight(x + 1, y)-getHeight(x, y), 0.0); auto relz = glm::vec3(0.0, getHeight(x, y + 1)-getHeight(x, y), 2.0); auto normal = glm::normalize(glm::cross(relz, relx)); /* fill in missing component, first scalar scales bump */ //normal.y = 0.25 * glm::sqrt(glm::abs(1.0 - normal.x*normal.x - normal.z*normal.z)); //vertices[x + y * patch_size].norm = glm::vec3(getHeight(x, y)); vertices[x + y * patch_size].norm = normal; } vertex_buffer = std::make_unique(phys_dev, dev, vertices.size()); vertex_buffer->upload(vertices); /* index generation */ const auto w = patch_size - 1; indices.resize(w * w * 4); for (auto x = 0_u32; x < w; x++) for (auto y = 0_u32; y < w; y++) { auto idx = (x + y * w) * 4; indices[idx] = x+y*patch_size; indices[idx+1] = indices[idx] + patch_size; indices[idx+2] = indices[idx+1] + 1; indices[idx + 3] = indices[idx] + 1; } index_buffer = std::make_unique(phys_dev, dev, sizeof(uint32_t)*indices.size(), vk::BufferUsageFlagBits::eIndexBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible); index_buffer->upload(indices); } void Terrain::draw(CommandBuffer& cmd) { } Terrain::~Terrain() { index_buffer.reset(); vertex_buffer.reset(); }