Skip to content

Commit

Permalink
Merge pull request #45 from egorodet/develop
Browse files Browse the repository at this point in the history
Asteroids sample single-threaded rendering is ready, addressable resource bindings, texture arrays and mip-maps, advanced multi-subset mesh rendering extensions and several runtime optimisations
  • Loading branch information
egorodet authored Dec 7, 2019
2 parents 3d09730 + 008e046 commit 51ecc74
Show file tree
Hide file tree
Showing 193 changed files with 5,573 additions and 2,685 deletions.
1 change: 1 addition & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

245 changes: 245 additions & 0 deletions Apps/Samples/Asteroids/Asteroid.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
/******************************************************************************
Copyright 2019 Evgeny Gorodetskiy
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*******************************************************************************
FILE: Asteroid.cpp
Random generated asteroid model with mesh and texture ready for rendering
******************************************************************************/

#include "Asteroid.h"

#include <Methane/Graphics/Noise.hpp>
#include <Methane/Data/Instrumentation.h>

#include <sstream>

namespace Methane::Samples
{

using AsteroidColorSchema = std::array<gfx::Color3f, Asteroid::color_schema_size>;

static gfx::Color3f TransformSRGBToLinear(const gfx::Color3f& srgb_color)
{
ITT_FUNCTION_TASK();

gfx::Color3f linear_color = {};
for (int c = 0; c < 3; ++c)
{
linear_color[c] = std::powf(srgb_color[c] / 255.f, 2.2f);
}
return linear_color;
}

static AsteroidColorSchema TransformSRGBToLinear(const AsteroidColorSchema& srgb_color_schema)
{
ITT_FUNCTION_TASK();

AsteroidColorSchema linear_color_schema = {};
for (size_t i = 0; i < srgb_color_schema.size(); ++i)
{
linear_color_schema[i] = TransformSRGBToLinear(srgb_color_schema[i]);
}
return linear_color_schema;
}

Asteroid::Mesh::Mesh(uint32_t subdivisions_count, bool randomize)
: gfx::IcosahedronMesh<Vertex>(VertexLayoutFromArray(Vertex::layout), 0.5f, subdivisions_count, true)
{
ITT_FUNCTION_TASK();

if (randomize)
{
Randomize();
}
}

void Asteroid::Mesh::Randomize(uint32_t random_seed)
{
ITT_FUNCTION_TASK();

const float noise_scale = 0.5f;
const float radius_scale = 1.8f;
const float radius_bias = 0.3f;

std::mt19937 rng(random_seed);

auto random_persistence = std::normal_distribution<float>(0.95f, 0.04f);
const gfx::NoiseOctaves<4> perlin_noise(random_persistence(rng));

auto random_noise = std::uniform_real_distribution<float>(0.0f, 10000.0f);
const float noise = random_noise(rng);

m_depth_range[0] = std::numeric_limits<float>::max();
m_depth_range[1] = std::numeric_limits<float>::min();

for (Vertex& vertex : m_vertices)
{
vertex.position *= perlin_noise(gfx::Vector4f(vertex.position * noise_scale, noise)) * radius_scale + radius_bias;

const float vertex_depth = vertex.position.length();
m_depth_range[0] = std::min(m_depth_range[0], vertex_depth);
m_depth_range[1] = std::max(m_depth_range[1], vertex_depth);
}

ComputeAverageNormals();
}

Asteroid::Asteroid(gfx::Context& context)
: BaseBuffers(context, Mesh(3, true), "Asteroid")
{
ITT_FUNCTION_TASK();

SetSubsetTexture(GenerateTextureArray(context, gfx::Dimensions(256, 256), 1, true, TextureNoiseParameters()), 0);
}

gfx::Texture::Ptr Asteroid::GenerateTextureArray(gfx::Context& context, const gfx::Dimensions& dimensions, uint32_t array_size, bool mipmapped,
const TextureNoiseParameters& noise_parameters)
{
ITT_FUNCTION_TASK();

const gfx::Resource::SubResources sub_resources = GenerateTextureArraySubresources(dimensions, array_size, noise_parameters);
gfx::Texture::Ptr sp_texture_array = gfx::Texture::CreateImage(context, dimensions, array_size, gfx::PixelFormat::RGBA8Unorm, mipmapped);
sp_texture_array->SetData(sub_resources);
return sp_texture_array;
}

gfx::Resource::SubResources Asteroid::GenerateTextureArraySubresources(const gfx::Dimensions& dimensions, uint32_t array_size, const TextureNoiseParameters& noise_parameters)
{
ITT_FUNCTION_TASK();

const gfx::PixelFormat pixel_format = gfx::PixelFormat::RGBA8Unorm;
const uint32_t pixel_size = gfx::GetPixelSize(pixel_format);
const uint32_t pixels_count = dimensions.GetPixelsCount();
const uint32_t row_stide = pixel_size * dimensions.width;

gfx::Resource::SubResources sub_resources;
sub_resources.reserve(array_size);

std::mt19937 rng(noise_parameters.random_seed);
std::uniform_real_distribution<float> noise_seed_distribution(0.f, 10000.f);

for (uint32_t array_index = 0; array_index < array_size; ++array_index)
{
Data::Bytes sub_resource_data(pixels_count * pixel_size, 255u);
FillPerlinNoiseToTexture(sub_resource_data, dimensions,
pixel_size, row_stide,
noise_seed_distribution(rng),
noise_parameters.persistence,
noise_parameters.scale,
noise_parameters.strength,
array_index);

sub_resources.emplace_back(std::move(sub_resource_data), gfx::Resource::SubResource::Index{ 0, array_index });
}

return sub_resources;
}

Asteroid::Colors Asteroid::GetAsteroidRockColors(uint32_t deep_color_index, uint32_t shallow_color_index)
{
ITT_FUNCTION_TASK();

static const AsteroidColorSchema s_srgb_deep_rock_colors = { {
{ 55.f, 49.f, 40.f },
{ 58.f, 38.f, 14.f },
{ 98.f, 101.f, 104.f },
{ 205.f, 197.f, 178.f },
{ 88.f, 88.f, 88.f },
{ 148.f, 108.f, 102.f },
} };
static const AsteroidColorSchema s_linear_deep_rock_colors = TransformSRGBToLinear(s_srgb_deep_rock_colors);

static const AsteroidColorSchema s_srgb_shallow_rock_colors = { {
{ 156.f, 139.f, 113.f },
{ 198.f, 188.f, 137.f },
{ 239.f, 222.f, 191.f },
{ 239.f, 213.f, 198.f },
{ 153.f, 146.f, 136.f },
{ 189.f, 181.f, 164.f },
} };
static const AsteroidColorSchema s_linear_shallow_rock_colors = TransformSRGBToLinear(s_srgb_shallow_rock_colors);

if (deep_color_index >= s_linear_deep_rock_colors.size() ||
shallow_color_index >= s_linear_shallow_rock_colors.size())
throw std::invalid_argument("Deep or shallow color indices are out of boundaries for asteroids color schema.");

return Asteroid::Colors{ s_linear_deep_rock_colors[deep_color_index], s_linear_shallow_rock_colors[shallow_color_index] };
}

Asteroid::Colors Asteroid::GetAsteroidIceColors(uint32_t deep_color_index, uint32_t shallow_color_index)
{
ITT_FUNCTION_TASK();

static const AsteroidColorSchema s_srgb_deep_ice_colors = { {
{ 8.f, 57.f, 72.f },
{ 35.f, 79.f, 116.f },
{ 7.f, 25.f, 27.f },
{ 55.f, 116.f, 161.f },
{ 16.f, 66.f, 66.f },
{ 48.f, 103.f, 147.f }
} };
static const AsteroidColorSchema s_linear_deep_ice_colors = TransformSRGBToLinear(s_srgb_deep_ice_colors);

static const AsteroidColorSchema s_srgb_shallow_ice_colors = { {
{ 199.f, 212.f, 244.f },
{ 196.f, 227.f, 239.f },
{ 133.f, 177.f, 222.f },
{ 133.f, 186.f, 230.f },
{ 167.f, 212.f, 239.f },
{ 200.f, 221.f, 252.f }
} };
static const AsteroidColorSchema s_linear_shallow_ice_colors = TransformSRGBToLinear(s_srgb_shallow_ice_colors);

if (deep_color_index >= s_linear_deep_ice_colors.size() ||
shallow_color_index >= s_linear_shallow_ice_colors.size())
throw std::invalid_argument("Deep or shallow color indices are out of boundaries for asteroids color schema.");

return Asteroid::Colors{ s_linear_deep_ice_colors[deep_color_index], s_linear_shallow_ice_colors[shallow_color_index] };
}

void Asteroid::FillPerlinNoiseToTexture(Data::Bytes& texture_data, const gfx::Dimensions& dimensions, uint32_t pixel_size, uint32_t row_stride,
float random_seed, float persistence, float noise_scale, float noise_strength, uint32_t array_index)
{
ITT_FUNCTION_TASK();

const gfx::NoiseOctaves<4> perlin_noise(persistence);

for (size_t row = 0; row < dimensions.height; ++row)
{
uint32_t* row_data = reinterpret_cast<uint32_t*>(texture_data.data() + row * row_stride);

for (size_t col = 0; col < dimensions.width; ++col)
{
const gfx::Vector3f noise_coordinates(noise_scale * row, noise_scale * col, random_seed);
const float noise_intensity = std::max(0.0f, std::min(1.0f, (perlin_noise(noise_coordinates) - 0.5f) * noise_strength + 0.5f));

uint8_t* texel_data = reinterpret_cast<uint8_t*>(&row_data[col]);
for (size_t channel = 0; channel < 3; ++channel)
{
#if 1
const float channel_value = 255.f;
#else
const float channel_value = array_index % 3 == channel ? 255.f : 125.f;
#endif
texel_data[channel] = static_cast<uint8_t>(channel_value * noise_intensity);
}
}
}
}

} // namespace Methane::Samples
117 changes: 117 additions & 0 deletions Apps/Samples/Asteroids/Asteroid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/******************************************************************************
Copyright 2019 Evgeny Gorodetskiy
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*******************************************************************************
FILE: Asteroid.h
Random generated asteroid model with mesh and texture ready for rendering.
******************************************************************************/

#pragma once

#include <Methane/Graphics/Context.h>
#include <Methane/Graphics/MathTypes.h>
#include <Methane/Graphics/MeshBuffers.hpp>

namespace Methane::Samples
{

namespace gfx = Graphics;

struct SHADER_STRUCT_ALIGN AsteroidUniforms
{
SHADER_FIELD_ALIGN gfx::Matrix44f model_matrix;
SHADER_FIELD_ALIGN gfx::Matrix44f mvp_matrix;
SHADER_FIELD_ALIGN gfx::Color3f deep_color;
SHADER_FIELD_ALIGN gfx::Color3f shallow_color;
SHADER_FIELD_ALIGN gfx::Vector2f depth_range;
};

class Asteroid final : public gfx::TexturedMeshBuffers<AsteroidUniforms>
{
public:
using Ptr = std::unique_ptr<Asteroid>;
using BaseBuffers = gfx::TexturedMeshBuffers<AsteroidUniforms>;

struct Vertex
{
gfx::Mesh::Position position;
gfx::Mesh::Normal normal;

static constexpr const std::array<gfx::Mesh::VertexField, 2> layout = {
gfx::Mesh::VertexField::Position,
gfx::Mesh::VertexField::Normal,
};
};

class Mesh : public gfx::IcosahedronMesh<Vertex>
{
public:
Mesh(uint32_t subdivisions_count, bool randomize);

void Randomize(uint32_t random_seed = 1337);

const gfx::Vector2f& GetDepthRange() const { return m_depth_range; }

private:
gfx::Vector2f m_depth_range;
};

struct Colors
{
gfx::Color3f deep;
gfx::Color3f shallow;
};

struct Parameters
{
const uint32_t index;
const uint32_t subset_index;
const gfx::Vector2f depth_range;
const Colors colors;
const gfx::Matrix44f scale_matrix;
const gfx::Matrix44f translation_matrix;
const gfx::Point3f spin_axis;
const float orbit_speed;
const float spin_speed;
float spin_angle_rad;
float orbit_angle_rad;
};

struct TextureNoiseParameters
{
uint32_t random_seed = 0;
float persistence = 0.9f;
float scale = 0.5f;
float strength = 1.5f;
};

Asteroid(gfx::Context& context);

static gfx::Texture::Ptr GenerateTextureArray(gfx::Context& context, const gfx::Dimensions& dimensions, uint32_t array_size, bool mipmapped, const TextureNoiseParameters& noise_parameters);
static gfx::Resource::SubResources GenerateTextureArraySubresources(const gfx::Dimensions& dimensions, uint32_t array_size, const TextureNoiseParameters& noise_parameters);

static constexpr size_t color_schema_size = 6u;
static Colors GetAsteroidRockColors(uint32_t deep_color_index, uint32_t shallow_color_index);
static Colors GetAsteroidIceColors(uint32_t deep_color_index, uint32_t shallow_color_index);

private:
static void FillPerlinNoiseToTexture(Data::Bytes& texture_data, const gfx::Dimensions& dimensions, uint32_t pixel_size, uint32_t row_stride,
float random_seed, float persistence, float noise_scale, float noise_strength, uint32_t array_index);
};

} // namespace Methane::Samples
Loading

0 comments on commit 51ecc74

Please sign in to comment.