Skip to content

Commit

Permalink
interior mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
turanszkij committed Jan 24, 2025
1 parent c0cbd84 commit 32b9694
Show file tree
Hide file tree
Showing 16 changed files with 318 additions and 11 deletions.
59 changes: 58 additions & 1 deletion Editor/MaterialWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,11 +742,53 @@ void MaterialWindow::Create(EditorComponent* _editor)
MaterialComponent* material = get_material(scene, x);
if (material == nullptr)
continue;
material->blend_with_terrain_height = args.fValue;
material->SetBlendWithTerrainHeight(args.fValue);
}
});
AddWidget(&blendTerrainSlider);

interiorScaleXSlider.Create(1, 10, 1, 1000, "Interior Scale X: ");
interiorScaleXSlider.SetTooltip("Set the cubemap scale for the interior mapping (if material uses interior mapping shader)");
interiorScaleXSlider.OnSlide([&](wi::gui::EventArgs args) {
wi::scene::Scene& scene = editor->GetCurrentScene();
for (auto& x : editor->translator.selected)
{
MaterialComponent* material = get_material(scene, x);
if (material == nullptr)
continue;
material->SetInteriorMappingScale(XMFLOAT3(args.fValue, material->interiorMappingScale.y, material->interiorMappingScale.z));
}
});
AddWidget(&interiorScaleXSlider);

interiorScaleYSlider.Create(1, 10, 1, 1000, "Interior Scale Y: ");
interiorScaleYSlider.SetTooltip("Set the cubemap scale for the interior mapping (if material uses interior mapping shader)");
interiorScaleYSlider.OnSlide([&](wi::gui::EventArgs args) {
wi::scene::Scene& scene = editor->GetCurrentScene();
for (auto& x : editor->translator.selected)
{
MaterialComponent* material = get_material(scene, x);
if (material == nullptr)
continue;
material->SetInteriorMappingScale(XMFLOAT3(material->interiorMappingScale.x, args.fValue, material->interiorMappingScale.z));
}
});
AddWidget(&interiorScaleYSlider);

interiorScaleZSlider.Create(1, 10, 1, 1000, "Interior Scale Z: ");
interiorScaleZSlider.SetTooltip("Set the cubemap scale for the interior mapping (if material uses interior mapping shader)");
interiorScaleZSlider.OnSlide([&](wi::gui::EventArgs args) {
wi::scene::Scene& scene = editor->GetCurrentScene();
for (auto& x : editor->translator.selected)
{
MaterialComponent* material = get_material(scene, x);
if (material == nullptr)
continue;
material->SetInteriorMappingScale(XMFLOAT3(material->interiorMappingScale.x, material->interiorMappingScale.y, args.fValue));
}
});
AddWidget(&interiorScaleZSlider);


//
hei = 20;
Expand Down Expand Up @@ -947,6 +989,14 @@ void MaterialWindow::Create(EditorComponent* _editor)
{
const Texture& texture = material->textures[args.iValue].resource.GetTexture();
tooltiptext += "\nResolution: " + std::to_string(texture.desc.width) + " * " + std::to_string(texture.desc.height);
if (texture.desc.array_size > 0)
{
tooltiptext += " * " + std::to_string(texture.desc.array_size);
}
if (has_flag(texture.desc.misc_flags, ResourceMiscFlag::TEXTURECUBE))
{
tooltiptext += " (cubemap)";
}
tooltiptext += "\nMip levels: " + std::to_string(texture.desc.mip_levels);
tooltiptext += "\nFormat: ";
tooltiptext += GetFormatString(texture.desc.format);
Expand Down Expand Up @@ -1115,6 +1165,7 @@ void MaterialWindow::SetEntity(Entity entity)
shaderTypeComboBox.AddItem("Water", MaterialComponent::SHADERTYPE_WATER);
shaderTypeComboBox.AddItem("Cartoon", MaterialComponent::SHADERTYPE_CARTOON);
shaderTypeComboBox.AddItem("Unlit", MaterialComponent::SHADERTYPE_UNLIT);
shaderTypeComboBox.AddItem("Interior", MaterialComponent::SHADERTYPE_INTERIORMAPPING);
for (auto& x : wi::renderer::GetCustomShaders())
{
shaderTypeComboBox.AddItem("*" + x.name);
Expand Down Expand Up @@ -1177,6 +1228,9 @@ void MaterialWindow::SetEntity(Entity entity)
clearcoatSlider.SetValue(material->clearcoat);
clearcoatRoughnessSlider.SetValue(material->clearcoatRoughness);
blendTerrainSlider.SetValue(material->blend_with_terrain_height);
interiorScaleXSlider.SetValue(material->interiorMappingScale.x);
interiorScaleYSlider.SetValue(material->interiorMappingScale.y);
interiorScaleZSlider.SetValue(material->interiorMappingScale.z);

shadingRateComboBox.SetEnabled(wi::graphics::GetDevice()->CheckCapability(GraphicsDeviceCapability::VARIABLE_RATE_SHADING));

Expand Down Expand Up @@ -1289,6 +1343,9 @@ void MaterialWindow::ResizeLayout()
add(clearcoatSlider);
add(clearcoatRoughnessSlider);
add(blendTerrainSlider);
add(interiorScaleXSlider);
add(interiorScaleYSlider);
add(interiorScaleZSlider);
add(colorComboBox);
add_fullwidth(colorPicker);
add(textureSlotComboBox);
Expand Down
3 changes: 3 additions & 0 deletions Editor/MaterialWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ class MaterialWindow : public wi::gui::Window
wi::gui::Slider clearcoatSlider;
wi::gui::Slider clearcoatRoughnessSlider;
wi::gui::Slider blendTerrainSlider;
wi::gui::Slider interiorScaleXSlider;
wi::gui::Slider interiorScaleYSlider;
wi::gui::Slider interiorScaleZSlider;

wi::gui::ComboBox colorComboBox;
wi::gui::ColorPicker colorPicker;
Expand Down
1 change: 1 addition & 0 deletions WickedEngine/shaders/ShaderInterop_Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum IMAGE_FLAGS
IMAGE_FLAG_ANGULAR_INVERSE = 1u << 7u,
IMAGE_FLAG_DISTORTION_MASK = 1u << 8u,
IMAGE_FLAG_HIGHLIGHT = 1u << 9u,
IMAGE_FLAG_CUBEMAP_BASE = 1u << 10u,
};

struct alignas(16) ImageConstants
Expand Down
9 changes: 8 additions & 1 deletion WickedEngine/shaders/ShaderInterop_Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,9 @@ struct alignas(16) ShaderMaterial
uint2 transmission_sheenroughness_clearcoat_clearcoatroughness;
uint2 aniso_anisosin_anisocos_terrainblend;

uint2 interiorscale;
uint2 padding;

int sampler_descriptor;
uint options_stencilref;
uint layerMask;
Expand Down Expand Up @@ -402,6 +405,9 @@ struct alignas(16) ShaderMaterial
transmission_sheenroughness_clearcoat_clearcoatroughness = uint2(0, 0);
aniso_anisosin_anisocos_terrainblend = uint2(0, 0);

interiorscale = uint2(0, 0); // packed half3 + unused half
padding = uint2(0, 0);

sampler_descriptor = -1;
options_stencilref = 0;
layerMask = ~0u;
Expand Down Expand Up @@ -441,6 +447,7 @@ struct alignas(16) ShaderMaterial
inline half GetAnisotropySin() { return unpack_half4(aniso_anisosin_anisocos_terrainblend).y; }
inline half GetAnisotropyCos() { return unpack_half4(aniso_anisosin_anisocos_terrainblend).z; }
inline half GetTerrainBlendRcp() { return unpack_half4(aniso_anisosin_anisocos_terrainblend).w; }
inline half3 GetInteriorScale() { return unpack_half3(interiorscale); }
inline uint GetStencilRef() { return options_stencilref >> 24u; }
#endif // __cplusplus

Expand Down Expand Up @@ -470,7 +477,7 @@ struct alignas(16) ShaderTypeBin
uint4 padding; // 32-byte alignment
#endif // __SCE__ || __PSSL__
};
static const uint SHADERTYPE_BIN_COUNT = 11;
static const uint SHADERTYPE_BIN_COUNT = 12;

struct alignas(16) VisibilityTile
{
Expand Down
121 changes: 121 additions & 0 deletions WickedEngine/shaders/globals.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,44 @@ inline float3 cubemap_to_uv(in float3 r)
return float3((uvw.xy / uvw.z + 1) * 0.5, faceIndex);
}


inline bool is_inside_uv(in float2 uv, in float4 uv_range)
{
return all(uv.xy >= uv_range.xy) && all(uv.xy <= uv_range.zw);
}

static const float4 cubemap_cross_ranges[] = {
float4(0.5, 0.333, 0.75, 0.667), // positive_x
float4(0.0, 0.333, 0.25, 0.667), // negative_x
float4(0.25, 0.0, 0.5, 0.333), // positive_y
float4(0.25, 0.667, 0.5, 1.0), // negative_y
float4(0.25, 0.333, 0.5, 0.667), // positive_z
float4(0.75, 0.333, 1.0, 0.667), // negative_z
};

// From a 2D UV coordinate, returns 3D cubemap sampling UV to sample the cubemap as an unwrapped 2D cross image
// Returns 0 if the input UV doesn't correspond to any face, and a 3D direction vector that can be used to sample a TextureCube otherwise
inline float3 uv_to_cubemap_cross(in float2 uv)
{
float2 cross_uv = 0;
int result_face = -1;
for (int face = 0; face < arraysize(cubemap_cross_ranges); ++face)
{
float4 range = cubemap_cross_ranges[face];
if (is_inside_uv(uv.xy, range))
{
result_face = face;
cross_uv = inverse_lerp(range.xy, range.zw, uv.xy);
break;
}
}

if (result_face >= 0)
return uv_to_cubemap(cross_uv, result_face);

return 0;
}

// Samples a texture with Catmull-Rom filtering, using 9 texture fetches instead of 16. ( https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1#file-tex2dcatmullrom-hlsl )
// See http://vec3.ca/bicubic-filtering-in-fewer-taps/ for more details
float4 SampleTextureCatmullRom(in Texture2D<float4> tex, in SamplerState linearSampler, in float2 uv)
Expand Down Expand Up @@ -2068,4 +2106,87 @@ float3 random_color(uint index)
return random_colors[index % arraysize(random_colors)];
}

// Matrix operations for HLSL: https://gist.github.com/mattatz/86fff4b32d198d0928d0fa4ff32cf6fa
float4x4 inverse(float4x4 m)
{
float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0], n14 = m[3][0];
float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1], n24 = m[3][1];
float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2], n34 = m[3][2];
float n41 = m[0][3], n42 = m[1][3], n43 = m[2][3], n44 = m[3][3];

float t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44;
float t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44;
float t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44;
float t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;

float det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
float idet = 1.0f / det;

float4x4 ret;

ret[0][0] = t11 * idet;
ret[0][1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * idet;
ret[0][2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * idet;
ret[0][3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * idet;

ret[1][0] = t12 * idet;
ret[1][1] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * idet;
ret[1][2] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * idet;
ret[1][3] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * idet;

ret[2][0] = t13 * idet;
ret[2][1] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * idet;
ret[2][2] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * idet;
ret[2][3] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * idet;

ret[3][0] = t14 * idet;
ret[3][1] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * idet;
ret[3][2] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * idet;
ret[3][3] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * idet;

return ret;
}

// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
float4 matrix_to_quaternion(float4x4 m)
{
float tr = m[0][0] + m[1][1] + m[2][2];
float4 q = float4(0, 0, 0, 0);

if (tr > 0)
{
float s = sqrt(tr + 1.0) * 2; // S=4*qw
q.w = 0.25 * s;
q.x = (m[2][1] - m[1][2]) / s;
q.y = (m[0][2] - m[2][0]) / s;
q.z = (m[1][0] - m[0][1]) / s;
}
else if ((m[0][0] > m[1][1]) && (m[0][0] > m[2][2]))
{
float s = sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]) * 2; // S=4*qx
q.w = (m[2][1] - m[1][2]) / s;
q.x = 0.25 * s;
q.y = (m[0][1] + m[1][0]) / s;
q.z = (m[0][2] + m[2][0]) / s;
}
else if (m[1][1] > m[2][2])
{
float s = sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]) * 2; // S=4*qy
q.w = (m[0][2] - m[2][0]) / s;
q.x = (m[0][1] + m[1][0]) / s;
q.y = 0.25 * s;
q.z = (m[1][2] + m[2][1]) / s;
}
else
{
float s = sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]) * 2; // S=4*qz
q.w = (m[1][0] - m[0][1]) / s;
q.x = (m[0][2] + m[2][0]) / s;
q.y = (m[1][2] + m[2][1]) / s;
q.z = 0.25 * s;
}

return q;
}

#endif // WI_SHADER_GLOBALS_HF
16 changes: 15 additions & 1 deletion WickedEngine/shaders/imagePS.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,21 @@ float4 main(VertextoPixel input) : SV_TARGET
[branch]
if (image.texture_base_index >= 0)
{
half4 tex = bindless_textures_half4[descriptor_index(image.texture_base_index)].Sample(sam, uvsets.xy);
half4 tex = 0;

[branch]
if (image.flags & IMAGE_FLAG_CUBEMAP_BASE)
{
float3 cube_dir = uv_to_cubemap_cross(uvsets.xy);
if (any(cube_dir))
{
tex = bindless_cubemaps_half4[descriptor_index(image.texture_base_index)].Sample(sam, cube_dir);
}
}
else
{
tex = bindless_textures_half4[descriptor_index(image.texture_base_index)].Sample(sam, uvsets.xy);
}

if (image.flags & IMAGE_FLAG_EXTRACT_NORMALMAP)
{
Expand Down
40 changes: 38 additions & 2 deletions WickedEngine/shaders/objectHF.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -580,8 +580,9 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target
#endif // OBJECTSHADER_USE_TANGENT



#ifdef OBJECTSHADER_USE_UVSETS

#ifndef INTERIORMAPPING
[branch]
#ifdef PREPASS
if (material.textures[BASECOLORMAP].IsValid())
Expand All @@ -591,6 +592,7 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target
{
surface.baseColor *= material.textures[BASECOLORMAP].Sample(sampler_objectshader, uvsets);
}
#endif // INTERIORMAPPING

[branch]
if (material.textures[TRANSPARENCYMAP].IsValid())
Expand Down Expand Up @@ -1065,6 +1067,41 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target
color = surface.baseColor;
#endif // UNLIT

#ifdef INTERIORMAPPING
[branch]
if (material.textures[BASECOLORMAP].IsValid())
{
TextureCube cubemap = bindless_cubemaps[descriptor_index(material.textures[BASECOLORMAP].texture_descriptor)];

// Note: there is some heavy per-pixel matrix math here (mul, inverse, matrix_to_quaternion) by intention
// to not increase common structure sizes for single shader that would require these things!

half3 scale = material.GetInteriorScale();
float4x4 scaleMatrix = float4x4(
scale.x, 0, 0, 0,
0, scale.y, 0, 0,
0, 0, scale.z, 0,
0, 0, 0, 1
);
float4x4 interiorTransform = mul(meshinstance.transformRaw.GetMatrix(), scaleMatrix);
float4x4 interiorProjection = inverse(interiorTransform);

const half3 clipSpacePos = mul(interiorProjection, float4(surface.P, 1)).xyz;

surface.R = -surface.V;
half3 RayLS = mul((half3x3)interiorProjection, surface.R);
half3 FirstPlaneIntersect = (1 - clipSpacePos) / RayLS;
half3 SecondPlaneIntersect = (-1 - clipSpacePos) / RayLS;
half3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
half Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
half3 R_parallaxCorrected = surface.P - meshinstance.center + surface.R * Distance;
R_parallaxCorrected = rotate_vector(R_parallaxCorrected, matrix_to_quaternion(interiorProjection));

surface.baseColor *= cubemap.SampleLevel(sampler_linear_clamp, R_parallaxCorrected, 0);
}
color = surface.baseColor;
#endif // INTERIORMAPPING


// Transparent objects has been rendered separately from opaque, so let's apply it now.
// Must also be applied before fog since fog is layered over.
Expand All @@ -1079,7 +1116,6 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target

color = saturateMediump(color);


// end point:
#ifdef PREPASS
coverage = AlphaToCoverage(color.a, material.GetAlphaTest() + meshinstance.GetAlphaTest(), input.pos); // opaque soft alpha test (temporal AA, etc)
Expand Down
Loading

0 comments on commit 32b9694

Please sign in to comment.