Terrain detail and macro texture support (#4403)
* Terrain feature processor improvements regarding material, mesh, and lod - Now using a material with pbr lighting for terrain. Removed some of the old shader code that wasn't needed anymore - Move heightmap image declaration to the material so it's not needed in the object SRG anymore - Added prototype code (commented out) for smoothing the terrain with a b-spline weighting function - Mesh data is all made with a proper mesh asset now. - Added basic LOD support (no continuous LOD yet, but it does pop between lod levels) - Moved RenderCommon to be accessible publicly. It contains stencil refs that should be public. Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Adding more material options to terrain shader Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Fixing terrain's per object srg because of changes in the default per object srg. Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Added more features to the terrain material. Shader & Material reloads are now handled. Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Added stub for terrain render max area setting in the renderer component. Added detail texture tiling setable from the material Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Missing change to material type from last commit Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Adding macro material in material type and support detail roughness. Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Fixing merge issues in terrain material type Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Adding more features to the terrain material - Macro color and normals - Detail layer fade out - Reoriented detail normals Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Remove line that unintentionally was added back during a rebase & merge. Signed-off-by: Ken Pruiksma <pruiksma@amazon.com> * Fixing previously deleted unused static that came back after a merge. Fixed an issue with macro normals in the terrain shader. Signed-off-by: Ken Pruiksma <pruiksma@amazon.com>
This commit is contained in:
@@ -4,8 +4,27 @@
|
||||
"parentMaterial": "",
|
||||
"propertyLayoutVersion": 1,
|
||||
"properties": {
|
||||
"settings": {
|
||||
"baseColor": [ 0.78, 0.59, 0.48 ]
|
||||
"macroColor": {
|
||||
"useTexture": false
|
||||
},
|
||||
"macroNormal": {
|
||||
"useTexture": false
|
||||
},
|
||||
"baseColor": {
|
||||
"color": [ 0.18, 0.18, 0.18 ],
|
||||
"useTexture": false
|
||||
},
|
||||
"normal":
|
||||
{
|
||||
"useTexture": false
|
||||
},
|
||||
"roughness":
|
||||
{
|
||||
"useTexture": false
|
||||
},
|
||||
"specularF0":
|
||||
{
|
||||
"useTexture": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,25 +100,269 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "baseColor",
|
||||
"displayName": "Base Color",
|
||||
"id": "detailTextureMultiplier",
|
||||
"displayName": "Detail Texture UV Multiplier",
|
||||
"description": "How many times to repeat the detail texture per sector",
|
||||
"type": "Float",
|
||||
"defaultValue": 8.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_detailTextureMultiplier"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "detailFadeDistance",
|
||||
"displayName": "Detail Fade Distance (meters)",
|
||||
"description": "The distance in meters that the detail texture starts to fade",
|
||||
"type": "Float",
|
||||
"defaultValue": 100.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_detailFadeDistance"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "detailFadeLength",
|
||||
"displayName": "Detail Fade Length",
|
||||
"description": "How far beyond Detail Fade Distance where the detail texture no longer applies.",
|
||||
"type": "Float",
|
||||
"defaultValue": 50.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_detailFadeLength"
|
||||
}
|
||||
}
|
||||
],
|
||||
"macroColor": [
|
||||
{
|
||||
"id": "textureMap",
|
||||
"displayName": "Texture",
|
||||
"description": "Macro color texture map",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_macroColorMap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "useTexture",
|
||||
"displayName": "Use Texture",
|
||||
"description": "Whether to use the texture.",
|
||||
"type": "Bool",
|
||||
"defaultValue": true
|
||||
}
|
||||
|
||||
],
|
||||
"macroNormal": [
|
||||
{
|
||||
"id": "textureMap",
|
||||
"displayName": "Texture",
|
||||
"description": "Macro normal texture map",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_macroNormalMap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "useTexture",
|
||||
"displayName": "Use Texture",
|
||||
"description": "Whether to use the texture.",
|
||||
"type": "Bool",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"id": "flipX",
|
||||
"displayName": "Flip X Channel",
|
||||
"description": "Flip tangent direction for this normal map.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_flipMacroNormalX"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "flipY",
|
||||
"displayName": "Flip Y Channel",
|
||||
"description": "Flip bitangent direction for this normal map.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_flipMacroNormalY"
|
||||
}
|
||||
}
|
||||
],
|
||||
"baseColor": [
|
||||
{
|
||||
"id": "color",
|
||||
"displayName": "Color",
|
||||
"description": "Color is displayed as sRGB but the values are stored as linear color.",
|
||||
"type": "Color",
|
||||
"defaultValue": [ 0.18, 0.18, 0.18 ],
|
||||
"defaultValue": [ 1.0, 1.0, 1.0 ],
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_baseColor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "roughness",
|
||||
"displayName": "Roughness",
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.",
|
||||
"type": "Float",
|
||||
"defaultValue": 1.0,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_roughness"
|
||||
"id": "m_baseColorFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "textureMap",
|
||||
"displayName": "Texture",
|
||||
"description": "Base color texture map",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_baseColorMap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "useTexture",
|
||||
"displayName": "Use Texture",
|
||||
"description": "Whether to use the texture.",
|
||||
"type": "Bool",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"id": "textureBlendMode",
|
||||
"displayName": "Texture Blend Mode",
|
||||
"description": "Selects the equation to use when combining Color, Factor, and Texture.",
|
||||
"type": "Enum",
|
||||
"enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ],
|
||||
"defaultValue": "Overlay",
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
"id": "o_baseColorTextureBlendMode"
|
||||
}
|
||||
}
|
||||
],
|
||||
"normal": [
|
||||
{
|
||||
"id": "textureMap",
|
||||
"displayName": "Texture",
|
||||
"description": "Texture for defining surface normal direction.",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_normalMap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "useTexture",
|
||||
"displayName": "Use Texture",
|
||||
"description": "Whether to use the texture, or just rely on vertex normals.",
|
||||
"type": "Bool",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"id": "flipX",
|
||||
"displayName": "Flip X Channel",
|
||||
"description": "Flip tangent direction for this normal map.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_flipNormalX"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "flipY",
|
||||
"displayName": "Flip Y Channel",
|
||||
"description": "Flip bitangent direction for this normal map.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_flipNormalY"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Strength factor for scaling the values",
|
||||
"type": "Float",
|
||||
"defaultValue": 1.0,
|
||||
"min": 0.0,
|
||||
"softMax": 2.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_normalFactor"
|
||||
}
|
||||
}
|
||||
],
|
||||
"roughness": [
|
||||
{
|
||||
"id": "textureMap",
|
||||
"displayName": "Texture",
|
||||
"description": "Texture for defining surface roughness.",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_roughnessMap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "useTexture",
|
||||
"description": "Whether to use the texture, or just default to the Factor value.",
|
||||
"type": "Bool",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Controls the roughness value",
|
||||
"type": "Float",
|
||||
"defaultValue": 1.0,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_roughnessFactor"
|
||||
}
|
||||
}
|
||||
],
|
||||
"specularF0": [
|
||||
{
|
||||
"id": "textureMap",
|
||||
"displayName": "Texture",
|
||||
"description": "Texture for defining surface reflectance.",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_specularF0Map"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "useTexture",
|
||||
"displayName": "Use Texture",
|
||||
"description": "Whether to use the texture, or just default to the Factor value.",
|
||||
"type": "Bool",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"id": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.",
|
||||
"type": "Float",
|
||||
"defaultValue": 0.5,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_specularF0Factor"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -136,5 +380,55 @@
|
||||
}
|
||||
],
|
||||
"functors": [
|
||||
{
|
||||
"type": "UseTexture",
|
||||
"args": {
|
||||
"textureProperty": "macroColor.textureMap",
|
||||
"useTextureProperty": "macroColor.useTexture",
|
||||
"shaderOption": "o_macroColor_useTexture"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "UseTexture",
|
||||
"args": {
|
||||
"textureProperty": "macroNormal.textureMap",
|
||||
"useTextureProperty": "macroNormal.useTexture",
|
||||
"shaderOption": "o_macroNormal_useTexture"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "UseTexture",
|
||||
"args": {
|
||||
"textureProperty": "baseColor.textureMap",
|
||||
"useTextureProperty": "baseColor.useTexture",
|
||||
"dependentProperties": ["baseColor.textureBlendMode"],
|
||||
"shaderOption": "o_baseColor_useTexture"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "UseTexture",
|
||||
"args": {
|
||||
"textureProperty": "specularF0.textureMap",
|
||||
"useTextureProperty": "specularF0.useTexture",
|
||||
"shaderOption": "o_specularF0_useTexture"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "UseTexture",
|
||||
"args": {
|
||||
"textureProperty": "normal.textureMap",
|
||||
"useTextureProperty": "normal.useTexture",
|
||||
"dependentProperties": ["normal.factor", "normal.flipX", "normal.flipY"],
|
||||
"shaderOption": "o_normal_useTexture"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "UseTexture",
|
||||
"args": {
|
||||
"textureProperty": "roughness.textureMap",
|
||||
"useTextureProperty": "roughness.useTexture",
|
||||
"shaderOption": "o_roughness_useTexture"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <../Materials/Types/MaterialInputs/BaseColorInput.azsli>
|
||||
#include <../Materials/Types/MaterialInputs/RoughnessInput.azsli>
|
||||
#include <../Materials/Types/MaterialInputs/MetallicInput.azsli>
|
||||
#include <../Materials/Types/MaterialInputs/SpecularInput.azsli>
|
||||
#include <../Materials/Types/MaterialInputs/NormalInput.azsli>
|
||||
|
||||
ShaderResourceGroup ObjectSrg : SRG_PerObject
|
||||
{
|
||||
row_major float3x4 m_modelToWorld;
|
||||
@@ -70,7 +76,10 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject
|
||||
|
||||
ShaderResourceGroup TerrainMaterialSrg : SRG_PerMaterial
|
||||
{
|
||||
Texture2D<float> m_heightmapImage;
|
||||
Texture2D m_heightmapImage;
|
||||
float m_detailTextureMultiplier;
|
||||
float m_detailFadeDistance;
|
||||
float m_detailFadeLength;
|
||||
|
||||
Sampler HeightmapSampler
|
||||
{
|
||||
@@ -82,11 +91,52 @@ ShaderResourceGroup TerrainMaterialSrg : SRG_PerMaterial
|
||||
AddressW = Clamp;
|
||||
};
|
||||
|
||||
Sampler m_sampler
|
||||
{
|
||||
AddressU = Wrap;
|
||||
AddressV = Wrap;
|
||||
MinFilter = Linear;
|
||||
MagFilter = Linear;
|
||||
MipFilter = Linear;
|
||||
MaxAnisotropy = 16;
|
||||
};
|
||||
|
||||
// Macro Color
|
||||
Texture2D m_macroColorMap;
|
||||
|
||||
// Macro normal
|
||||
Texture2D m_macroNormalMap;
|
||||
bool m_flipMacroNormalX;
|
||||
bool m_flipMacroNormalY;
|
||||
|
||||
// Base Color
|
||||
float3 m_baseColor;
|
||||
float m_roughness;
|
||||
float m_baseColorFactor;
|
||||
Texture2D m_baseColorMap;
|
||||
|
||||
// Normal
|
||||
Texture2D m_normalMap;
|
||||
bool m_flipNormalX;
|
||||
bool m_flipNormalY;
|
||||
float m_normalFactor;
|
||||
|
||||
// Roughness
|
||||
Texture2D m_roughnessMap;
|
||||
float m_roughnessFactor;
|
||||
|
||||
// Specular
|
||||
Texture2D m_specularF0Map;
|
||||
float m_specularF0Factor;
|
||||
}
|
||||
|
||||
option bool o_useTerrainSmoothing = false;
|
||||
option bool o_macroColor_useTexture = true;
|
||||
option bool o_macroNormal_useTexture = true;
|
||||
option bool o_baseColor_useTexture = true;
|
||||
option bool o_specularF0_useTexture = true;
|
||||
option bool o_normal_useTexture = true;
|
||||
option bool o_roughness_useTexture = true;
|
||||
option TextureBlendMode o_baseColorTextureBlendMode = TextureBlendMode::Multiply;
|
||||
|
||||
struct VertexInput
|
||||
{
|
||||
@@ -98,7 +148,7 @@ struct VertexInput
|
||||
// This function samples a 4x4 neighborhood around the uv. Normally this would take 16 samples, but by taking
|
||||
// advantage of bilinear filtering this can be done with 9 taps on the edges between pixels. The cost is further
|
||||
// reduced by dropping the diagonals.
|
||||
float SampleBSpline5Tap(Texture2D<float> texture, SamplerState textureSampler, float2 uv, float2 textureSize, float2 rcpTextureSize)
|
||||
float SampleBSpline5Tap(Texture2D texture, SamplerState textureSampler, float2 uv, float2 textureSize, float2 rcpTextureSize)
|
||||
{
|
||||
// Think of sample locations in the 4x4 neighborhood as having a top left coordinate of 0,0 and
|
||||
// a bottom right coordinate of 3,3.
|
||||
|
||||
@@ -71,18 +71,49 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN)
|
||||
|
||||
Surface surface;
|
||||
|
||||
// Position, Normal, Roughness
|
||||
// Position
|
||||
surface.position = IN.m_worldPosition.xyz;
|
||||
surface.normal = normalize(IN.m_normal);
|
||||
surface.roughnessLinear = TerrainMaterialSrg::m_roughness;
|
||||
float viewDistance = length(ViewSrg::m_worldPosition - surface.position);
|
||||
float detailFactor = saturate((viewDistance - TerrainMaterialSrg::m_detailFadeDistance) / max(TerrainMaterialSrg::m_detailFadeLength, EPSILON));
|
||||
|
||||
ObjectSrg::TerrainData terrainData = ObjectSrg::m_terrainData;
|
||||
float2 origUv = lerp(terrainData.m_uvMin, terrainData.m_uvMax, IN.m_uv);
|
||||
origUv.y = 1.0 - origUv.y;
|
||||
float2 detailUv = IN.m_uv * TerrainMaterialSrg::m_detailTextureMultiplier;
|
||||
|
||||
// ------- Normal -------
|
||||
float3 macroNormal = IN.m_normal;
|
||||
if (o_macroNormal_useTexture)
|
||||
{
|
||||
macroNormal = GetNormalInputTS(TerrainMaterialSrg::m_macroNormalMap, TerrainMaterialSrg::m_sampler,
|
||||
origUv, TerrainMaterialSrg::m_flipMacroNormalX, TerrainMaterialSrg::m_flipMacroNormalY, CreateIdentity3x3(), true, 1.0);
|
||||
}
|
||||
|
||||
float3 detailNormal = GetNormalInputTS(TerrainMaterialSrg::m_normalMap, TerrainMaterialSrg::m_sampler,
|
||||
detailUv, TerrainMaterialSrg::m_flipNormalX, TerrainMaterialSrg::m_flipNormalY, CreateIdentity3x3(), o_normal_useTexture, TerrainMaterialSrg::m_normalFactor);
|
||||
|
||||
detailNormal = ReorientTangentSpaceNormal(macroNormal, detailNormal);
|
||||
surface.normal = lerp(detailNormal, macroNormal, detailFactor);
|
||||
surface.normal = normalize(surface.normal);
|
||||
|
||||
// ------- Macro Color -------
|
||||
float3 macroColor = GetBaseColorInput(TerrainMaterialSrg::m_macroColorMap, TerrainMaterialSrg::m_sampler, origUv, TerrainMaterialSrg::m_baseColor.rgb, o_baseColor_useTexture);
|
||||
|
||||
// ------- Base Color -------
|
||||
float3 detailColor = GetBaseColorInput(TerrainMaterialSrg::m_baseColorMap, TerrainMaterialSrg::m_sampler, detailUv, TerrainMaterialSrg::m_baseColor.rgb, o_baseColor_useTexture);
|
||||
float3 blendedColor = BlendBaseColor(lerp(detailColor, TerrainMaterialSrg::m_baseColor.rgb, detailFactor), macroColor, TerrainMaterialSrg::m_baseColorFactor, o_baseColorTextureBlendMode, o_baseColor_useTexture);
|
||||
|
||||
// ------- Specular -------
|
||||
float specularF0Factor = GetSpecularInput(TerrainMaterialSrg::m_specularF0Map, TerrainMaterialSrg::m_sampler, detailUv, TerrainMaterialSrg::m_specularF0Factor, o_specularF0_useTexture);
|
||||
specularF0Factor = lerp(specularF0Factor, 0.5, detailFactor);
|
||||
surface.SetAlbedoAndSpecularF0(blendedColor, specularF0Factor, 0.0);
|
||||
|
||||
// ------- Roughness -------
|
||||
surface.roughnessLinear = GetRoughnessInput(TerrainMaterialSrg::m_roughnessMap, TerrainMaterialSrg::m_sampler, detailUv, TerrainMaterialSrg::m_roughnessFactor, 0.0, 1.0, o_roughness_useTexture);
|
||||
surface.roughnessLinear = lerp(surface.roughnessLinear, 1.0, detailFactor);
|
||||
surface.CalculateRoughnessA();
|
||||
|
||||
// Albedo, SpecularF0
|
||||
const float specularF0Factor = 0.5f;
|
||||
float3 color = TerrainMaterialSrg::m_baseColor;
|
||||
surface.SetAlbedoAndSpecularF0(color, specularF0Factor, 0.0);
|
||||
|
||||
// Clear Coat, Transmission
|
||||
// Clear Coat, Transmission (Not used for terrain)
|
||||
surface.clearCoat.InitializeToZero();
|
||||
surface.transmission.InitializeToZero();
|
||||
|
||||
|
||||
@@ -28,16 +28,27 @@ namespace Terrain
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<TerrainWorldRendererConfig, AZ::ComponentConfig>()->Version(1);
|
||||
serialize->Class<TerrainWorldRendererConfig, AZ::ComponentConfig>()
|
||||
->Version(1)
|
||||
->Field("WorldSize", &TerrainWorldRendererConfig::m_worldSize)
|
||||
;
|
||||
|
||||
AZ::EditContext* edit = serialize->GetEditContext();
|
||||
if (edit)
|
||||
AZ::EditContext* editContext = serialize->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
edit->Class<TerrainWorldRendererConfig>("Terrain World Renderer Component", "Enables terrain rendering")
|
||||
editContext->Class<TerrainWorldRendererConfig>("Terrain World Renderer Component", "Enables terrain rendering")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true);
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &TerrainWorldRendererConfig::m_worldSize, "Rendered world size", "The maximum amount of terrain that's rendered")
|
||||
->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_512Meters, "512 Meters")
|
||||
->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_1024Meters, "1 Kilometer")
|
||||
->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_2048Meters, "2 Kilometers")
|
||||
->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_4096Meters, "4 Kilometers")
|
||||
->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_8192Meters, "8 Kilometers")
|
||||
->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_16384Meters, "16 Kilometers")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,6 +83,28 @@ namespace Terrain
|
||||
TerrainWorldRendererComponent::TerrainWorldRendererComponent(const TerrainWorldRendererConfig& configuration)
|
||||
: m_configuration(configuration)
|
||||
{
|
||||
switch (configuration.m_worldSize)
|
||||
{
|
||||
case TerrainWorldRendererConfig::WorldSize::_512Meters:
|
||||
m_terrainFeatureProcessor->SetWorldSize(AZ::Vector2(512.0f, 512.0f));
|
||||
break;
|
||||
case TerrainWorldRendererConfig::WorldSize::_1024Meters:
|
||||
m_terrainFeatureProcessor->SetWorldSize(AZ::Vector2(1024.0f, 1024.0f));
|
||||
break;
|
||||
case TerrainWorldRendererConfig::WorldSize::_2048Meters:
|
||||
m_terrainFeatureProcessor->SetWorldSize(AZ::Vector2(2048.0f, 2048.0f));
|
||||
break;
|
||||
case TerrainWorldRendererConfig::WorldSize::_4096Meters:
|
||||
m_terrainFeatureProcessor->SetWorldSize(AZ::Vector2(4096.0f, 4096.0f));
|
||||
break;
|
||||
case TerrainWorldRendererConfig::WorldSize::_8192Meters:
|
||||
m_terrainFeatureProcessor->SetWorldSize(AZ::Vector2(8192.0f, 8192.0f));
|
||||
break;
|
||||
case TerrainWorldRendererConfig::WorldSize::_16384Meters:
|
||||
m_terrainFeatureProcessor->SetWorldSize(AZ::Vector2(16384.0f, 16384.0f));
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
TerrainWorldRendererComponent::~TerrainWorldRendererComponent()
|
||||
|
||||
@@ -27,13 +27,28 @@ namespace Terrain
|
||||
{
|
||||
class TerrainFeatureProcessor;
|
||||
|
||||
class TerrainWorldRendererConfig
|
||||
struct TerrainWorldRendererConfig final
|
||||
: public AZ::ComponentConfig
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(TerrainWorldRendererConfig, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(TerrainWorldRendererConfig, "{08C5863C-092D-4A69-8226-4978E4F6E343}", AZ::ComponentConfig);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
enum class WorldSize : uint8_t
|
||||
{
|
||||
Unknown,
|
||||
|
||||
_512Meters,
|
||||
_1024Meters,
|
||||
_2048Meters,
|
||||
_4096Meters,
|
||||
_8192Meters,
|
||||
_16384Meters,
|
||||
|
||||
WorldSizeCount,
|
||||
};
|
||||
|
||||
WorldSize m_worldSize;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@ namespace Terrain
|
||||
editContext->Class<EditorTerrainWorldRendererComponent>(
|
||||
"Terrain World Renderer", "")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Terrain")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/TerrainWorldRenderer.svg")
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/TerrainWorldRenderer.svg")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Terrain")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/TerrainWorldRenderer.svg")
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/TerrainWorldRenderer.svg")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,26 +76,24 @@ namespace Terrain
|
||||
|
||||
void TerrainFeatureProcessor::Initialize()
|
||||
{
|
||||
{
|
||||
// Load the terrain material asynchronously
|
||||
const AZStd::string materialFilePath = "Materials/Terrain/DefaultPbrTerrain.azmaterial";
|
||||
m_materialAssetLoader = AZStd::make_unique<AZ::RPI::AssetUtils::AsyncAssetLoader>();
|
||||
*m_materialAssetLoader = AZ::RPI::AssetUtils::AsyncAssetLoader::Create<AZ::RPI::MaterialAsset>(materialFilePath, 0u,
|
||||
[&](AZ::Data::Asset<AZ::Data::AssetData> assetData, bool success) -> void
|
||||
// Load the terrain material asynchronously
|
||||
const AZStd::string materialFilePath = "Materials/Terrain/DefaultPbrTerrain.azmaterial";
|
||||
m_materialAssetLoader = AZStd::make_unique<AZ::RPI::AssetUtils::AsyncAssetLoader>();
|
||||
*m_materialAssetLoader = AZ::RPI::AssetUtils::AsyncAssetLoader::Create<AZ::RPI::MaterialAsset>(materialFilePath, 0u,
|
||||
[&](AZ::Data::Asset<AZ::Data::AssetData> assetData, bool success) -> void
|
||||
{
|
||||
const AZ::Data::Asset<AZ::RPI::MaterialAsset>& materialAsset = static_cast<AZ::Data::Asset<AZ::RPI::MaterialAsset>>(assetData);
|
||||
if (success)
|
||||
{
|
||||
const AZ::Data::Asset<AZ::RPI::MaterialAsset>& materialAsset = static_cast<AZ::Data::Asset<AZ::RPI::MaterialAsset>>(assetData);
|
||||
if (success)
|
||||
m_materialInstance = AZ::RPI::Material::FindOrCreate(assetData);
|
||||
AZ::RPI::MaterialReloadNotificationBus::Handler::BusConnect(materialAsset->GetId());
|
||||
if (!materialAsset->GetObjectSrgLayout())
|
||||
{
|
||||
m_materialInstance = AZ::RPI::Material::FindOrCreate(assetData);
|
||||
if (!materialAsset->GetObjectSrgLayout())
|
||||
{
|
||||
AZ_Error("TerrainFeatureProcessor", false, "No per-object ShaderResourceGroup found on terrain material.");
|
||||
}
|
||||
AZ_Error("TerrainFeatureProcessor", false, "No per-object ShaderResourceGroup found on terrain material.");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
if (!InitializePatchModel())
|
||||
{
|
||||
AZ_Error(TerrainFPName, false, "Failed to create Terrain render buffers!");
|
||||
@@ -105,10 +103,9 @@ namespace Terrain
|
||||
|
||||
void TerrainFeatureProcessor::Deactivate()
|
||||
{
|
||||
DisableSceneNotification();
|
||||
|
||||
m_patchModel = {};
|
||||
m_areaData = {};
|
||||
AZ::RPI::MaterialReloadNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::Render(const AZ::RPI::FeatureProcessor::RenderPacket& packet)
|
||||
@@ -291,7 +288,7 @@ namespace Terrain
|
||||
AZ::Vector2 sectorCenterXY = AZ::Vector2(sectorData.m_aabb.GetCenter().GetX(), sectorData.m_aabb.GetCenter().GetY());
|
||||
|
||||
float sectorDistance = sectorCenterXY.GetDistance(cameraPositionXY);
|
||||
float lodForCamera = ceilf(AZ::GetMax(0.0f, log2f(sectorDistance / (GridMeters * 4.0f))));
|
||||
float lodForCamera = floorf(AZ::GetMax(0.0f, log2f(sectorDistance / (GridMeters * 4.0f))));
|
||||
lodChoice = AZ::GetMin(lodChoice, aznumeric_cast<uint8_t>(lodForCamera));
|
||||
}
|
||||
}
|
||||
@@ -317,6 +314,7 @@ namespace Terrain
|
||||
|
||||
uint16_t gridVertices = gridSize + 1; // For m_gridSize quads, (m_gridSize + 1) vertices are needed.
|
||||
size_t size = gridVertices * gridVertices;
|
||||
size *= size;
|
||||
|
||||
patchdata.m_positions.reserve(size);
|
||||
patchdata.m_uvs.reserve(size);
|
||||
@@ -432,4 +430,21 @@ namespace Terrain
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::OnMaterialReinitialized([[maybe_unused]] const AZ::Data::Instance<AZ::RPI::Material>& material)
|
||||
{
|
||||
for (auto& sectorData : m_sectorData)
|
||||
{
|
||||
for (auto& drawPacket : sectorData.m_drawPackets)
|
||||
{
|
||||
drawPacket.Update(*GetParentScene());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::SetWorldSize([[maybe_unused]] AZ::Vector2 sizeInMeters)
|
||||
{
|
||||
// This will control the max rendering size. Actual terrain size can be much
|
||||
// larger but this will limit how much is rendered.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <Atom/RHI/StreamBufferView.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
|
||||
#include <Atom/RPI.Public/Material/MaterialReloadNotificationBus.h>
|
||||
|
||||
namespace AZ::RPI
|
||||
{
|
||||
@@ -41,6 +42,7 @@ namespace Terrain
|
||||
{
|
||||
class TerrainFeatureProcessor final
|
||||
: public AZ::RPI::FeatureProcessor
|
||||
, private AZ::RPI::MaterialReloadNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(TerrainFeatureProcessor, "{D7DAC1F9-4A9F-4D3C-80AE-99579BF8AB1C}", AZ::RPI::FeatureProcessor);
|
||||
@@ -52,12 +54,18 @@ namespace Terrain
|
||||
TerrainFeatureProcessor() = default;
|
||||
~TerrainFeatureProcessor() = default;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
// AZ::Component overrides...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
// AZ::RPI::FeatureProcessor overrides...
|
||||
void Render(const AZ::RPI::FeatureProcessor::RenderPacket& packet) override;
|
||||
|
||||
// AZ::RPI::MaterialReloadNotificationBus::Handler overrides...
|
||||
void OnMaterialReinitialized(const AZ::Data::Instance<AZ::RPI::Material>& material) override;
|
||||
|
||||
void SetWorldSize(AZ::Vector2 sizeInMeters);
|
||||
|
||||
void UpdateTerrainData(const AZ::Transform& transform, const AZ::Aabb& worldBounds, float sampleSpacing,
|
||||
uint32_t width, uint32_t height, const AZStd::vector<float>& heightData);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user