Skip to content

Commit

Permalink
Start adding support for multi-layer ocean refraction.
Browse files Browse the repository at this point in the history
  • Loading branch information
Hans-Kristian Arntzen committed Oct 6, 2018
1 parent ae31fae commit 1a4a44b
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 49 deletions.
61 changes: 49 additions & 12 deletions assets/shaders/ocean/ocean.frag
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,28 @@ layout(set = 2, binding = 3) uniform mediump sampler2D uNormal;
#if VARIANT_BIT_1
#include "../inc/render_parameters.h"
#include "../inc/bandlimited_pixel_filter.h"
layout(set = 2, binding = 4) uniform mediump sampler2D uDirectRefraction;

layout(set = 2, binding = 5, std140) uniform Refraction
// sampler2DArray makes way more sense here. TODO: Add support for layers in render graph.
layout(set = 2, binding = 4) uniform mediump sampler2D uDirectRefraction0;
layout(set = 2, binding = 5) uniform mediump sampler2D uDirectRefraction1;
layout(set = 2, binding = 6) uniform mediump sampler2D uDirectRefraction2;
layout(set = 2, binding = 7) uniform mediump sampler2D uDirectRefraction3;

layout(set = 2, binding = 8, std140) uniform Refraction
{
vec4 refraction_size;
vec4 refraction_depths;
float refraction_uv_scale;
float refraction_depth;
float refraction_emissive_mod;
};

mediump vec3 merge_emissive_layers(mediump vec4 layer0, mediump vec4 layer1, mediump vec4 layer2, mediump vec4 layer3)
{
mediump vec3 merged = mix(layer2.rgb, layer3.rgb, layer2.a);
merged = mix(layer1.rgb, merged, layer1.a);
merged = mix(layer0.rgb, merged, layer0.a);
return merged;
}
#endif

void main()
Expand All @@ -46,7 +59,10 @@ void main()

#if VARIANT_BIT_1
mediump vec3 to_ocean = normalize(vPos - global.camera_position);
vec2 uv = vPos.xz * refraction_uv_scale;
vec2 uv0 = vPos.xz * refraction_uv_scale;
vec2 uv1 = uv0;
vec2 uv2 = uv0;
vec2 uv3 = uv0;

mediump vec3 refracted_dir = refract(to_ocean, normal, 1.0 / 1.33);
mediump float dir_to_bottom = -refracted_dir.y;
Expand All @@ -59,17 +75,38 @@ void main()

if (dir_to_bottom > 0.0)
{
mediump vec2 refracted_xz_offset = refracted_dir.xz * ((refraction_depth + vPos.y) / dir_to_bottom);
mediump vec3 refracted_pos_offset = vec3(refracted_xz_offset.x, vPos.y + refraction_depth, refracted_xz_offset.y);
mediump float fade_length = length(refracted_pos_offset);
uv = refraction_uv_scale * (refracted_xz_offset + vPos.xz);
mediump vec2 refracted_xz_offset;
mediump vec4 depths = (refraction_depths + vPos.y) / dir_to_bottom;
refracted_xz_offset = refracted_dir.xz * depths.x;
uv0 = refraction_uv_scale * (refracted_xz_offset + vPos.xz);
refracted_xz_offset = refracted_dir.xz * depths.y;
uv1 = refraction_uv_scale * (refracted_xz_offset + vPos.xz);
refracted_xz_offset = refracted_dir.xz * depths.z;
uv2 = refraction_uv_scale * (refracted_xz_offset + vPos.xz);
refracted_xz_offset = refracted_dir.xz * depths.w;
uv3 = refraction_uv_scale * (refracted_xz_offset + vPos.xz);
}

#if VARIANT_BIT_2
BandlimitedPixelInfo info =
compute_pixel_weights(uv, refraction_size.xy, refraction_size.zw, exp2(3.0 * turbulence));
mediump vec3 emissive = refraction_emissive_mod * sample_bandlimited_pixel(uDirectRefraction, uv, info, 3.0 * turbulence).rgb;
mediump float turbulence_extent_mod = exp2(2.0 * turbulence);
BandlimitedPixelInfo info;

info = compute_pixel_weights(uv0, refraction_size.xy, refraction_size.zw, turbulence_extent_mod);
mediump vec4 emissive0 = sample_bandlimited_pixel(uDirectRefraction0, uv0, info, 2.0 * turbulence);
info = compute_pixel_weights(uv1, refraction_size.xy, refraction_size.zw, turbulence_extent_mod);
mediump vec4 emissive1 = sample_bandlimited_pixel(uDirectRefraction1, uv1, info, 2.0 * turbulence);
info = compute_pixel_weights(uv2, refraction_size.xy, refraction_size.zw, turbulence_extent_mod);
mediump vec4 emissive2 = sample_bandlimited_pixel(uDirectRefraction2, uv2, info, 2.0 * turbulence);
info = compute_pixel_weights(uv3, refraction_size.xy, refraction_size.zw, turbulence_extent_mod);
mediump vec4 emissive3 = sample_bandlimited_pixel(uDirectRefraction3, uv3, info, 2.0 * turbulence);

mediump vec3 emissive = refraction_emissive_mod * merge_emissive_layers(emissive0, emissive1, emissive2, emissive3);
#else
mediump vec3 emissive = refraction_emissive_mod * texture(uDirectRefraction, uv, 3.0 * turbulence).rgb;
mediump vec4 emissive0 = texture(uDirectRefraction0, uv0, 2.0 * turbulence);
mediump vec4 emissive1 = texture(uDirectRefraction1, uv1, 2.0 * turbulence);
mediump vec4 emissive2 = texture(uDirectRefraction2, uv2, 2.0 * turbulence);
mediump vec4 emissive3 = texture(uDirectRefraction3, uv3, 2.0 * turbulence);
mediump vec3 emissive = refraction_emissive_mod * merge_emissive_layers(emissive0, emissive1, emissive2, emissive3);
#endif
#else
const mediump vec3 emissive = vec3(0.0);
Expand Down
4 changes: 4 additions & 0 deletions assets/shaders/sprite.frag
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,8 @@ void main()
#endif
Color = color;
#endif

#if defined(VARIANT_BIT_3)
Color.a = 0.0;
#endif
}
88 changes: 56 additions & 32 deletions renderer/ocean.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,13 @@ void Ocean::setup_render_pass_dependencies(RenderGraph &, RenderPass &target)
target.add_texture_input("ocean-gradient-jacobian-output", VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
target.add_texture_input("ocean-normal-fft-output", VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);

if (!config.refraction.input.empty() && config.refraction.input_is_render_graph)
refraction_resource = &target.add_texture_input(config.refraction.input);
else
refraction_resource = nullptr;
for (unsigned i = 0; i < OceanLayers; i++)
{
if (!config.refraction.inputs[i].empty() && config.refraction.input_is_render_graph)
refraction_resources[i] = &target.add_texture_input(config.refraction.inputs[i]);
else
refraction_resources[i] = nullptr;
}
}

void Ocean::setup_render_pass_resources(RenderGraph &graph)
Expand Down Expand Up @@ -255,18 +258,21 @@ void Ocean::setup_render_pass_resources(RenderGraph &graph)
displacement_fft->process(&deferred_cmd, &displacement_output, &displacement_input);
}

refraction = nullptr;
if (!config.refraction.input.empty())
for (unsigned i = 0; i < OceanLayers; i++)
{
if (config.refraction.input_is_render_graph)
{
refraction = &graph.get_physical_texture_resource(*refraction_resource);
}
else
refractions[i] = nullptr;
if (!config.refraction.inputs[i].empty())
{
auto *texture = graph.get_device().get_texture_manager().request_texture(config.refraction.input);
if (texture)
refraction = &texture->get_image()->get_view();
if (config.refraction.input_is_render_graph)
{
refractions[i] = &graph.get_physical_texture_resource(*refraction_resources[i]);
}
else
{
auto *texture = graph.get_device().get_texture_manager().request_texture(config.refraction.inputs[i]);
if (texture)
refractions[i] = &texture->get_image()->get_view();
}
}
}
}
Expand Down Expand Up @@ -704,8 +710,8 @@ struct OceanData
struct RefractionData
{
vec4 texture_size;
vec4 depths;
float uv_scale;
float depth;
float emissive_mod;
};

Expand All @@ -732,7 +738,7 @@ struct OceanInfo
unsigned lod_stride;
OceanData data;

const Vulkan::ImageView *refraction;
const Vulkan::ImageView *refractions[OceanLayers];
RefractionData refraction_data;
};

Expand All @@ -757,12 +763,19 @@ static void ocean_render(Vulkan::CommandBuffer &cmd, const RenderQueueData *info
cmd.set_texture(2, 2, *ocean_info.grad_jacobian, Vulkan::StockSampler::TrilinearWrap);
cmd.set_texture(2, 3, *ocean_info.normal, Vulkan::StockSampler::TrilinearWrap);

if (ocean_info.refraction)
bool has_refraction = false;
for (unsigned i = 0; i < 4; i++)
{
cmd.set_texture(2, 4, *ocean_info.refraction, Vulkan::StockSampler::TrilinearWrap);
*cmd.allocate_typed_constant_data<RefractionData>(2, 5, 1) = ocean_info.refraction_data;
if (ocean_info.refractions[i])
{
cmd.set_texture(2, 4 + i, *ocean_info.refractions[i], Vulkan::StockSampler::TrilinearWrap);
has_refraction = true;
}
}

if (has_refraction)
*cmd.allocate_typed_constant_data<RefractionData>(2, 8, 1) = ocean_info.refraction_data;

for (unsigned lod = 0; lod < ocean_info.lods; lod++)
{
cmd.set_uniform_buffer(3, 0, *ocean_info.ubo,
Expand Down Expand Up @@ -803,22 +816,30 @@ void Ocean::get_render_info(const RenderContext &,
hasher.u64(grad_jacobian.get_cookie());
hasher.u64(ubo.get_cookie());
hasher.u64(indirect.get_cookie());
if (refraction)
hasher.u64(refraction->get_cookie());
else
hasher.u32(0);

bool has_refraction = false;
for (unsigned i = 0; i < 4; i++)
{
if (refractions[i])
{
hasher.u64(refractions[i]->get_cookie());
has_refraction = true;
}
else
hasher.u32(0);
}

auto instance_key = hasher.get();

auto *patch_data = queue.push<OceanInfo>(refraction ?
auto *patch_data = queue.push<OceanInfo>(has_refraction ?
Queue::OpaqueEmissive : Queue::Opaque,
instance_key, 1,
RenderFunctions::ocean_render,
nullptr);

if (patch_data)
{
uint32_t refraction_flag = refraction ? 2 : 0;
uint32_t refraction_flag = has_refraction ? 2 : 0;
if (config.refraction.bandlimited_pixel)
refraction_flag |= 4;

Expand Down Expand Up @@ -855,17 +876,20 @@ void Ocean::get_render_info(const RenderContext &,
patch_data->index_type = index_type;
patch_data->border_count = border_count;

patch_data->refraction = refraction;
if (refraction)
memcpy(patch_data->refractions, refractions, sizeof(refractions));
if (has_refraction)
{
patch_data->refraction_data.texture_size = vec4(
float(refraction->get_image().get_width()),
float(refraction->get_image().get_height()),
1.0f / float(refraction->get_image().get_width()),
1.0f / float(refraction->get_image().get_height()));
float(refractions[0]->get_image().get_width()),
float(refractions[0]->get_image().get_height()),
1.0f / float(refractions[0]->get_image().get_width()),
1.0f / float(refractions[0]->get_image().get_height()));

patch_data->refraction_data.uv_scale = config.refraction.uv_scale;
patch_data->refraction_data.depth = config.refraction.depth;

for (unsigned i = 0; i < OceanLayers; i++)
patch_data->refraction_data.depths[i] = config.refraction.depth[i];

patch_data->refraction_data.emissive_mod = config.refraction.emissive_mod;
}

Expand Down
10 changes: 6 additions & 4 deletions renderer/ocean.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ namespace Granite
class RenderTextureResource;
class RenderBufferResource;

static constexpr unsigned OceanLayers = 4;

struct OceanConfig
{
unsigned fft_resolution = 512;
Expand All @@ -49,9 +51,9 @@ struct OceanConfig

struct
{
std::string input;
std::string inputs[OceanLayers];
float uv_scale = 0.01f;
float depth = 3.0f;
float depth[OceanLayers] = { 2.0f, 4.0f, 6.0f, 8.0f };
float emissive_mod = 1.0f;
bool bandlimited_pixel = false;
bool input_is_render_graph = false;
Expand Down Expand Up @@ -187,7 +189,7 @@ class Ocean : public AbstractRenderable,
vec2 heightmap_world_size() const;
vec2 normalmap_world_size() const;

Vulkan::ImageView *refraction = nullptr;
RenderTextureResource *refraction_resource = nullptr;
Vulkan::ImageView *refractions[OceanLayers];
RenderTextureResource *refraction_resources[OceanLayers] = {};
};
}
8 changes: 8 additions & 0 deletions renderer/render_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ RenderTextureResource &RenderPass::add_texture_input(const std::string &name, Vk
res.read_in_pass(index);
res.add_image_usage(VK_IMAGE_USAGE_SAMPLED_BIT);

// Support duplicate add_texture_inputs.
auto itr = find_if(begin(generic_texture), end(generic_texture), [&](const AccessedTextureResource &acc) {
return acc.texture == &res;
});

if (itr != end(generic_texture))
return *itr->texture;

AccessedTextureResource acc;
acc.texture = &res;
acc.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
Expand Down
3 changes: 3 additions & 0 deletions ui/sprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ void Sprite::get_sprite_render_info(const SpriteTransformInfo &transform, Render
hasher.s32(transparent);
hasher.s32(bandlimited_pixel);
hasher.s32(luma_to_alpha);
hasher.s32(clear_alpha_to_zero);
hasher.s32(texture_alt ? 1 : 0);
auto pipe_hash = hasher.get();

Expand Down Expand Up @@ -203,6 +204,8 @@ void Sprite::get_sprite_render_info(const SpriteTransformInfo &transform, Render
flags |= 1 << 1;
if (luma_to_alpha)
flags |= 1 << 2;
if (clear_alpha_to_zero)
flags |= 1 << 3;

sprite.program = suite.get_program(pipeline,
MESH_ATTRIBUTE_POSITION_BIT |
Expand Down
1 change: 1 addition & 0 deletions ui/sprite.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct Sprite : AbstractRenderable
float texture_blending_factor = 0.0f;
bool bandlimited_pixel = false;
bool luma_to_alpha = false;
bool clear_alpha_to_zero = false;

void get_sprite_render_info(const SpriteTransformInfo &transform, RenderQueue &queue) const override;
void get_render_info(const RenderContext &, const CachedSpatialTransformComponent *, RenderQueue &) const override
Expand Down
5 changes: 4 additions & 1 deletion vulkan/command_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1703,7 +1703,10 @@ void CommandBuffer::set_transparent_sprite_state()
state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
state.write_mask = ~0u;

set_blend_factors(VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
// The alpha layer should start at 1 (fully transparent).
// As layers are blended in, the transparency is multiplied with other transparencies (1 - alpha).
set_blend_factors(VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ZERO,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
set_blend_op(VK_BLEND_OP_ADD);

set_dirty(COMMAND_BUFFER_DIRTY_STATIC_STATE_BIT);
Expand Down

0 comments on commit 1a4a44b

Please sign in to comment.