Ogre::PBSM_DETAIL0_NM Bug in Ogre-Next?

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Lax
Orc Shaman
Posts: 711
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 75

Ogre::PBSM_DETAIL0_NM Bug in Ogre-Next?

Post by Lax »

Hi all,

i create PlanetTerra and I'm able to sculpt and paint on a planet.
I use diffuse texture and normal map as base. Then i have 4 layers:

PBSM_DETAIL0,
PBSM_DETAIL1,
PBSM_DETAIL2,
PBSM_DETAIL3,

For which i set textures.

Now as soon as i set the corresponding:

PBSM_DETAIL0_NM,
PBSM_DETAIL1_NM,
PBSM_DETAIL2_NM,
PBSM_DETAIL3_NM,

Texture. I get this crash:

21:54:13: There were HLMS syntax errors while parsing 100000002PixelShader_ps
21:54:13: OGRE EXCEPTION(-2147467259:RenderingAPIException): Cannot compile D3D11 high-level shader 100000002PixelShader_ps Errors:
(1037,3): error X3000: syntax error: unexpected token '@'
(1100,23): error X3004: undeclared identifier 'textureMaps'
in D3D11HLSLProgram::compileMicrocode at E:\Ogre2.2SDK\RenderSystems\Direct3D11\src\OgreD3D11HLSLProgram.cpp (line 558)
21:54:14: High-level program 100000002PixelShader_ps encountered an error during loading and is thus not supported.
OGRE EXCEPTION(-2147467259:RenderingAPIException): Cannot compile D3D11 high-level shader 100000002PixelShader_ps Errors:
(1037,3): error X3000: syntax error: unexpected token '@'
(1100,23): error X3004: undeclared identifier 'textureMaps'
in D3D11HLSLProgram::compileMicrocode at E:\Ogre2.2SDK\RenderSystems\Direct3D11\src\OgreD3D11HLSLProgram.cpp (line 558)

I tried to track that down and it has maybe something todo with automatic batching?

I do this:

Code: Select all

Ogre::uint32 textureFlags = 0;

if (this->datablock->suggestUsingSRGB(pbsTextureType))
{
    textureFlags |= Ogre::TextureFlags::PrefersLoadingFromFileAsSRGB;
}

// Apply AutomaticBatching for all normal map slots so they enter the
// textureMaps[] pool. detail_maps_normal and normal_map_tex properties
// in the HLMS piece only generate textureMaps and SampleDetailMapNm
// pieces when textures are in the pool (num_textures > 0).
if (pbsTextureType == Ogre::PBSM_NORMAL || (pbsTextureType >= Ogre::PBSM_DETAIL0_NM && pbsTextureType <= Ogre::PBSM_DETAIL3_NM))
{
    textureFlags |= Ogre::TextureFlags::AutomaticBatching;
}

Ogre::TextureTypes::TextureTypes internalTextureType = Ogre::TextureTypes::Type2D;
if (Ogre::PBSM_REFLECTION == pbsTextureType)
{
    internalTextureType = Ogre::TextureTypes::TypeCube;
}

Ogre::uint32 filters = Ogre::TextureFilter::FilterTypes::TypeGenerateDefaultMipmaps;
filters |= this->datablock->suggestFiltersForType(pbsTextureType);

Ogre::TextureGpu* texture =
    hlmsTextureManager->createOrRetrieveTexture(oldTextureName, Ogre::GpuPageOutStrategy::SaveToSystemRam, textureFlags, internalTextureType, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, filters, 0u);

Maybe someone already experimented with detail map normal textures...

Best Regards
Laxx18

http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5560
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1403

Re: Ogre::PBSM_DETAIL0_NM Bug in Ogre-Next?

Post by dark_sylinc »

Can you include the generated shader? It sounds like textureMaps@n which was supposed to translate to textureMaps0 (or whatever index) was left as is, for some reason.

Lax
Orc Shaman
Posts: 711
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 75

Re: Ogre::PBSM_DETAIL0_NM Bug in Ogre-Next?

Post by Lax »

Hi @dark_sylinc,

Short summary about findings. suspicions:

Scenario:
Custom sphere mesh, standard vertex format: pos(float3) + normal(float3) + tangent(float4) + uv0(float2). PBS material with 4 detail diffuse maps + 4 detail NM maps (BC5_SNORM DDS). Crashes on any mesh including standard Ogre example meshes with this material.
What works: Detail diffuse maps only (no NMs) -> renders fine.
What crashes: As soon as any PBSM_DETAIL0_NM..DETAIL3_NM slot is populated.
Properties at compile time are correct:
num_textures = 7
detail_maps_normal = 4
first_valid_detail_map_nm = 0
detail_map_nm0_idx = 3
detail_map_nm1_idx = 4
detail_map_nm2_idx = 5
detail_map_nm3_idx = 6
All 4 NM textures are Resident + AutomaticBatching + in pool before setTexture is called.
What the failing HLSL (attached) shows:

Line 1233 — blend mode pieces not resolved:

@insertpiece( NormalNonPremul) @add( t, 1 ) ← 4x literal

Lines 1328–1345 — SampleDetailMapNm0 piece body is emitted directly as HLSL code (not via @insertpiece) with @value() calls unresolved, and @piece(SampleDetailMapNm1-3) definition headers also appear literally:

hlslgetTSNormal( textureMaps@value(detail_map_nm0_idx), ← not resolved
samplerState@value(detail_map_nm0_sampler),...
@piece( SampleDetailMapNm1 )getTSNormal( textureMaps@value(detail_map_nm1_idx),...
@piece( SampleDetailMapNm2 )getTSNormal( textureMaps@value(detail_map_nm2_idx),...
@piece( SampleDetailMapNm3 )getTSNormal( textureMaps@value(detail_map_nm3_idx),...

Lines 1352–1376 — @value(detail_map_nm0_idx_slice) also unresolved in the getTSDetailNormal calls.

Hypothesis: The @piece(SampleDetailMapNmN)...@end blocks are not being properly captured — their content leaks into the HLSL output unevaluated instead of being stored as pieces for later @insertpiece expansion. The @value() calls inside them are therefore never processed. This also somehow prevents NormalNonPremul from being found when @insertpiece(blend_mode_idx0) expands.

Here the shader attached:

Code: Select all

#if 0
	***	textureMaps3	6
	***	hlms_uv_count0	2
	***	hlms_pose	0
	***	uv_emissive	0
	***	first_valid_detail_map_nm	4
	***	fresnel_scalar	0
	***	hlms_shadowmap2_uv_max_y	1054567864
	***	envprobe_map_sampler	3
	***	hlms_uv_count	2
	***	detail_map1	1
	***	pcf_iterations	4
	***	uv_detail_nm1	0
	***	uv_detail_nm2	0
	***	envMapRegSampler	3
	***	emissive_map_sampler	3
	***	hlms_tex_gather	1
	***	precision_mode	-2126167738
	***	hlms_shadowmap2_array_idx	0
	***	set0_texture_slot_end	3
	***	uv_specular	0
	***	hlms_disable_stage	0
	***	NumPoseWeightVectors	0
	***	hlms_shadowmap1_uv_min_x	0
	***	specular_map_sampler	3
	***	hlms_shadowmap0_uv_min_y	0
	***	texcoord	11
	***	fast_shader_build_hack	1
	***	glsl	635204550
	***	normal_weight_tex	1
	***	normal_sampling_format	-1392068498
	***	hlms_uv_count1	2
	***	NumPoseWeightVectorsB	0
	***	detail_map2	1
	***	hlms_num_shadow_map_lights	3
	***	hlms_lights_directional	1
	***	samplerStateStart	3
	***	detail_map3	1
	***	alpha_test	0
	***	roughness_map_sampler	3
	***	detail_weight_map	3
	***	hlms_shadowmap2	0
	***	hlms_shadowmap0_light_idx	0
	***	StrongMacroblockBits	0
	***	metallic_workflow	0
	***	hw_gamma_write	1
	***	uv_detail_weight	0
	***	detail_map_nm2_sampler	3
	***	hlms_shadowmap1_uvs_fulltex	1
	***	hlms_alpha_to_coverage	0
	***	cubemaps_as_diffuse_gi	1
	***	hlms_shadowmap2_uv_min_y	1049774373
	***	uv_detail_nm3	0
	***	NumPoseWeightVectorsC	0
	***	hlms_pssm_splits	3
	***	ambient_hemisphere_inverted	1
	***	hlms_pose_normals	0
	***	target_envprobe_map	1
	***	hlms_pose_half	0
	***	hlms_shadowmap1_light_idx	0
	***	hlms_lights_spot	1
	***	shadowmap2_is_directional_light	1
	***	hlms_shadowmap1_uv_max_x	1056964608
	***	hlms_shadowmap0_uv_min_x	0
	***	detail_map1_sampler	3
	***	uv_normal	0
	***	relaxed	1726237731
	***	hlms_shadowmap1_uv_min_y	1049774373
	***	detail_map_nm3_sampler	3
	***	hlms_alphablend	0
	***	textureMaps2	5
	***	hlms_num_shadow_map_textures	1
	***	hlms_view_matrix	1
	***	MoreThanOnePose	-1
	***	hlms_shadowmap1_array_idx	0
	***	detail_map0	4
	***	num_textures	4
	***	hlslvk	1841745752
	***	normal_map_tex	2
	***	uv_detail3	0
	***	detail_maps_diffuse	4
	***	hlms_shadow_uses_depth_texture	1
	***	hlms_msaa_samples	1
	***	ltcMatrix	1
	***	detail_map3_sampler	3
	***	hlms_shadowmap0_uv_max_x	1065353216
	***	normal_map	1
	***	hlms_tangent	1
	***	hlms_shadowmap1	0
	***	needs_env_brdf	1
	***	NumPoseWeightVectorsA	0
	***	pcf	3
	***	uv_detail1	0
	***	fresnel_workflow	1
	***	shadowmap1_is_directional_light	1
	***	full32	-2126167738
	***	perceptual_roughness	1
	***	alpha_test_shadow_caster_only	0
	***	materials_per_buffer	2
	***	hw_gamma_read	1
	***	normal_map_tex_idx	1
	***	detail_weight_map_idx	2
	***	hlms_skeleton	0
	***	hlms_pssm_splits_minus_one	2
	***	midf16	-1978079318
	***	partial_pso_clip_distances	0
	***	syntax	-334286542
	***	hlms_lights_point	1
	***	diffuse_map_sampler	3
	***	hlms_tangent4	1
	***	hlms_fine_light_mask	1
	***	metal	-1698855755
	***	fresnel_has_diffuse	1
	***	detail_map_nm1_sampler	3
	***	s_lights_directional_non_caster	1
	***	uv_detail0	0
	***	uv_diffuse	0
	***	diffuse_map	1
	***	needs_refl_dir	1
	***	hlms_pssm_blend	1
	***	uv_detail_nm0	0
	***	detail_weight_map_sampler	3
	***	detail_offsets3	1
	***	detail_offsets0	1
	***	normal_rg_snorm	-1392068498
	***	diffuse_map_idx	0
	***	detail_map_nm0_sampler	3
	***	hlms_shadowmap2_uv_max_x	1065353216
	***	hlms_shadowmap1_uv_max_y	1054567864
	***	hlms_shadowmap2_light_idx	0
	***	shadowmap0_is_directional_light	1
	***	hlms_shadowmap0_array_idx	0
	***	hlms_render_depth_only	0
	***	num_pass_const_buffers	4
	***	normal_map_tex_sampler	3
	***	uv_detail2	0
	***	MoreThanOnePoseWeightVector	-1
	***	detail_map2_sampler	3
	***	full_pso_clip_distances	0
	***	textureMaps0	3
	***	hlms_shadowmap0_uvs_fulltex	1
	***	detail_map0_sampler	3
	***	hlms_shadowmap2_uv_min_x	1056964608
	***	uv_roughness	0
	***	receive_shadows	1
	***	detail_offsets2	1
	***	textureMaps1	4
	***	detail_map3_idx	0
	***	hlms_pssm_fade	1
	***	hlms_shadowmap0	0
	***	detail_map0_idx	3
	***	needs_view_dir	1
	***	detail_map2_idx	0
	***	hlms_shadowmap2_uvs_fulltex	1
	***	BRDF_CookTorrance	1
	***	detail_map1_idx	0
	***	set1_texture_slot_end	7
	***	use_planar_reflections	0
	***	texShadowMap0	2
	***	ambient_hemisphere	1
	***	hlms_normal	1
	***	ltc_texture_available	1
	***	num_samplers	1
	***	glslvk	-338983575
	***	hlsl	-334286542
	***	hlms_shadowmap0_uv_max_y	1049774373
	***	detail_offsets1	1
	***	normal_weight	1
	DONE DUMPING PROPERTIES
	***	blend_mode_idx3	@insertpiece( NormalNonPremul)
	***	hlms_shadowmap2_uv_max_y	0.428571
	***	hlms_shadowmap1_uv_min_x	0.000000
	***	hlms_shadowmap0_uv_min_y	0.000000
	***	blend_mode_idx2	@insertpiece( NormalNonPremul)
	***	hlms_shadowmap2_uv_min_y	0.285714
	***	hlms_shadowmap1_uv_max_x	0.500000
	***	hlms_shadowmap0_uv_min_x	0.000000
	***	hlms_shadowmap1_uv_min_y	0.285714
	***	hlms_shadowmap0_uv_max_x	1.000000
	***	hlms_shadowmap2_uv_max_x	1.000000
	***	hlms_shadowmap1_uv_max_y	0.428571
	***	blend_mode_idx1	@insertpiece( NormalNonPremul)
	***	hlms_shadowmap2_uv_min_x	0.500000
	***	blend_mode_idx0	@insertpiece( NormalNonPremul)
	***	hlms_shadowmap0_uv_max_y	0.285714
	DONE DUMPING PIECES
#endif

//#include "SyntaxHighlightingMisc.h"


#define ushort uint
#define ushort3 uint3
#define ushort4 uint4
#define ogre_float4x3 float4x3

//Short used for read operations. It's an int in GLSL & HLSL. An ushort in Metal
#define rshort int
#define rshort2 int2
#define rint int
//Short used for write operations. It's an int in GLSL. An ushort in HLSL & Metal
#define wshort2 uint2
#define wshort3 uint3

#define toFloat3x3( x ) ((float3x3)(x))
#define buildFloat3x3( row0, row1, row2 ) transpose( float3x3( row0, row1, row2 ) )

#define buildFloat4x4( row0, row1, row2, row3 ) transpose( float4x4( row0, row1, row2, row3 ) )

#define getMatrixRow( mat, idx ) transpose( mat )[idx]

// See CrossPlatformSettings_piece_all.glsl for an explanation

#define _h(x) (x)

#define midf float
#define midf2 float2
#define midf3 float3
#define midf4 float4
#define midf2x2 float2x2
#define midf3x3 float3x3
#define midf4x4 float4x4

#define midf_c float
#define midf2_c float2
#define midf3_c float3
#define midf4_c float4
#define midf2x2_c float2x2
#define midf3x3_c float3x3
#define midf4x4_c float4x4

#define toMidf3x3( x ) ((float3x3)( x ))
#define buildMidf3x3( row0, row1, row2 ) transpose( float3x3( row0, row1, row2 ) )

#define ensureValidRangeF16(x)

#define min3( a, b, c ) min( a, min( b, c ) )
#define max3( a, b, c ) max( a, max( b, c ) )

#define INLINE
#define NO_INTERPOLATION_PREFIX nointerpolation
#define NO_INTERPOLATION_SUFFIX

#define PARAMS_ARG_DECL
#define PARAMS_ARG

#define floatBitsToUint(x) asuint(x)
#define uintBitsToFloat(x) asfloat(x)
#define floatBitsToInt(x) asint(x)
#define fract frac
#define lessThan( a, b ) (a < b)

#define inVs_vertexId input.vertexId
#define inVs_vertex input.vertex
#define inVs_normal input.normal
#define inVs_tangent input.tangent
#define inVs_binormal input.binormal
#define inVs_blendWeights input.blendWeights
#define inVs_blendIndices input.blendIndices
#define inVs_qtangent input.qtangent
#define inVs_colour input.colour

#define inVs_drawId input.drawId

#define finalDrawId inVs_drawId


#define inVs_uv0 input.uv0
#define inVs_uv1 input.uv1
#define outVs_Position outVs.gl_Position
#define outVs_viewportIndex outVs.gl_ViewportIndex
#define outVs_clipDistance0 outVs.gl_ClipDistance0.x

#define gl_SampleMaskIn0 gl_SampleMask
#define interpolateAtSample( interp, subsample ) EvaluateAttributeAtSample( interp, subsample )
#define findLSB firstbitlow
#define findMSB firstbithigh
#define mod( a, b ) ( (a) - (b) * floor( (a) / (b) ) )

#define outPs_colour0 outPs.colour0
#define OGRE_Sample( tex, sampler, uv ) tex.Sample( sampler, uv )
#define OGRE_SampleLevel( tex, sampler, uv, lod ) tex.SampleLevel( sampler, uv, lod )
#define OGRE_SampleArray2D( tex, sampler, uv, arrayIdx ) tex.Sample( sampler, float3( uv, arrayIdx ) )
#define OGRE_SampleArray2DLevel( tex, sampler, uv, arrayIdx, lod ) tex.SampleLevel( sampler, float3( uv, arrayIdx ), lod )
#define OGRE_SampleArrayCubeLevel( tex, sampler, uv, arrayIdx, lod ) tex.SampleLevel( sampler, float4( uv, arrayIdx ), lod )
#define OGRE_SampleGrad( tex, sampler, uv, ddx, ddy ) tex.SampleGrad( sampler, uv, ddx, ddy )
#define OGRE_SampleArray2DGrad( tex, sampler, uv, arrayIdx, ddx, ddy ) tex.SampleGrad( sampler, float3( uv, arrayIdx ), ddx, ddy )
#define OGRE_ddx( val ) ddx( val )
#define OGRE_ddy( val ) ddy( val )
#define OGRE_Load2D( tex, iuv, lod ) tex.Load( int3( iuv, lod ) )
#define OGRE_LoadArray2D( tex, iuv, arrayIdx, lod ) tex.Load( int4( iuv, arrayIdx, lod ) )
#define OGRE_Load2DMS( tex, iuv, subsample ) tex.Load( iuv, subsample )

#define OGRE_Load3D( tex, iuv, lod ) tex.Load( int4( iuv, lod ) )

#define OGRE_Load2DF16( tex, iuv, lod ) tex.Load( int3( iuv, lod ) )
#define OGRE_Load2DMSF16( tex, iuv, subsample ) tex.Load( iuv, subsample )
#define OGRE_SampleF16( tex, sampler, uv ) tex.Sample( sampler, uv )
#define OGRE_SampleLevelF16( tex, sampler, uv, lod ) tex.SampleLevel( sampler, uv, lod )
#define OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx ) tex.Sample( sampler, float3( uv, arrayIdx ) )
#define OGRE_SampleArray2DLevelF16( tex, sampler, uv, arrayIdx, lod ) tex.SampleLevel( sampler, float3( uv, arrayIdx ), lod )
#define OGRE_SampleArrayCubeLevelF16( tex, sampler, uv, arrayIdx, lod ) tex.SampleLevel( sampler, float4( uv, arrayIdx ), lod )
#define OGRE_SampleGradF16( tex, sampler, uv, ddx, ddy ) tex.SampleGrad( sampler, uv, ddx, ddy )
#define OGRE_SampleArray2DGradF16( tex, sampler, uv, arrayIdx, ddx, ddy ) tex.SampleGrad( sampler, float3( uv, arrayIdx ), ddx, ddy )

#define bufferFetch( buffer, idx ) buffer.Load( idx )
#define bufferFetch1( buffer, idx ) buffer.Load( idx ).x

#define structuredBufferFetch( buffer, idx ) buffer[idx]

#define ReadOnlyBuffer( slot, varType, varName ) StructuredBuffer<varType> varName : register(t##slot)
#define readOnlyFetch( bufferVar, idx ) bufferVar[idx]
#define readOnlyFetch1( bufferVar, idx ) bufferVar[idx].x

#define OGRE_Texture3D_float4 Texture3D

#define OGRE_ArrayTex( declType, varName, arrayCount ) declType varName[arrayCount]

#define OGRE_SAMPLER_ARG_DECL( samplerName ) , SamplerState samplerName
#define OGRE_SAMPLER_ARG( samplerName ) , samplerName

#define CONST_BUFFER( bufferName, bindingPoint ) cbuffer bufferName : register(b##bindingPoint)
#define CONST_BUFFER_STRUCT_BEGIN( structName, bindingPoint ) cbuffer structName : register(b##bindingPoint) { struct _##structName
#define CONST_BUFFER_STRUCT_END( variableName ) variableName; }

#define FLAT_INTERPOLANT( decl, bindingPoint ) nointerpolation decl : TEXCOORD##bindingPoint
#define INTERPOLANT( decl, bindingPoint ) decl : TEXCOORD##bindingPoint

#define OGRE_OUT_REF( declType, variableName ) out declType variableName
#define OGRE_INOUT_REF( declType, variableName ) inout declType variableName

#define OGRE_ARRAY_START( type ) {
#define OGRE_ARRAY_END }

float4 unpackSnorm4x8( uint value )
{
	int signedValue = int( value );
	int4 packed = int4( signedValue << 24, signedValue << 16, signedValue << 8, signedValue ) >> 24;
	return clamp( float4( packed ) / 127.0, -1.0, 1.0 );
}

float2 unpackSnorm2x16( uint value )
{
	int signedValue = int( value );
	int2 packed = int2( signedValue << 16, signedValue ) >> 16;
	return clamp( float2( packed ) / 32767.0, -1.0, 1.0 );
}



#define UV_DIFFUSE(x) (x)
#define UV_NORMAL(x) (x)
#define UV_SPECULAR(x) (x)
#define UV_ROUGHNESS(x) (x)
#define UV_DETAIL_WEIGHT(x) (x)
#define UV_DETAIL0(x) (x)
#define UV_DETAIL1(x) (x)
#define UV_DETAIL2(x) (x)
#define UV_DETAIL3(x) (x)
#define UV_DETAIL_NM0(x) (x)
#define UV_DETAIL_NM1(x) (x)
#define UV_DETAIL_NM2(x) (x)
#define UV_DETAIL_NM3(x) (x)
#define UV_EMISSIVE(x) (x)







// START UNIFORM DECLARATION

	
		
struct ShadowReceiverData
{
	float4x4 texViewProj;
	float2 shadowDepthRange;
	float normalOffsetBias;
	float padding;
	float4 invShadowMapSize;
};

struct Light
{
			float3 position;
		uint lightMask;
		float4 diffuse;		//.w contains numNonCasterDirectionalLights
	float3 specular;

float3 attenuation;
//Spotlights:
//  spotDirection.xyz is direction
//  spotParams.xyz contains falloff params
float4 spotDirection;
float4 spotParams;

#define lightTexProfileIdx spotDirection.w
};

#define numNonCasterDirectionalLights lights[0].diffuse.w

#define areaLightDiffuseMipmapStart areaApproxLights[0].diffuse.w
#define areaLightNumMipmapsSpecFactor areaApproxLights[0].specular.w

#define numAreaApproxLights areaApproxLights[0].doubleSided.y
#define numAreaApproxLightsWithMask areaApproxLights[0].doubleSided.z

#define numAreaLtcLights areaLtcLights[0].points[0].w
#define numAreaLtcLights areaLtcLights[0].points[0].w

struct AreaLight
{
			float3 position;
		uint lightMask;
		float4 diffuse;		//[0].w contains diffuse mipmap start
	float4 specular;	//[0].w contains mipmap scale
	float4 attenuation;	//.w contains texture array idx
	//Custom 2D Shape:
	//  direction.xyz direction
	//  direction.w invHalfRectSize.x
	//  tangent.xyz tangent
	//  tangent.w invHalfRectSize.y
	float4 direction;
	float4 tangent;
	float4 doubleSided;	//.y contains numAreaApproxLights
						//.z contains numAreaApproxLightsWithMask
	};

struct AreaLtcLight
{
			float3 position;
		uint lightMask;
		float4 diffuse;			//.w contains attenuation range
	float4 specular;		//.w contains doubleSided
	float4 points[4];		//.w contains numAreaLtcLights
							//points[1].w, points[2].w, points[3].w contain obbFadeFactorLtc.xyz
	};





//Uniforms that change per pass
CONST_BUFFER_STRUCT_BEGIN( PassBuffer, 0 )
{
	//Vertex shader (common to both receiver and casters)

float4x4 viewProj;




//Vertex shader
float4x4 view;
ShadowReceiverData shadowRcv[3];

//-------------------------------------------------------------------------

//Pixel shader
float3x3 invViewMatCubemap;

float padding; //Compatibility with GLSL

float4 pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps;

float4 aspectRatio_planarReflNumMips_unused2;

float2 invWindowRes;
float2 windowResolution;


float4 ambientUpperHemi;

float4 ambientLowerHemi;
float4 ambientHemisphereDir;




float pssmSplitPoints0;
float pssmSplitPoints1;
float pssmSplitPoints2;
float pssmBlendPoints0;
float pssmBlendPoints1;
float pssmFadePoint;

Light lights[1];		// !use_light_buffers











#define pccVctMinDistance		pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps.x
#define invPccVctInvDistance	pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps.y
#define rightEyePixelStartX		pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps.z
#define envMapNumMipmaps		pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps.w

#define aspectRatio			aspectRatio_planarReflNumMips_unused2.x
#define planarReflNumMips	aspectRatio_planarReflNumMips_unused2.y
}
CONST_BUFFER_STRUCT_END( passBuf );


#define light0Buf		passBuf
#define light1Buf		passBuf
#define light2Buf		passBuf

// use_light_buffers


	
	
//Uniforms that change per Item/Entity, but change very infrequently
struct Material
{
	/* kD is already divided by PI to make it energy conserving.
	  (formula is finalDiffuse = NdotL * surfaceDiffuse / PI)
	*/
	float4 bgDiffuse;
	float4 kD; //kD.w is alpha_test_threshold
	float4 kS; //kS.w is roughness
	//Fresnel coefficient, may be per colour component (float3) or scalar (float)
	//F0.w is transparency
	float4 F0;
	float4 normalWeights;
	float4 cDetailWeights;
	float4 detailOffsetScale[4];
	float4 emissive;		//emissive.w contains mNormalMapWeight.
	float refractionStrength;
	float clearCoat;
	float clearCoatRoughness;
	float _padding1;
	float4 userValue[3];


	uint4 indices0_3;
	uint4 indices4_7;


};
	#define normalMapWeight material.emissive.w
	
	CONST_BUFFER( MaterialBuf, 1 )
	{
		Material materialArray[2];
	};

	
	//Uniforms that change per Item/Entity
	CONST_BUFFER( InstanceBuffer, 2 )
	{
		//.x =
		//The lower 9 bits contain the material's start index.
		//The higher 23 bits contain the world matrix start index.
		//
		//.y =
		//shadowConstantBias. Send the bias directly to avoid an
		//unnecessary indirection during the shadow mapping pass.
		//Must be loaded with uintBitsToFloat
		//
		//.z =
		//lightMask. Ogre must have been compiled with OGRE_NO_FINE_LIGHT_MASK_GRANULARITY
		
			uint4 worldMaterialIdx[2];
				};

	


// END UNIFORM DECLARATION


	#define float_fresnel midf
	#define float_fresnel_c( x ) midf_c( x )
	#define make_float_fresnel( x ) midf_c( x )



		#define OGRE_DEPTH_CMP_GE( a, b ) (a) <= (b)
	#define OGRE_DEPTH_DEFAULT_CLEAR 0.0



	#define PASSBUF_ARG_DECL
	#define PASSBUF_ARG




struct PixelData
{
	
		midf3 normal;
		
			midf3 geomNormal;
		
		
		midf4	diffuse;
		midf3	specular;

		

		midf	perceptualRoughness;
		midf	roughness;
		float_fresnel	F0;

		
			midf3	viewDir;
			midf	NdotV;
		

		
			midf3 reflDir;
			
				midf3 envColourS;
				midf3 envColourD;

				
			
		
	

	
};

#define SampleDetailWeightMap( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )

	#define SampleDetailCol0( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )

	#define SampleDetailCol1( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )

	#define SampleDetailCol2( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )

	#define SampleDetailCol3( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )


	#define SampleDiffuse( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx ) 









	INLINE midf3 reconstructZfromTSNormal( midf2 tsNormal2 )
	{
		midf3 tsNormal;
		tsNormal.xy = tsNormal2.xy;
		tsNormal.z	= sqrt( max( _h(0.0f), _h(1.0f) - tsNormal.x * tsNormal.x - tsNormal.y * tsNormal.y ) );
		return tsNormal.xyz;
	}

	
		//Normal texture must be in UV8/RG8_SNORM or BC5S format!
		#define getTSNormal( normalMap, samplerState, uv, normalIdx ) reconstructZfromTSNormal( OGRE_SampleArray2DF16( normalMap, samplerState, uv, normalIdx ).xy )
	
	
	
	





	

	
//Cook-Torrance
INLINE midf3 BRDF( midf3 lightDir, midf3 lightDiffuse, midf3 lightSpecular, PixelData pixelData PASSBUF_ARG_DECL )
{
	midf3 halfWay = normalize( lightDir + pixelData.viewDir );
	midf NdotL = saturate( dot( pixelData.normal, lightDir ) );
	midf NdotH = clamp( dot( pixelData.normal, halfWay ), _h( 0.001 ), _h( 1.0 ) );
	midf VdotH = clamp( dot( pixelData.viewDir, halfWay ), _h( 0.001 ), _h( 1.0 ) );

midf sqR = pixelData.roughness * pixelData.roughness;

//Roughness/Distribution/NDF term (Beckmann distribution)
//Formula:
//	Where alpha = NdotH and m = roughness
//	R = [ 1 / (m^2 x cos(alpha)^4 ] x [ e^( -tan(alpha)^2 / m^2 ) ]
//	R = [ 1 / (m^2 x cos(alpha)^4 ] x [ e^( ( cos(alpha)^2 - 1 )  /  (m^2 cos(alpha)^2 ) ]

midf NdotH_sq = NdotH * NdotH;
midf roughness_b = NdotH_sq - _h( 1.0 );	//( cos(alpha)^2 - 1 )

midf roughness_a = _h( 1.0 ) / ( _h( 3.141592654 ) * sqR * NdotH_sq * NdotH_sq );//( 1 / (m^2 x cos(alpha)^4 )
midf roughness_c = sqR * NdotH_sq;			//( m^2 cos(alpha)^2 )

//Avoid Inf * 0 = NaN; we need Inf * 0 = 0
midf R = min( roughness_a, _h( 65504.0 ) ) * exp( roughness_b / roughness_c );

ensureValidRangeF16( R );

//Geometric/Visibility term (Cook Torrance)
midf shared_geo = _h( 2.0 ) * NdotH / VdotH;
ensureValidRangeF16( shared_geo );
midf geo_b	= shared_geo * pixelData.NdotV;
midf geo_c	= shared_geo * NdotL;
midf G	 	= min( _h( 1.0 ), min( geo_b, geo_c ) );

//Fresnel term (Schlick's approximation)
//Formula:
//	fresnelS = lerp( (1 - V*H)^5, 1, F0 )
//	fresnelD = lerp( (1 - N*L)^5, 1, 1 - F0 ) [See s2010_course_note_practical_implementation_at_triace.pdf]
float_fresnel fresnelS = pixelData.F0 + pow( _h( 1.0 ) - VdotH, _h( 5.0 ) ) * (_h( 1.0 ) - pixelData.F0);

	
		midf fresnelD = _h( 1.0f ) - fresnelS;
	


//Avoid very small denominators, they go to NaN or cause aliasing artifacts
float_fresnel Rs = ( fresnelS * (R * G)  ) / max( _h( 4.0 ) * pixelData.NdotV * NdotL, _h( 0.01 ) );

return NdotL * (pixelData.specular.xyz * lightSpecular * Rs +
				pixelData.diffuse.xyz * lightDiffuse * fresnelD);
}

	
	













struct PS_INPUT
{

		
		FLAT_INTERPOLANT( ushort drawId, 0 );
		

	
		INTERPOLANT( float3 pos, 1 );
		INTERPOLANT( midf3 normal, 2 );
		
			INTERPOLANT( midf3 tangent, 3 );
			FLAT_INTERPOLANT( midf biNormalReflection, 4 );							
		INTERPOLANT( float2 uv0, 5 );
		INTERPOLANT( float2 uv1, 6 );
	
		
			
				INTERPOLANT( float4 posL0, 7 );
						
			
				INTERPOLANT( float4 posL1, 8 );
						
			
				INTERPOLANT( float4 posL2, 9 );
								
	INTERPOLANT( float depth, 10 );		
	
				

};




















Texture2DArray textureMaps0 : register(t3);
Texture2DArray textureMaps1 : register(t4);
Texture2DArray textureMaps2 : register(t5);
Texture2DArray textureMaps3 : register(t6);




SamplerState samplerState3 : register(s3);









#define hlms_shadowmap0 texShadowMap0
#define hlms_shadowmap0_uv_min float2( 0.000000, 0.000000 )
#define hlms_shadowmap0_uv_max float2( 1.000000, 0.285714 )

						#define hlms_shadowmap0_uv_param , hlms_shadowmap0_uv_min, hlms_shadowmap0_uv_max
		
#define hlms_shadowmap1 texShadowMap0
#define hlms_shadowmap1_uv_min float2( 0.000000, 0.285714 )
#define hlms_shadowmap1_uv_max float2( 0.500000, 0.428571 )

						#define hlms_shadowmap1_uv_param , hlms_shadowmap1_uv_min, hlms_shadowmap1_uv_max
		
#define hlms_shadowmap2 texShadowMap0
#define hlms_shadowmap2_uv_min float2( 0.500000, 0.285714 )
#define hlms_shadowmap2_uv_max float2( 1.000000, 0.428571 )

						#define hlms_shadowmap2_uv_param , hlms_shadowmap2_uv_min, hlms_shadowmap2_uv_max
		



#define OGRE_SAMPLE_SHADOW( tex, sampler, uv, depth ) (OGRE_DEPTH_CMP_GE( depth, OGRE_DEPTH_DEFAULT_CLEAR ) ? _h( 1.0 ) : midf_c( tex.SampleCmpLevelZero( sampler, uv.xy, depth ).x ))
#define OGRE_SAMPLE_SHADOW_ESM( tex, sampler, uv ) tex.SampleLevel( sampler, uv, 0 ).x



	SamplerComparisonState shadowSampler: register(s2);
	
		Texture2D<float> texShadowMap0				: register(t2);	


		
		
			#define inPs_posL0 inPs.posL0
				
		
			#define inPs_posL1 inPs.posL1
				
		
			#define inPs_posL2 inPs.posL2
					

	// Perform normal offset bias. See https://github.com/OGRECave/ogre-next/issues/100
	INLINE float3 getNormalOffsetBiasPoint( midf3 geomNormal, float3 lightDir,
											float normalOffsetBias, float shadowMapTexSize,
											float depthRange
	
											)
			{
		float tmpNdotL = saturate( dot( lightDir.xyz, float3( geomNormal.xyz ) ) );

		
		return ( ( 1.0f - tmpNdotL ) * normalOffsetBias * float3( geomNormal.xyz ) * shadowMapTexSize );
	}

	// Perform normal offset bias. See https://github.com/OGRECave/ogre-next/issues/100
	INLINE float3 getNormalOffsetBiasPoint( midf3 geomNormal, float3 lightDir,
											float normalOffsetBias, float shadowMapTexSize,
											float depthRange
													, float2 minUV, float2 maxUV )
			{
		float tmpNdotL = saturate( dot( lightDir.xyz, float3( geomNormal.xyz ) ) );

		
			shadowMapTexSize /= maxUV.x - minUV.x;
		
		return ( ( 1.0f - tmpNdotL ) * normalOffsetBias * float3( geomNormal.xyz ) * shadowMapTexSize );
	}


	INLINE midf getShadow( Texture2D<float> shadowMap, SamplerComparisonState shadowSampler, 
							float4 psPosLN, float4 invShadowMapSize )
	{

	//Spot and directional lights
	
		float fDepth = psPosLN.z / psPosLN.w;
			float2 uv = float2( psPosLN.xy / psPosLN.w );


	midf retVal = _h( 0. );

	
		float2 offsets[4] =
					{
					
			float2( 0., 0. ),	//0, 0
			float2( 1., 0. ),	//1, 0
			float2( 0., 1. ),	//1, 1
			float2(-1., 0. ) 	//0, 1
																	};
				
	
	
		
			uv += offsets[0] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[1] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[2] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[3] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );		
	
		retVal *= _h( 0.25 );
		///! exponential_shadow_maps
   ///! exponential_shadow_maps



	return retVal;
}


	INLINE midf getShadow( Texture2D<float> shadowMap, SamplerComparisonState shadowSampler, 
							float4 psPosLN, float4 invShadowMapSize, float2 minUV, float2 maxUV )
	{

	//Spot and directional lights
	
		float fDepth = psPosLN.z / psPosLN.w;
			float2 uv = float2( psPosLN.xy / psPosLN.w );


	midf retVal = _h( 0. );

	
		float2 offsets[4] =
					{
					
			float2( 0., 0. ),	//0, 0
			float2( 1., 0. ),	//1, 0
			float2( 0., 1. ),	//1, 1
			float2(-1., 0. ) 	//0, 1
																	};
				
	
	
		
			uv += offsets[0] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[1] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[2] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[3] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );		
	
		retVal *= _h( 0.25 );
		///! exponential_shadow_maps
   ///! exponential_shadow_maps



	retVal = (uv.x <= minUV.x || uv.x >= maxUV.x ||
			  uv.y <= minUV.y || uv.y >= maxUV.y) ? _h( 1.0 ) : retVal;

	return retVal;
}


	INLINE midf getShadowPoint( Texture2D<float> shadowMap, SamplerComparisonState shadowSampler, 
								 midf3 geomNormal, float normalOffsetBias,
								 float3 posVS, float3 lightPos,float4 invShadowMapSize, float2 invDepthRange
								 PASSBUF_ARG_DECL )
	{
		//Point lights
	float3 cubemapDir = posVS.xyz - lightPos.xyz;
	cubemapDir += getNormalOffsetBiasPoint( geomNormal, cubemapDir, normalOffsetBias,
			
											invShadowMapSize.x, invDepthRange.y );
			
	float fDepth = length( cubemapDir );
	cubemapDir *= 1.0 / fDepth;
	cubemapDir = mul( cubemapDir.xyz, passBuf.invViewMatCubemap );
				fDepth = (invDepthRange.x - fDepth) * invDepthRange.y;
	
	float2 uv;
	uv.x = (cubemapDir.x / (1.0 + abs( cubemapDir.z ))) * 0.25 +
			(cubemapDir.z < 0.0 ? 0.75 : 0.25 );
	uv.y = (cubemapDir.y / (1.0 + abs( cubemapDir.z ))) * 0.5 + 0.5;

		

	midf retVal = _h( 0. );

	
		float2 offsets[4] =
					{
					
			float2( 0., 0. ),	//0, 0
			float2( 1., 0. ),	//1, 0
			float2( 0., 1. ),	//1, 1
			float2(-1., 0. ) 	//0, 1
																	};
				
	
	
		
			uv += offsets[0] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[1] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[2] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[3] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );		
	
		retVal *= _h( 0.25 );
		///! exponential_shadow_maps
   ///! exponential_shadow_maps



	return retVal;
}


	INLINE midf getShadowPoint( Texture2D<float> shadowMap, SamplerComparisonState shadowSampler, 
								 midf3 geomNormal, float normalOffsetBias,
								 float3 posVS, float3 lightPos, float4 invShadowMapSize, float2 invDepthRange,
								 float2 minUV, float2 maxUV, float2 lengthUV
								 PASSBUF_ARG_DECL )
	{
		//Point lights
	float3 cubemapDir = posVS.xyz - lightPos.xyz;
	cubemapDir += getNormalOffsetBiasPoint( geomNormal, cubemapDir, normalOffsetBias,
															invShadowMapSize.x, invDepthRange.y, minUV, maxUV );
			
	float fDepth = length( cubemapDir );
	cubemapDir *= 1.0 / fDepth;
	cubemapDir = mul( cubemapDir.xyz, passBuf.invViewMatCubemap );
				fDepth = (invDepthRange.x - fDepth) * invDepthRange.y;
	
	float2 uv;
	uv.x = (cubemapDir.x / (1.0 + abs( cubemapDir.z ))) * 0.25 +
			(cubemapDir.z < 0.0 ? 0.75 : 0.25 );
	uv.y = (cubemapDir.y / (1.0 + abs( cubemapDir.z ))) * 0.5 + 0.5;

	uv.xy = uv.xy * lengthUV.xy + minUV.xy;	

	midf retVal = _h( 0. );

	
		float2 offsets[4] =
					{
					
			float2( 0., 0. ),	//0, 0
			float2( 1., 0. ),	//1, 0
			float2( 0., 1. ),	//1, 1
			float2(-1., 0. ) 	//0, 1
																	};
				
	
	
		
			uv += offsets[0] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[1] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[2] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[3] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );		
	
		retVal *= _h( 0.25 );
		///! exponential_shadow_maps
   ///! exponential_shadow_maps



	retVal = (uv.x <= minUV.x || uv.x >= maxUV.x ||
			  uv.y <= minUV.y || uv.y >= maxUV.y) ? _h( 1.0 ) : retVal;

	return retVal;
}



	        		
		Texture2DArray<float4> ltcMatrix	: register(t1);
		SamplerState ltcSampler				: register(s1);
				






struct PS_OUTPUT
{
	
		
			float4 colour0 : SV_Target0;
		
	

	
	
	

	
};




PS_OUTPUT main
(
	PS_INPUT inPs
	


)
{
	PS_OUTPUT outPs;
	







	PixelData pixelData;

	

	
        ushort materialId	= worldMaterialIdx[inPs.drawId].x & 0x1FFu;
        #define material materialArray[materialId]
	


	

			ushort texIndex_diffuseIdx			= material.indices0_3.x & 0x0000FFFFu;
		ushort texIndex_weightMapIdx		= material.indices0_3.z & 0x0000FFFFu;
			ushort texIndex_detailMapIdx0		= material.indices0_3.z >> 16u;
			ushort texIndex_detailMapIdx1		= material.indices0_3.w & 0x0000FFFFu;
			ushort texIndex_detailMapIdx2		= material.indices0_3.w >> 16u;
			ushort texIndex_detailMapIdx3		= material.indices4_7.x & 0x0000FFFFu;


	

			ushort texIndex_normalIdx			= material.indices0_3.x >> 16u;
	
	
	
	
	
	
	
	


	uint objLightMask = worldMaterialIdx[inPs.drawId].z;
	

	

	//Prepare weight map for the detail maps.
	
		midf4 detailWeights = SampleDetailWeightMap( textureMaps2,
													  samplerState3,
													  UV_DETAIL_WEIGHT( inPs.uv0.xy ),
													  texIndex_weightMapIdx );
		
	



	
/// Sample detail maps and weight them against the weight map in the next foreach loop.

	
		midf4 detailCol0 = SampleDetailCol0( textureMaps3,
												samplerState3,
												UV_DETAIL0( inPs.uv0.xy * material.detailOffsetScale[0].zw + material.detailOffsetScale[0].xy ),
                                                texIndex_detailMapIdx0 );
		detailWeights.x *= detailCol0.w;
		detailCol0.w = detailWeights.x;
	

	
		midf4 detailCol1 = SampleDetailCol1( textureMaps0,
												samplerState3,
												UV_DETAIL1( inPs.uv0.xy * material.detailOffsetScale[1].zw + material.detailOffsetScale[1].xy ),
                                                texIndex_detailMapIdx1 );
		detailWeights.y *= detailCol1.w;
		detailCol1.w = detailWeights.y;
	

	
		midf4 detailCol2 = SampleDetailCol2( textureMaps0,
												samplerState3,
												UV_DETAIL2( inPs.uv0.xy * material.detailOffsetScale[2].zw + material.detailOffsetScale[2].xy ),
                                                texIndex_detailMapIdx2 );
		detailWeights.z *= detailCol2.w;
		detailCol2.w = detailWeights.z;
	

	
		midf4 detailCol3 = SampleDetailCol3( textureMaps0,
												samplerState3,
												UV_DETAIL3( inPs.uv0.xy * material.detailOffsetScale[3].zw + material.detailOffsetScale[3].xy ),
                                                texIndex_detailMapIdx3 );
		detailWeights.w *= detailCol3.w;
		detailCol3.w = detailWeights.w;
	



	
		
/// DIFFUSE MAP

	pixelData.diffuse = SampleDiffuse( textureMaps0,
									   samplerState3,
									   UV_DIFFUSE( inPs.uv0.xy ),
									   texIndex_diffuseIdx );


/// Blend the detail diffuse maps with the main diffuse.

	
//Normal Non Premultiplied 0
pixelData.diffuse.xyz = lerp( pixelData.diffuse.xyz, detailCol0.xyz, detailCol0.a );
pixelData.diffuse.w = lerp( pixelData.diffuse.w, _h( 1.0 ), detailCol0.w );
  
	
//Normal Non Premultiplied 1
pixelData.diffuse.xyz = lerp( pixelData.diffuse.xyz, detailCol1.xyz, detailCol1.a );
pixelData.diffuse.w = lerp( pixelData.diffuse.w, _h( 1.0 ), detailCol1.w );
  
	
//Normal Non Premultiplied 2
pixelData.diffuse.xyz = lerp( pixelData.diffuse.xyz, detailCol2.xyz, detailCol2.a );
pixelData.diffuse.w = lerp( pixelData.diffuse.w, _h( 1.0 ), detailCol2.w );
  
	
//Normal Non Premultiplied 3
pixelData.diffuse.xyz = lerp( pixelData.diffuse.xyz, detailCol3.xyz, detailCol3.a );
pixelData.diffuse.w = lerp( pixelData.diffuse.w, _h( 1.0 ), detailCol3.w );
  

/// Apply the material's diffuse over the textures
pixelData.diffuse.xyz *= midf3_c( material.kD.xyz );




	

	
/// SPECUlAR MAP
pixelData.specular.xyz = midf3_c( material.kS.xyz );

	pixelData.F0 = float_fresnel_c( material.F0.x );
	
	



	
	
/// ROUGHNESS MAP
pixelData.perceptualRoughness = midf_c( material.kS.w );





	pixelData.roughness = max( pixelData.perceptualRoughness * pixelData.perceptualRoughness, _h( 0.001f ) );





	
		
// Geometric normal
pixelData.geomNormal = normalize( inPs.normal ) ;

	

	

	
		

	//Normal mapping.
	pixelData.geomNormal = normalize( inPs.normal ) ;
	midf3 vTangent		= normalize( inPs.tangent );

	
		
	

	//Get the TBN matrix
	midf3 vBinormal	= normalize( cross( pixelData.geomNormal, vTangent ) * inPs.biNormalReflection );
	midf3x3 TBN		= buildMidf3x3( vTangent, vBinormal, pixelData.geomNormal );

	
		pixelData.normal = getTSNormal( textureMaps1,
										samplerState3,
										UV_NORMAL( inPs.uv0.xy ),
										texIndex_normalIdx );
	
	
		// Apply the weight to the main normal map
		pixelData.normal = lerp( midf3_c( 0.0, 0.0, 1.0 ), pixelData.normal, normalMapWeight );
	


		
/// If there is no normal map, the first iteration must
/// initialize pixelData.normal instead of try to merge with it.

	
	






/// Blend the detail normal maps with the main normal.




		

		

		
			pixelData.normal = normalize( mul( TBN, pixelData.normal ) );
		

		

	midf fShadow = _h( 1.0 );

	midf fShadowBlend = _h( 1.0 );
	
	if( inPs.depth <= passBuf.pssmSplitPoints0 )
	{
		fShadow = getShadow( hlms_shadowmap0, shadowSampler, 
							 inPs_posL0,
							 passBuf.shadowRcv[0].invShadowMapSize
							 hlms_shadowmap0_uv_param );
		
			if( inPs.depth > passBuf.pssmBlendPoints0 )
			{
				fShadowBlend = getShadow( hlms_shadowmap1, shadowSampler, 
										  inPs_posL1,
										  passBuf.shadowRcv[1].invShadowMapSize
										  hlms_shadowmap1_uv_param );
				fShadow = lerp(
					fShadow, fShadowBlend,
					midf_c( ( inPs.depth - passBuf.pssmBlendPoints0 ) /
							( passBuf.pssmSplitPoints0 -
							  passBuf.pssmBlendPoints0 ) ) );
			}
							}
	
	else if( inPs.depth <= passBuf.pssmSplitPoints1 )
	{
		fShadow = getShadow( hlms_shadowmap1, shadowSampler, 
							 inPs_posL1,
							 passBuf.shadowRcv[1].invShadowMapSize
							 hlms_shadowmap1_uv_param );
		
			if( inPs.depth > passBuf.pssmBlendPoints1 )
			{
				fShadowBlend = getShadow( hlms_shadowmap2, shadowSampler, 
										  inPs_posL2,
										  passBuf.shadowRcv[2].invShadowMapSize
										  hlms_shadowmap2_uv_param );
				fShadow = lerp(
					fShadow, fShadowBlend,
					midf_c( ( inPs.depth - passBuf.pssmBlendPoints1 ) /
							( passBuf.pssmSplitPoints1 -
							  passBuf.pssmBlendPoints1 ) ) );
			}
							}
	else if( inPs.depth <= passBuf.pssmSplitPoints2 )
	{
		fShadow = getShadow( hlms_shadowmap2, shadowSampler, 
							 inPs_posL2,
							 passBuf.shadowRcv[2].invShadowMapSize
							 hlms_shadowmap2_uv_param );
		
			if( inPs.depth > passBuf.pssmFadePoint )
			{
				fShadow = lerp( fShadow, _h( 1.0 ),
								midf_c( ( inPs.depth - passBuf.pssmFadePoint ) /
										( passBuf.pssmSplitPoints2 -
										  passBuf.pssmFadePoint ) ) );
			}
							}	

	

	
		
//Everything's in Camera space

	
		pixelData.viewDir	= midf3_c( normalize( -inPs.pos ) );
	
	pixelData.NdotV		= saturate( dot( pixelData.normal, pixelData.viewDir ) );



	midf3 finalColour = midf3_c(0, 0, 0);



	float3 lightDir;
	float fDistance;
	midf3 tmpColour;
	midf spotCosAngle;





	pixelData.reflDir = _h( 2.0 ) * dot( pixelData.viewDir, pixelData.normal ) * pixelData.normal -
						pixelData.viewDir;



	midf ambientWD =
		dot( midf3_c( passBuf.ambientHemisphereDir.xyz ), pixelData.normal ) * _h( 0.5 ) + _h( 0.5 );
	midf ambientWS =
		dot( midf3_c( passBuf.ambientHemisphereDir.xyz ), pixelData.reflDir ) * _h( 0.5 ) + _h( 0.5 );



		

		
			

	if( (objLightMask & light0Buf.lights[0].lightMask) != 0u )
		finalColour += BRDF( midf3_c( light0Buf.lights[0].position.xyz ),
							 midf3_c( light0Buf.lights[0].diffuse.xyz ),
							 midf3_c( light0Buf.lights[0].specular ), pixelData PASSBUF_ARG ) * fShadow;




	


		

		




		





		
		

		

		
			pixelData.envColourS = midf3_c( 0, 0, 0 );
			pixelData.envColourD = midf3_c( 0, 0, 0 );

			
		

		
		

		
		

		



		

		

		

		


	
		float tmpAmbientWS = ambientWD;
		float tmpAmbientWD = ambientWS;
							pixelData.envColourS += lerp( midf3_c( passBuf.ambientLowerHemi.xyz ),
										  midf3_c( passBuf.ambientUpperHemi.xyz ), tmpAmbientWS );
			pixelData.envColourD += lerp( midf3_c( passBuf.ambientLowerHemi.xyz ),
										  midf3_c( passBuf.ambientUpperHemi.xyz ), tmpAmbientWD );
		


		
			
//Normally we'd use VdotH. However:
//	H = normalize(lightDir + viewDir)
//since:
//	lightDir = pixelData.reflDir
//then:
//	H = geomNormal
//Thus H = N, and therefore we use VdotN (NdotV)
//float VdotH = saturate( dot( pixelData.viewDir, normalize( pixelData.reflDir + pixelData.viewDir ) ) );
float_fresnel fresnelS = pixelData.F0 + pow( _h( 1.0 ) - pixelData.NdotV, _h( 5.0 ) ) * (max( make_float_fresnel( _h( 1.0 ) - pixelData.perceptualRoughness ), pixelData.F0 ) - pixelData.F0);


	#define brdfLUT ltcMatrix
	midf3 envBRDF = OGRE_SampleArray2DF16( brdfLUT, ltcSampler,
										   float2( pixelData.NdotV,
												   1.0 - pixelData.perceptualRoughness ), 2 ).xyz;



	
		midf fresnelD = _h( 1.0f ) - fresnelS;
	


    midf3 Rd = pixelData.envColourD * pixelData.diffuse.xyz * _h( 3.141592654 ) * fresnelD * envBRDF.z;
    midf3 Rs = pixelData.envColourS * pixelData.specular.xyz *

                ( fresnelS * envBRDF.x + envBRDF.y );




finalColour += Rd + Rs;

		

		

		
	///!hlms_prepass

///!hlms_normal || hlms_qtangent


	
		
			
				outPs_colour0.xyz	= finalColour;
			

			

	midf finalAlpha = _h( 1.0f );


			outPs_colour0.w = finalAlpha;

						
			
		
	







return outPs;

}

I'm struggling with this topic for days now. Even with AI, we are not able to find a solution. I debugged deep into Ogre.

This is the material.json with the detail normal map textures:

Code: Select all

{
    "comment" :
    [
        "PlanetTerra default PBS material - INITIAL TEMPLATE ONLY.",
        "DatablockPbsComponent clones this on first use and stores its own per-instance data.",
        "",
        "Normal maps: all detail NMs must be BC5_SNORM DDS.",
        "UV scale: adjust via PlanetTerraComponent AttrDetailUVScale (default 128)."
    ],

"samplers" :
{
    "PlanetTerra_Sampler" :
    {
        "min"              : "anisotropic",
        "mag"              : "anisotropic",
        "mip"              : "anisotropic",
        "u"                : "wrap",
        "v"                : "wrap",
        "w"                : "wrap",
        "miplodbias"       : 0,
        "max_anisotropic"  : 8,
        "compare_function" : "disabled",
        "border"           : [1, 1, 1, 1],
        "min_lod"          : -3.40282e+38,
        "max_lod"          : 3.40282e+38
    }
},

"macroblocks" :
{
    "PlanetTerra_Macroblock" :
    {
        "scissor_test"           : false,
        "depth_check"            : true,
        "depth_write"            : true,
        "depth_function"         : "less_equal",
        "depth_bias_constant"    : 0,
        "depth_bias_slope_scale" : 0,
        "cull_mode"              : "clockwise",
        "polygon_mode"           : "solid"
    }
},

"blendblocks" :
{
    "PlanetTerra_Blendblock" :
    {
        "alpha_to_coverage"  : false,
        "blendmask"          : "rgba",
        "separate_blend"     : false,
        "src_blend_factor"   : "one",
        "dst_blend_factor"   : "zero",
        "blend_operation"    : "add"
    }
},

"pbs" :
{
    "PlanetTerraDefaultMaterial" :
    {
        "macroblock"        : "PlanetTerra_Macroblock",
        "blendblock"        : "PlanetTerra_Blendblock",
        "shadow_const_bias" : 0.001,

        "workflow" : "specular_fresnel",
        "brdf"     : "cook_torrance",

        "roughness" : 0.85,

        "fresnel" :
        {
            "value" : 0.02,
            "mode"  : "coeff"
        },

        "specular" :
        {
            "value" : [0.04, 0.04, 0.04]
        },

        "diffuse" :
        {
            "value"      : [1, 1, 1],
            "background" : [1, 1, 1, 1],
            "texture"    : "ground_dirt_gardenD.png",
            "sampler"    : "PlanetTerra_Sampler"
        },
		
		"normal" :
        {
            "comment" : "flat_normal.dds (BC5_SNORM) - required to declare textureMaps array in shader.",
            "value"   : 0.0,
            "texture" : "ground_dirt_gardenN.dds",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_weight" :
        {
            "texture" : "PlanetTerraBlendDefault.png",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_diffuse0" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "adesert_cracks_d.jpg",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_normal0" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "adesert_cracks_n.dds",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_diffuse1" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "grass_green_d.jpg",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_normal1" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "grass_green_n.dds",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_diffuse2" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "island_sand_d.jpg",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_normal2" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "island_sand_n.dds",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_diffuse3" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "mntn_black_d.jpg",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_normal3" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "mntn_black_n.dds",
            "sampler" : "PlanetTerra_Sampler"
        }
    }
}
}

Note: All textures do exist etc. I checked already lots of stuff.

Best Regards
Lax

http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5560
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1403

Re: Ogre::PBSM_DETAIL0_NM Bug in Ogre-Next?

Post by dark_sylinc »

The shader you uploaded seems to be the wrong one. There is no line 1100 with code and searching for '@' results in nothing except in the #if 0 #endif block.

Lax
Orc Shaman
Posts: 711
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 75

Re: Ogre::PBSM_DETAIL0_NM Bug in Ogre-Next?

Post by Lax »

Hi,

arg sorry. I tested so much, that i got confused.

I simplified the scenario:

PlanetTerraDefaultMaterial json loaded at startup, datablock assigned to item by
name only — no C++ setTexture() calls whatsoever for the NM slots.

MATERIAL: base diffuse + base normal (BC5_SNORM) + detail_weight + 4x detail_diffuse
(jpg, NormalNonPremul) + 4x detail_normal (BC5_SNORM DDS, all different files,
same resolution).

Works fine with detail_diffuse only. Crashes as soon as detail_normal0..3 are
defined in the JSON.

The crashing shader property dump shows:

Code: Select all

detail_map_nm0_idx = 4
detail_map_nm1_idx = 4    <- all four identical
detail_map_nm2_idx = 4
detail_map_nm3_idx = 4
num_textures       = 5    <- should be 8
num_samplers       = 1    <- should be 2

All four BC5_SNORM DDS textures collapse to the same pool slot. HLMS then only
inlines SampleDetailMapNm0 — SampleDetailMapNm1/2/3 are emitted as raw @piece()
definition headers literally into the HLSL output, causing:

Code: Select all

error X3000: syntax error: unexpected token '@'
error X3004: undeclared identifier 'textureMaps'

Code: Select all

#if 0
	***	textureMaps3	6
	***	hlms_uv_count0	2
	***	hlms_pose	0
	***	uv_emissive	0
	***	textureMaps4	7
	***	first_valid_detail_map_nm	0
	***	fresnel_scalar	0
	***	hlms_shadowmap2_uv_max_y	1054567864
	***	envprobe_map_sampler	3
	***	hlms_uv_count	2
	***	detail_map1	1
	***	pcf_iterations	4
	***	uv_detail_nm1	0
	***	uv_detail_nm2	0
	***	envMapRegSampler	3
	***	emissive_map_sampler	3
	***	hlms_tex_gather	1
	***	precision_mode	-2126167738
	***	hlms_shadowmap2_array_idx	0
	***	set0_texture_slot_end	3
	***	uv_specular	0
	***	hlms_disable_stage	0
	***	NumPoseWeightVectors	0
	***	hlms_shadowmap1_uv_min_x	0
	***	specular_map_sampler	3
	***	hlms_shadowmap0_uv_min_y	0
	***	texcoord	11
	***	fast_shader_build_hack	1
	***	glsl	635204550
	***	normal_weight_tex	1
	***	normal_sampling_format	-1392068498
	***	hlms_uv_count1	2
	***	NumPoseWeightVectorsB	0
	***	detail_map2	1
	***	hlms_num_shadow_map_lights	3
	***	hlms_lights_directional	1
	***	samplerStateStart	3
	***	detail_map3	1
	***	alpha_test	0
	***	roughness_map_sampler	3
	***	detail_weight_map	3
	***	hlms_shadowmap2	0
	***	hlms_shadowmap0_light_idx	0
	***	StrongMacroblockBits	0
	***	metallic_workflow	0
	***	detail_map_nm1	5
	***	hw_gamma_write	1
	***	uv_detail_weight	0
	***	detail_map_nm0_idx	4
	***	detail_map_nm2_sampler	3
	***	hlms_shadowmap1_uvs_fulltex	1
	***	hlms_alpha_to_coverage	0
	***	cubemaps_as_diffuse_gi	1
	***	hlms_shadowmap2_uv_min_y	1049774373
	***	uv_detail_nm3	0
	***	NumPoseWeightVectorsC	0
	***	hlms_pssm_splits	3
	***	ambient_hemisphere_inverted	1
	***	hlms_pose_normals	0
	***	target_envprobe_map	1
	***	hlms_pose_half	0
	***	hlms_shadowmap1_light_idx	0
	***	hlms_lights_spot	1
	***	shadowmap2_is_directional_light	1
	***	hlms_shadowmap1_uv_max_x	1056964608
	***	hlms_shadowmap0_uv_min_x	0
	***	detail_map1_sampler	3
	***	uv_normal	0
	***	relaxed	1726237731
	***	hlms_shadowmap1_uv_min_y	1049774373
	***	detail_map_nm3_sampler	3
	***	hlms_alphablend	0
	***	textureMaps2	5
	***	detail_maps_normal	4
	***	hlms_num_shadow_map_textures	1
	***	detail_map_nm1_idx	4
	***	hlms_view_matrix	1
	***	MoreThanOnePose	-1
	***	hlms_shadowmap1_array_idx	0
	***	detail_map0	4
	***	num_textures	5
	***	hlslvk	1841745752
	***	normal_map_tex	2
	***	uv_detail3	0
	***	detail_maps_diffuse	4
	***	hlms_shadow_uses_depth_texture	1
	***	hlms_msaa_samples	1
	***	ltcMatrix	1
	***	detail_map3_sampler	3
	***	hlms_shadowmap0_uv_max_x	1065353216
	***	normal_map	1
	***	hlms_tangent	1
	***	hlms_shadowmap1	0
	***	needs_env_brdf	1
	***	NumPoseWeightVectorsA	0
	***	pcf	3
	***	uv_detail1	0
	***	fresnel_workflow	1
	***	shadowmap1_is_directional_light	1
	***	full32	-2126167738
	***	detail_map_nm0	5
	***	detail_map_nm3_idx	4
	***	perceptual_roughness	1
	***	alpha_test_shadow_caster_only	0
	***	materials_per_buffer	2
	***	hw_gamma_read	1
	***	normal_map_tex_idx	1
	***	detail_weight_map_idx	2
	***	hlms_skeleton	0
	***	hlms_pssm_splits_minus_one	2
	***	midf16	-1978079318
	***	partial_pso_clip_distances	0
	***	syntax	-334286542
	***	hlms_lights_point	1
	***	diffuse_map_sampler	3
	***	hlms_tangent4	1
	***	hlms_fine_light_mask	1
	***	metal	-1698855755
	***	fresnel_has_diffuse	1
	***	detail_map_nm1_sampler	3
	***	s_lights_directional_non_caster	1
	***	uv_detail0	0
	***	uv_diffuse	0
	***	diffuse_map	1
	***	needs_refl_dir	1
	***	hlms_pssm_blend	1
	***	uv_detail_nm0	0
	***	detail_weight_map_sampler	3
	***	detail_offsets3	1
	***	detail_offsets0	1
	***	normal_rg_snorm	-1392068498
	***	diffuse_map_idx	0
	***	detail_map_nm0_sampler	3
	***	hlms_shadowmap2_uv_max_x	1065353216
	***	hlms_shadowmap1_uv_max_y	1054567864
	***	hlms_shadowmap2_light_idx	0
	***	shadowmap0_is_directional_light	1
	***	hlms_shadowmap0_array_idx	0
	***	hlms_render_depth_only	0
	***	num_pass_const_buffers	4
	***	normal_map_tex_sampler	3
	***	uv_detail2	0
	***	MoreThanOnePoseWeightVector	-1
	***	detail_map2_sampler	3
	***	full_pso_clip_distances	0
	***	textureMaps0	3
	***	detail_map_nm3	5
	***	hlms_shadowmap0_uvs_fulltex	1
	***	detail_map0_sampler	3
	***	hlms_shadowmap2_uv_min_x	1056964608
	***	uv_roughness	0
	***	receive_shadows	1
	***	detail_offsets2	1
	***	textureMaps1	4
	***	detail_map3_idx	0
	***	hlms_pssm_fade	1
	***	hlms_shadowmap0	0
	***	detail_map0_idx	3
	***	needs_view_dir	1
	***	detail_map_nm2	5
	***	detail_map2_idx	0
	***	hlms_shadowmap2_uvs_fulltex	1
	***	BRDF_CookTorrance	1
	***	detail_map1_idx	0
	***	set1_texture_slot_end	8
	***	use_planar_reflections	0
	***	detail_map_nm2_idx	4
	***	texShadowMap0	2
	***	ambient_hemisphere	1
	***	hlms_normal	1
	***	ltc_texture_available	1
	***	num_samplers	1
	***	glslvk	-338983575
	***	hlsl	-334286542
	***	hlms_shadowmap0_uv_max_y	1049774373
	***	detail_offsets1	1
	***	normal_weight	1
	DONE DUMPING PROPERTIES
	***	blend_mode_idx3	@insertpiece( NormalNonPremul)
	***	hlms_shadowmap2_uv_max_y	0.428571
	***	hlms_shadowmap1_uv_min_x	0.000000
	***	hlms_shadowmap0_uv_min_y	0.000000
	***	blend_mode_idx2	@insertpiece( NormalNonPremul)
	***	hlms_shadowmap2_uv_min_y	0.285714
	***	hlms_shadowmap1_uv_max_x	0.500000
	***	hlms_shadowmap0_uv_min_x	0.000000
	***	hlms_shadowmap1_uv_min_y	0.285714
	***	hlms_shadowmap0_uv_max_x	1.000000
	***	hlms_shadowmap2_uv_max_x	1.000000
	***	hlms_shadowmap1_uv_max_y	0.428571
	***	blend_mode_idx1	@insertpiece( NormalNonPremul)
	***	hlms_shadowmap2_uv_min_x	0.500000
	***	blend_mode_idx0	@insertpiece( NormalNonPremul)
	***	hlms_shadowmap0_uv_max_y	0.285714
	DONE DUMPING PIECES
#endif

//#include "SyntaxHighlightingMisc.h"


#define ushort uint
#define ushort3 uint3
#define ushort4 uint4
#define ogre_float4x3 float4x3

//Short used for read operations. It's an int in GLSL & HLSL. An ushort in Metal
#define rshort int
#define rshort2 int2
#define rint int
//Short used for write operations. It's an int in GLSL. An ushort in HLSL & Metal
#define wshort2 uint2
#define wshort3 uint3

#define toFloat3x3( x ) ((float3x3)(x))
#define buildFloat3x3( row0, row1, row2 ) transpose( float3x3( row0, row1, row2 ) )

#define buildFloat4x4( row0, row1, row2, row3 ) transpose( float4x4( row0, row1, row2, row3 ) )

#define getMatrixRow( mat, idx ) transpose( mat )[idx]

// See CrossPlatformSettings_piece_all.glsl for an explanation

#define _h(x) (x)

#define midf float
#define midf2 float2
#define midf3 float3
#define midf4 float4
#define midf2x2 float2x2
#define midf3x3 float3x3
#define midf4x4 float4x4

#define midf_c float
#define midf2_c float2
#define midf3_c float3
#define midf4_c float4
#define midf2x2_c float2x2
#define midf3x3_c float3x3
#define midf4x4_c float4x4

#define toMidf3x3( x ) ((float3x3)( x ))
#define buildMidf3x3( row0, row1, row2 ) transpose( float3x3( row0, row1, row2 ) )

#define ensureValidRangeF16(x)

#define min3( a, b, c ) min( a, min( b, c ) )
#define max3( a, b, c ) max( a, max( b, c ) )

#define INLINE
#define NO_INTERPOLATION_PREFIX nointerpolation
#define NO_INTERPOLATION_SUFFIX

#define PARAMS_ARG_DECL
#define PARAMS_ARG

#define floatBitsToUint(x) asuint(x)
#define uintBitsToFloat(x) asfloat(x)
#define floatBitsToInt(x) asint(x)
#define fract frac
#define lessThan( a, b ) (a < b)

#define inVs_vertexId input.vertexId
#define inVs_vertex input.vertex
#define inVs_normal input.normal
#define inVs_tangent input.tangent
#define inVs_binormal input.binormal
#define inVs_blendWeights input.blendWeights
#define inVs_blendIndices input.blendIndices
#define inVs_qtangent input.qtangent
#define inVs_colour input.colour

#define inVs_drawId input.drawId

#define finalDrawId inVs_drawId


#define inVs_uv0 input.uv0
#define inVs_uv1 input.uv1
#define outVs_Position outVs.gl_Position
#define outVs_viewportIndex outVs.gl_ViewportIndex
#define outVs_clipDistance0 outVs.gl_ClipDistance0.x

#define gl_SampleMaskIn0 gl_SampleMask
#define interpolateAtSample( interp, subsample ) EvaluateAttributeAtSample( interp, subsample )
#define findLSB firstbitlow
#define findMSB firstbithigh
#define mod( a, b ) ( (a) - (b) * floor( (a) / (b) ) )

#define outPs_colour0 outPs.colour0
#define OGRE_Sample( tex, sampler, uv ) tex.Sample( sampler, uv )
#define OGRE_SampleLevel( tex, sampler, uv, lod ) tex.SampleLevel( sampler, uv, lod )
#define OGRE_SampleArray2D( tex, sampler, uv, arrayIdx ) tex.Sample( sampler, float3( uv, arrayIdx ) )
#define OGRE_SampleArray2DLevel( tex, sampler, uv, arrayIdx, lod ) tex.SampleLevel( sampler, float3( uv, arrayIdx ), lod )
#define OGRE_SampleArrayCubeLevel( tex, sampler, uv, arrayIdx, lod ) tex.SampleLevel( sampler, float4( uv, arrayIdx ), lod )
#define OGRE_SampleGrad( tex, sampler, uv, ddx, ddy ) tex.SampleGrad( sampler, uv, ddx, ddy )
#define OGRE_SampleArray2DGrad( tex, sampler, uv, arrayIdx, ddx, ddy ) tex.SampleGrad( sampler, float3( uv, arrayIdx ), ddx, ddy )
#define OGRE_ddx( val ) ddx( val )
#define OGRE_ddy( val ) ddy( val )
#define OGRE_Load2D( tex, iuv, lod ) tex.Load( int3( iuv, lod ) )
#define OGRE_LoadArray2D( tex, iuv, arrayIdx, lod ) tex.Load( int4( iuv, arrayIdx, lod ) )
#define OGRE_Load2DMS( tex, iuv, subsample ) tex.Load( iuv, subsample )

#define OGRE_Load3D( tex, iuv, lod ) tex.Load( int4( iuv, lod ) )

#define OGRE_Load2DF16( tex, iuv, lod ) tex.Load( int3( iuv, lod ) )
#define OGRE_Load2DMSF16( tex, iuv, subsample ) tex.Load( iuv, subsample )
#define OGRE_SampleF16( tex, sampler, uv ) tex.Sample( sampler, uv )
#define OGRE_SampleLevelF16( tex, sampler, uv, lod ) tex.SampleLevel( sampler, uv, lod )
#define OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx ) tex.Sample( sampler, float3( uv, arrayIdx ) )
#define OGRE_SampleArray2DLevelF16( tex, sampler, uv, arrayIdx, lod ) tex.SampleLevel( sampler, float3( uv, arrayIdx ), lod )
#define OGRE_SampleArrayCubeLevelF16( tex, sampler, uv, arrayIdx, lod ) tex.SampleLevel( sampler, float4( uv, arrayIdx ), lod )
#define OGRE_SampleGradF16( tex, sampler, uv, ddx, ddy ) tex.SampleGrad( sampler, uv, ddx, ddy )
#define OGRE_SampleArray2DGradF16( tex, sampler, uv, arrayIdx, ddx, ddy ) tex.SampleGrad( sampler, float3( uv, arrayIdx ), ddx, ddy )

#define bufferFetch( buffer, idx ) buffer.Load( idx )
#define bufferFetch1( buffer, idx ) buffer.Load( idx ).x

#define structuredBufferFetch( buffer, idx ) buffer[idx]

#define ReadOnlyBuffer( slot, varType, varName ) StructuredBuffer<varType> varName : register(t##slot)
#define readOnlyFetch( bufferVar, idx ) bufferVar[idx]
#define readOnlyFetch1( bufferVar, idx ) bufferVar[idx].x

#define OGRE_Texture3D_float4 Texture3D

#define OGRE_ArrayTex( declType, varName, arrayCount ) declType varName[arrayCount]

#define OGRE_SAMPLER_ARG_DECL( samplerName ) , SamplerState samplerName
#define OGRE_SAMPLER_ARG( samplerName ) , samplerName

#define CONST_BUFFER( bufferName, bindingPoint ) cbuffer bufferName : register(b##bindingPoint)
#define CONST_BUFFER_STRUCT_BEGIN( structName, bindingPoint ) cbuffer structName : register(b##bindingPoint) { struct _##structName
#define CONST_BUFFER_STRUCT_END( variableName ) variableName; }

#define FLAT_INTERPOLANT( decl, bindingPoint ) nointerpolation decl : TEXCOORD##bindingPoint
#define INTERPOLANT( decl, bindingPoint ) decl : TEXCOORD##bindingPoint

#define OGRE_OUT_REF( declType, variableName ) out declType variableName
#define OGRE_INOUT_REF( declType, variableName ) inout declType variableName

#define OGRE_ARRAY_START( type ) {
#define OGRE_ARRAY_END }

float4 unpackSnorm4x8( uint value )
{
	int signedValue = int( value );
	int4 packed = int4( signedValue << 24, signedValue << 16, signedValue << 8, signedValue ) >> 24;
	return clamp( float4( packed ) / 127.0, -1.0, 1.0 );
}

float2 unpackSnorm2x16( uint value )
{
	int signedValue = int( value );
	int2 packed = int2( signedValue << 16, signedValue ) >> 16;
	return clamp( float2( packed ) / 32767.0, -1.0, 1.0 );
}



#define UV_DIFFUSE(x) (x)
#define UV_NORMAL(x) (x)
#define UV_SPECULAR(x) (x)
#define UV_ROUGHNESS(x) (x)
#define UV_DETAIL_WEIGHT(x) (x)
#define UV_DETAIL0(x) (x)
#define UV_DETAIL1(x) (x)
#define UV_DETAIL2(x) (x)
#define UV_DETAIL3(x) (x)
#define UV_DETAIL_NM0(x) (x)
#define UV_DETAIL_NM1(x) (x)
#define UV_DETAIL_NM2(x) (x)
#define UV_DETAIL_NM3(x) (x)
#define UV_EMISSIVE(x) (x)







// START UNIFORM DECLARATION

	
		
struct ShadowReceiverData
{
	float4x4 texViewProj;
	float2 shadowDepthRange;
	float normalOffsetBias;
	float padding;
	float4 invShadowMapSize;
};

struct Light
{
			float3 position;
		uint lightMask;
		float4 diffuse;		//.w contains numNonCasterDirectionalLights
	float3 specular;

float3 attenuation;
//Spotlights:
//  spotDirection.xyz is direction
//  spotParams.xyz contains falloff params
float4 spotDirection;
float4 spotParams;

#define lightTexProfileIdx spotDirection.w
};

#define numNonCasterDirectionalLights lights[0].diffuse.w

#define areaLightDiffuseMipmapStart areaApproxLights[0].diffuse.w
#define areaLightNumMipmapsSpecFactor areaApproxLights[0].specular.w

#define numAreaApproxLights areaApproxLights[0].doubleSided.y
#define numAreaApproxLightsWithMask areaApproxLights[0].doubleSided.z

#define numAreaLtcLights areaLtcLights[0].points[0].w
#define numAreaLtcLights areaLtcLights[0].points[0].w

struct AreaLight
{
			float3 position;
		uint lightMask;
		float4 diffuse;		//[0].w contains diffuse mipmap start
	float4 specular;	//[0].w contains mipmap scale
	float4 attenuation;	//.w contains texture array idx
	//Custom 2D Shape:
	//  direction.xyz direction
	//  direction.w invHalfRectSize.x
	//  tangent.xyz tangent
	//  tangent.w invHalfRectSize.y
	float4 direction;
	float4 tangent;
	float4 doubleSided;	//.y contains numAreaApproxLights
						//.z contains numAreaApproxLightsWithMask
	};

struct AreaLtcLight
{
			float3 position;
		uint lightMask;
		float4 diffuse;			//.w contains attenuation range
	float4 specular;		//.w contains doubleSided
	float4 points[4];		//.w contains numAreaLtcLights
							//points[1].w, points[2].w, points[3].w contain obbFadeFactorLtc.xyz
	};





//Uniforms that change per pass
CONST_BUFFER_STRUCT_BEGIN( PassBuffer, 0 )
{
	//Vertex shader (common to both receiver and casters)

float4x4 viewProj;




//Vertex shader
float4x4 view;
ShadowReceiverData shadowRcv[3];

//-------------------------------------------------------------------------

//Pixel shader
float3x3 invViewMatCubemap;

float padding; //Compatibility with GLSL

float4 pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps;

float4 aspectRatio_planarReflNumMips_unused2;

float2 invWindowRes;
float2 windowResolution;


float4 ambientUpperHemi;

float4 ambientLowerHemi;
float4 ambientHemisphereDir;




float pssmSplitPoints0;
float pssmSplitPoints1;
float pssmSplitPoints2;
float pssmBlendPoints0;
float pssmBlendPoints1;
float pssmFadePoint;

Light lights[1];		// !use_light_buffers











#define pccVctMinDistance		pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps.x
#define invPccVctInvDistance	pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps.y
#define rightEyePixelStartX		pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps.z
#define envMapNumMipmaps		pccVctMinDistance_invPccVctInvDistance_rightEyePixelStartX_envMapNumMipmaps.w

#define aspectRatio			aspectRatio_planarReflNumMips_unused2.x
#define planarReflNumMips	aspectRatio_planarReflNumMips_unused2.y
}
CONST_BUFFER_STRUCT_END( passBuf );


#define light0Buf		passBuf
#define light1Buf		passBuf
#define light2Buf		passBuf

// use_light_buffers


	
	
//Uniforms that change per Item/Entity, but change very infrequently
struct Material
{
	/* kD is already divided by PI to make it energy conserving.
	  (formula is finalDiffuse = NdotL * surfaceDiffuse / PI)
	*/
	float4 bgDiffuse;
	float4 kD; //kD.w is alpha_test_threshold
	float4 kS; //kS.w is roughness
	//Fresnel coefficient, may be per colour component (float3) or scalar (float)
	//F0.w is transparency
	float4 F0;
	float4 normalWeights;
	float4 cDetailWeights;
	float4 detailOffsetScale[4];
	float4 emissive;		//emissive.w contains mNormalMapWeight.
	float refractionStrength;
	float clearCoat;
	float clearCoatRoughness;
	float _padding1;
	float4 userValue[3];


	uint4 indices0_3;
	uint4 indices4_7;


};
	#define normalMapWeight material.emissive.w
	
	CONST_BUFFER( MaterialBuf, 1 )
	{
		Material materialArray[2];
	};

	
	//Uniforms that change per Item/Entity
	CONST_BUFFER( InstanceBuffer, 2 )
	{
		//.x =
		//The lower 9 bits contain the material's start index.
		//The higher 23 bits contain the world matrix start index.
		//
		//.y =
		//shadowConstantBias. Send the bias directly to avoid an
		//unnecessary indirection during the shadow mapping pass.
		//Must be loaded with uintBitsToFloat
		//
		//.z =
		//lightMask. Ogre must have been compiled with OGRE_NO_FINE_LIGHT_MASK_GRANULARITY
		
			uint4 worldMaterialIdx[2];
				};

	


// END UNIFORM DECLARATION


	#define float_fresnel midf
	#define float_fresnel_c( x ) midf_c( x )
	#define make_float_fresnel( x ) midf_c( x )



		#define OGRE_DEPTH_CMP_GE( a, b ) (a) <= (b)
	#define OGRE_DEPTH_DEFAULT_CLEAR 0.0



	#define PASSBUF_ARG_DECL
	#define PASSBUF_ARG




struct PixelData
{
	
		midf3 normal;
		
			midf3 geomNormal;
		
		
		midf4	diffuse;
		midf3	specular;

		

		midf	perceptualRoughness;
		midf	roughness;
		float_fresnel	F0;

		
			midf3	viewDir;
			midf	NdotV;
		

		
			midf3 reflDir;
			
				midf3 envColourS;
				midf3 envColourD;

				
			
		
	

	
};

#define SampleDetailWeightMap( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )

	#define SampleDetailCol0( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )

	#define SampleDetailCol1( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )

	#define SampleDetailCol2( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )

	#define SampleDetailCol3( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx )


	#define SampleDiffuse( tex, sampler, uv, arrayIdx ) OGRE_SampleArray2DF16( tex, sampler, uv, arrayIdx ) 









	INLINE midf3 reconstructZfromTSNormal( midf2 tsNormal2 )
	{
		midf3 tsNormal;
		tsNormal.xy = tsNormal2.xy;
		tsNormal.z	= sqrt( max( _h(0.0f), _h(1.0f) - tsNormal.x * tsNormal.x - tsNormal.y * tsNormal.y ) );
		return tsNormal.xyz;
	}

	
		//Normal texture must be in UV8/RG8_SNORM or BC5S format!
		#define getTSNormal( normalMap, samplerState, uv, normalIdx ) reconstructZfromTSNormal( OGRE_SampleArray2DF16( normalMap, samplerState, uv, normalIdx ).xy )
	
	
	
	





	

	
//Cook-Torrance
INLINE midf3 BRDF( midf3 lightDir, midf3 lightDiffuse, midf3 lightSpecular, PixelData pixelData PASSBUF_ARG_DECL )
{
	midf3 halfWay = normalize( lightDir + pixelData.viewDir );
	midf NdotL = saturate( dot( pixelData.normal, lightDir ) );
	midf NdotH = clamp( dot( pixelData.normal, halfWay ), _h( 0.001 ), _h( 1.0 ) );
	midf VdotH = clamp( dot( pixelData.viewDir, halfWay ), _h( 0.001 ), _h( 1.0 ) );

midf sqR = pixelData.roughness * pixelData.roughness;

//Roughness/Distribution/NDF term (Beckmann distribution)
//Formula:
//	Where alpha = NdotH and m = roughness
//	R = [ 1 / (m^2 x cos(alpha)^4 ] x [ e^( -tan(alpha)^2 / m^2 ) ]
//	R = [ 1 / (m^2 x cos(alpha)^4 ] x [ e^( ( cos(alpha)^2 - 1 )  /  (m^2 cos(alpha)^2 ) ]

midf NdotH_sq = NdotH * NdotH;
midf roughness_b = NdotH_sq - _h( 1.0 );	//( cos(alpha)^2 - 1 )

midf roughness_a = _h( 1.0 ) / ( _h( 3.141592654 ) * sqR * NdotH_sq * NdotH_sq );//( 1 / (m^2 x cos(alpha)^4 )
midf roughness_c = sqR * NdotH_sq;			//( m^2 cos(alpha)^2 )

//Avoid Inf * 0 = NaN; we need Inf * 0 = 0
midf R = min( roughness_a, _h( 65504.0 ) ) * exp( roughness_b / roughness_c );

ensureValidRangeF16( R );

//Geometric/Visibility term (Cook Torrance)
midf shared_geo = _h( 2.0 ) * NdotH / VdotH;
ensureValidRangeF16( shared_geo );
midf geo_b	= shared_geo * pixelData.NdotV;
midf geo_c	= shared_geo * NdotL;
midf G	 	= min( _h( 1.0 ), min( geo_b, geo_c ) );

//Fresnel term (Schlick's approximation)
//Formula:
//	fresnelS = lerp( (1 - V*H)^5, 1, F0 )
//	fresnelD = lerp( (1 - N*L)^5, 1, 1 - F0 ) [See s2010_course_note_practical_implementation_at_triace.pdf]
float_fresnel fresnelS = pixelData.F0 + pow( _h( 1.0 ) - VdotH, _h( 5.0 ) ) * (_h( 1.0 ) - pixelData.F0);

	
		midf fresnelD = _h( 1.0f ) - fresnelS;
	


//Avoid very small denominators, they go to NaN or cause aliasing artifacts
float_fresnel Rs = ( fresnelS * (R * G)  ) / max( _h( 4.0 ) * pixelData.NdotV * NdotL, _h( 0.01 ) );

return NdotL * (pixelData.specular.xyz * lightSpecular * Rs +
				pixelData.diffuse.xyz * lightDiffuse * fresnelD);
}

	
	













struct PS_INPUT
{

		
		FLAT_INTERPOLANT( ushort drawId, 0 );
		

	
		INTERPOLANT( float3 pos, 1 );
		INTERPOLANT( midf3 normal, 2 );
		
			INTERPOLANT( midf3 tangent, 3 );
			FLAT_INTERPOLANT( midf biNormalReflection, 4 );							
		INTERPOLANT( float2 uv0, 5 );
		INTERPOLANT( float2 uv1, 6 );
	
		
			
				INTERPOLANT( float4 posL0, 7 );
						
			
				INTERPOLANT( float4 posL1, 8 );
						
			
				INTERPOLANT( float4 posL2, 9 );
								
	INTERPOLANT( float depth, 10 );		
	
				

};




















Texture2DArray textureMaps0 : register(t3);
Texture2DArray textureMaps1 : register(t4);
Texture2DArray textureMaps2 : register(t5);
Texture2DArray textureMaps3 : register(t6);
Texture2DArray textureMaps4 : register(t7);




SamplerState samplerState3 : register(s3);









#define hlms_shadowmap0 texShadowMap0
#define hlms_shadowmap0_uv_min float2( 0.000000, 0.000000 )
#define hlms_shadowmap0_uv_max float2( 1.000000, 0.285714 )

						#define hlms_shadowmap0_uv_param , hlms_shadowmap0_uv_min, hlms_shadowmap0_uv_max
		
#define hlms_shadowmap1 texShadowMap0
#define hlms_shadowmap1_uv_min float2( 0.000000, 0.285714 )
#define hlms_shadowmap1_uv_max float2( 0.500000, 0.428571 )

						#define hlms_shadowmap1_uv_param , hlms_shadowmap1_uv_min, hlms_shadowmap1_uv_max
		
#define hlms_shadowmap2 texShadowMap0
#define hlms_shadowmap2_uv_min float2( 0.500000, 0.285714 )
#define hlms_shadowmap2_uv_max float2( 1.000000, 0.428571 )

						#define hlms_shadowmap2_uv_param , hlms_shadowmap2_uv_min, hlms_shadowmap2_uv_max
		



#define OGRE_SAMPLE_SHADOW( tex, sampler, uv, depth ) (OGRE_DEPTH_CMP_GE( depth, OGRE_DEPTH_DEFAULT_CLEAR ) ? _h( 1.0 ) : midf_c( tex.SampleCmpLevelZero( sampler, uv.xy, depth ).x ))
#define OGRE_SAMPLE_SHADOW_ESM( tex, sampler, uv ) tex.SampleLevel( sampler, uv, 0 ).x



	SamplerComparisonState shadowSampler: register(s2);
	
		Texture2D<float> texShadowMap0				: register(t2);	


		
		
			#define inPs_posL0 inPs.posL0
				
		
			#define inPs_posL1 inPs.posL1
				
		
			#define inPs_posL2 inPs.posL2
					

	// Perform normal offset bias. See https://github.com/OGRECave/ogre-next/issues/100
	INLINE float3 getNormalOffsetBiasPoint( midf3 geomNormal, float3 lightDir,
											float normalOffsetBias, float shadowMapTexSize,
											float depthRange
	
											)
			{
		float tmpNdotL = saturate( dot( lightDir.xyz, float3( geomNormal.xyz ) ) );

		
		return ( ( 1.0f - tmpNdotL ) * normalOffsetBias * float3( geomNormal.xyz ) * shadowMapTexSize );
	}

	// Perform normal offset bias. See https://github.com/OGRECave/ogre-next/issues/100
	INLINE float3 getNormalOffsetBiasPoint( midf3 geomNormal, float3 lightDir,
											float normalOffsetBias, float shadowMapTexSize,
											float depthRange
													, float2 minUV, float2 maxUV )
			{
		float tmpNdotL = saturate( dot( lightDir.xyz, float3( geomNormal.xyz ) ) );

		
			shadowMapTexSize /= maxUV.x - minUV.x;
		
		return ( ( 1.0f - tmpNdotL ) * normalOffsetBias * float3( geomNormal.xyz ) * shadowMapTexSize );
	}


	INLINE midf getShadow( Texture2D<float> shadowMap, SamplerComparisonState shadowSampler, 
							float4 psPosLN, float4 invShadowMapSize )
	{

	//Spot and directional lights
	
		float fDepth = psPosLN.z / psPosLN.w;
			float2 uv = float2( psPosLN.xy / psPosLN.w );


	midf retVal = _h( 0. );

	
		float2 offsets[4] =
					{
					
			float2( 0., 0. ),	//0, 0
			float2( 1., 0. ),	//1, 0
			float2( 0., 1. ),	//1, 1
			float2(-1., 0. ) 	//0, 1
																	};
				
	
	
		
			uv += offsets[0] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[1] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[2] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[3] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );		
	
		retVal *= _h( 0.25 );
		///! exponential_shadow_maps
   ///! exponential_shadow_maps



	return retVal;
}


	INLINE midf getShadow( Texture2D<float> shadowMap, SamplerComparisonState shadowSampler, 
							float4 psPosLN, float4 invShadowMapSize, float2 minUV, float2 maxUV )
	{

	//Spot and directional lights
	
		float fDepth = psPosLN.z / psPosLN.w;
			float2 uv = float2( psPosLN.xy / psPosLN.w );


	midf retVal = _h( 0. );

	
		float2 offsets[4] =
					{
					
			float2( 0., 0. ),	//0, 0
			float2( 1., 0. ),	//1, 0
			float2( 0., 1. ),	//1, 1
			float2(-1., 0. ) 	//0, 1
																	};
				
	
	
		
			uv += offsets[0] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[1] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[2] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[3] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );		
	
		retVal *= _h( 0.25 );
		///! exponential_shadow_maps
   ///! exponential_shadow_maps



	retVal = (uv.x <= minUV.x || uv.x >= maxUV.x ||
			  uv.y <= minUV.y || uv.y >= maxUV.y) ? _h( 1.0 ) : retVal;

	return retVal;
}


	INLINE midf getShadowPoint( Texture2D<float> shadowMap, SamplerComparisonState shadowSampler, 
								 midf3 geomNormal, float normalOffsetBias,
								 float3 posVS, float3 lightPos,float4 invShadowMapSize, float2 invDepthRange
								 PASSBUF_ARG_DECL )
	{
		//Point lights
	float3 cubemapDir = posVS.xyz - lightPos.xyz;
	cubemapDir += getNormalOffsetBiasPoint( geomNormal, cubemapDir, normalOffsetBias,
			
											invShadowMapSize.x, invDepthRange.y );
			
	float fDepth = length( cubemapDir );
	cubemapDir *= 1.0 / fDepth;
	cubemapDir = mul( cubemapDir.xyz, passBuf.invViewMatCubemap );
				fDepth = (invDepthRange.x - fDepth) * invDepthRange.y;
	
	float2 uv;
	uv.x = (cubemapDir.x / (1.0 + abs( cubemapDir.z ))) * 0.25 +
			(cubemapDir.z < 0.0 ? 0.75 : 0.25 );
	uv.y = (cubemapDir.y / (1.0 + abs( cubemapDir.z ))) * 0.5 + 0.5;

		

	midf retVal = _h( 0. );

	
		float2 offsets[4] =
					{
					
			float2( 0., 0. ),	//0, 0
			float2( 1., 0. ),	//1, 0
			float2( 0., 1. ),	//1, 1
			float2(-1., 0. ) 	//0, 1
																	};
				
	
	
		
			uv += offsets[0] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[1] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[2] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[3] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );		
	
		retVal *= _h( 0.25 );
		///! exponential_shadow_maps
   ///! exponential_shadow_maps



	return retVal;
}


	INLINE midf getShadowPoint( Texture2D<float> shadowMap, SamplerComparisonState shadowSampler, 
								 midf3 geomNormal, float normalOffsetBias,
								 float3 posVS, float3 lightPos, float4 invShadowMapSize, float2 invDepthRange,
								 float2 minUV, float2 maxUV, float2 lengthUV
								 PASSBUF_ARG_DECL )
	{
		//Point lights
	float3 cubemapDir = posVS.xyz - lightPos.xyz;
	cubemapDir += getNormalOffsetBiasPoint( geomNormal, cubemapDir, normalOffsetBias,
															invShadowMapSize.x, invDepthRange.y, minUV, maxUV );
			
	float fDepth = length( cubemapDir );
	cubemapDir *= 1.0 / fDepth;
	cubemapDir = mul( cubemapDir.xyz, passBuf.invViewMatCubemap );
				fDepth = (invDepthRange.x - fDepth) * invDepthRange.y;
	
	float2 uv;
	uv.x = (cubemapDir.x / (1.0 + abs( cubemapDir.z ))) * 0.25 +
			(cubemapDir.z < 0.0 ? 0.75 : 0.25 );
	uv.y = (cubemapDir.y / (1.0 + abs( cubemapDir.z ))) * 0.5 + 0.5;

	uv.xy = uv.xy * lengthUV.xy + minUV.xy;	

	midf retVal = _h( 0. );

	
		float2 offsets[4] =
					{
					
			float2( 0., 0. ),	//0, 0
			float2( 1., 0. ),	//1, 0
			float2( 0., 1. ),	//1, 1
			float2(-1., 0. ) 	//0, 1
																	};
				
	
	
		
			uv += offsets[0] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[1] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[2] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );
			uv += offsets[3] * invShadowMapSize.xy;				retVal += OGRE_SAMPLE_SHADOW( shadowMap, shadowSampler, uv, fDepth );		
	
		retVal *= _h( 0.25 );
		///! exponential_shadow_maps
   ///! exponential_shadow_maps



	retVal = (uv.x <= minUV.x || uv.x >= maxUV.x ||
			  uv.y <= minUV.y || uv.y >= maxUV.y) ? _h( 1.0 ) : retVal;

	return retVal;
}



	        		
		Texture2DArray<float4> ltcMatrix	: register(t1);
		SamplerState ltcSampler				: register(s1);
				






struct PS_OUTPUT
{
	
		
			float4 colour0 : SV_Target0;
		
	

	
	
	

	
};




PS_OUTPUT main
(
	PS_INPUT inPs
	


)
{
	PS_OUTPUT outPs;
	







	PixelData pixelData;

	

	
        ushort materialId	= worldMaterialIdx[inPs.drawId].x & 0x1FFu;
        #define material materialArray[materialId]
	


	

			ushort texIndex_diffuseIdx			= material.indices0_3.x & 0x0000FFFFu;
		ushort texIndex_weightMapIdx		= material.indices0_3.z & 0x0000FFFFu;
			ushort texIndex_detailMapIdx0		= material.indices0_3.z >> 16u;
			ushort texIndex_detailMapIdx1		= material.indices0_3.w & 0x0000FFFFu;
			ushort texIndex_detailMapIdx2		= material.indices0_3.w >> 16u;
			ushort texIndex_detailMapIdx3		= material.indices4_7.x & 0x0000FFFFu;


	

			ushort texIndex_normalIdx			= material.indices0_3.x >> 16u;
	
	
			ushort texIndex_detailNormMapIdx0	= material.indices4_7.x >> 16u;
			ushort texIndex_detailNormMapIdx1	= material.indices4_7.y & 0x0000FFFFu;
			ushort texIndex_detailNormMapIdx2	= material.indices4_7.y >> 16u;
			ushort texIndex_detailNormMapIdx3	= material.indices4_7.z & 0x0000FFFFu;
	
	


	uint objLightMask = worldMaterialIdx[inPs.drawId].z;
	

	

	//Prepare weight map for the detail maps.
	
		midf4 detailWeights = SampleDetailWeightMap( textureMaps2,
													  samplerState3,
													  UV_DETAIL_WEIGHT( inPs.uv0.xy ),
													  texIndex_weightMapIdx );
		
	



	
/// Sample detail maps and weight them against the weight map in the next foreach loop.

	
		midf4 detailCol0 = SampleDetailCol0( textureMaps3,
												samplerState3,
												UV_DETAIL0( inPs.uv0.xy * material.detailOffsetScale[0].zw + material.detailOffsetScale[0].xy ),
                                                texIndex_detailMapIdx0 );
		detailWeights.x *= detailCol0.w;
		detailCol0.w = detailWeights.x;
	

	
		midf4 detailCol1 = SampleDetailCol1( textureMaps0,
												samplerState3,
												UV_DETAIL1( inPs.uv0.xy * material.detailOffsetScale[1].zw + material.detailOffsetScale[1].xy ),
                                                texIndex_detailMapIdx1 );
		detailWeights.y *= detailCol1.w;
		detailCol1.w = detailWeights.y;
	

	
		midf4 detailCol2 = SampleDetailCol2( textureMaps0,
												samplerState3,
												UV_DETAIL2( inPs.uv0.xy * material.detailOffsetScale[2].zw + material.detailOffsetScale[2].xy ),
                                                texIndex_detailMapIdx2 );
		detailWeights.z *= detailCol2.w;
		detailCol2.w = detailWeights.z;
	

	
		midf4 detailCol3 = SampleDetailCol3( textureMaps0,
												samplerState3,
												UV_DETAIL3( inPs.uv0.xy * material.detailOffsetScale[3].zw + material.detailOffsetScale[3].xy ),
                                                texIndex_detailMapIdx3 );
		detailWeights.w *= detailCol3.w;
		detailCol3.w = detailWeights.w;
	



	
		
/// DIFFUSE MAP

	pixelData.diffuse = SampleDiffuse( textureMaps0,
									   samplerState3,
									   UV_DIFFUSE( inPs.uv0.xy ),
									   texIndex_diffuseIdx );


/// Blend the detail diffuse maps with the main diffuse.

	@insertpiece( NormalNonPremul) @add( t, 1 ) 
	@insertpiece( NormalNonPremul) @add( t, 1 ) 
	@insertpiece( NormalNonPremul) @add( t, 1 ) 
	@insertpiece( NormalNonPremul) @add( t, 1 ) 

/// Apply the material's diffuse over the textures
pixelData.diffuse.xyz *= midf3_c( material.kD.xyz );




	

	
/// SPECUlAR MAP
pixelData.specular.xyz = midf3_c( material.kS.xyz );

	pixelData.F0 = float_fresnel_c( material.F0.x );
	
	



	
	
/// ROUGHNESS MAP
pixelData.perceptualRoughness = midf_c( material.kS.w );





	pixelData.roughness = max( pixelData.perceptualRoughness * pixelData.perceptualRoughness, _h( 0.001f ) );





	
		
// Geometric normal
pixelData.geomNormal = normalize( inPs.normal ) ;

	

	

	
		

	//Normal mapping.
	pixelData.geomNormal = normalize( inPs.normal ) ;
	midf3 vTangent		= normalize( inPs.tangent );

	
		
	

	//Get the TBN matrix
	midf3 vBinormal	= normalize( cross( pixelData.geomNormal, vTangent ) * inPs.biNormalReflection );
	midf3x3 TBN		= buildMidf3x3( vTangent, vBinormal, pixelData.geomNormal );

	
		pixelData.normal = getTSNormal( textureMaps@value( normal_map_tex_idx ),
										samplerState@value( normal_map_tex_sampler ),
										UV_NORMAL( inPs.uv@value(uv_normal).xy ),
										texIndex_normalIdx );
	
	
		// Apply the weight to the main normal map
		pixelData.normal = lerp( midf3_c( 0.0, 0.0, 1.0 ), pixelData.normal, normalMapWeight );
	


		
/// If there is no normal map, the first iteration must
/// initialize pixelData.normal instead of try to merge with it.

	
	



   
	   
   
	   
   
	   
   
	   
   



	getTSNormal( textureMaps@value(detail_map_nm0_idx),
											  samplerState@value(detail_map_nm0_sampler),
											  UV_DETAIL_NM0( inPs.uv@value(uv_detail_nm0).xy * material.detailOffsetScale[0].zw + material.detailOffsetScale[0].xy ),
											  texIndex_detailNormMapIdx0 ) * detailWeights.x @end

	@piece( SampleDetailMapNm1 )getTSNormal( textureMaps@value(detail_map_nm1_idx),
											  samplerState@value(detail_map_nm1_sampler),
											  UV_DETAIL_NM1( inPs.uv@value(uv_detail_nm1).xy * material.detailOffsetScale[1].zw + material.detailOffsetScale[1].xy ),
											  texIndex_detailNormMapIdx1 ) * detailWeights.y @end

	@piece( SampleDetailMapNm2 )getTSNormal( textureMaps@value(detail_map_nm2_idx),
											  samplerState@value(detail_map_nm2_sampler),
											  UV_DETAIL_NM2( inPs.uv@value(uv_detail_nm2).xy * material.detailOffsetScale[2].zw + material.detailOffsetScale[2].xy ),
											  texIndex_detailNormMapIdx2 ) * detailWeights.z @end

	@piece( SampleDetailMapNm3 )getTSNormal( textureMaps@value(detail_map_nm3_idx),
											  samplerState@value(detail_map_nm3_sampler),
											  UV_DETAIL_NM3( inPs.uv@value(uv_detail_nm3).xy * material.detailOffsetScale[3].zw + material.detailOffsetScale[3].xy ),
											  texIndex_detailNormMapIdx3 ) * detailWeights.w @end


/// Blend the detail normal maps with the main normal.

	float3 vDetail = 
    getTSDetailNormal( textureMaps[@value(detail_map_nm0_idx)], float3( inPs.uv0.xy * material.detailOffsetScale[0].zw + material.detailOffsetScale[0].xy , @value(detail_map_nm0_idx_slice) ) )
;
	pixelData.normal.xy	+= vDetail.xy;
	pixelData.normal.z	*= vDetail.z + 1.0 - detailWeights.x ;


	
		vDetail = 
    getTSDetailNormal( textureMaps[@value(detail_map_nm1_idx)], float3( inPs.uv0.xy * material.detailOffsetScale[1].zw + material.detailOffsetScale[1].xy , @value(detail_map_nm1_idx_slice) ) )
;
		pixelData.normal.xy	+= vDetail.xy;
		pixelData.normal.z	*= vDetail.z + 1.0 - detailWeights.y ;
	

	
		vDetail = 
    getTSDetailNormal( textureMaps[@value(detail_map_nm2_idx)], float3( inPs.uv0.xy * material.detailOffsetScale[2].zw + material.detailOffsetScale[2].xy , @value(detail_map_nm2_idx_slice) ) )
;
		pixelData.normal.xy	+= vDetail.xy;
		pixelData.normal.z	*= vDetail.z + 1.0 - detailWeights.z ;
	

	
		vDetail = 
    getTSDetailNormal( textureMaps[@value(detail_map_nm3_idx)], float3( inPs.uv0.xy * material.detailOffsetScale[3].zw + material.detailOffsetScale[3].xy , @value(detail_map_nm3_idx_slice) ) )
;
		pixelData.normal.xy	+= vDetail.xy;
		pixelData.normal.z	*= vDetail.z + 1.0 - detailWeights.w ;
	



		

		

		
			pixelData.normal = normalize( mul( TBN, pixelData.normal ) );
		

		

	midf fShadow = _h( 1.0 );

	midf fShadowBlend = _h( 1.0 );
	
	if( inPs.depth <= passBuf.pssmSplitPoints@value(CurrentShadowMap) )
	{
		fShadow = getShadow( hlms_shadowmap@value(CurrentShadowMap), shadowSampler, 
							 inPs_posL0,
							 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
							 hlms_shadowmap@counter(CurrentShadowMap)_uv_param );
		
			if( inPs.depth > passBuf.pssmBlendPoints@value(CurrentShadowMapBlend) )
			{
				fShadowBlend = getShadow( hlms_shadowmap@value(CurrentShadowMap), shadowSampler, 
										  inPs_posL1,
										  passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
										  hlms_shadowmap@value(CurrentShadowMap)_uv_param );
				fShadow = lerp(
					fShadow, fShadowBlend,
					midf_c( ( inPs.depth - passBuf.pssmBlendPoints@value( CurrentShadowMapBlend ) ) /
							( passBuf.pssmSplitPoints@value( CurrentShadowMapBlend ) -
							  passBuf.pssmBlendPoints@counter( CurrentShadowMapBlend ) ) ) );
			}
							}
	
	else if( inPs.depth <= passBuf.pssmSplitPoints@value(CurrentShadowMap) )
	{
		fShadow = getShadow( hlms_shadowmap@value(CurrentShadowMap), shadowSampler, 
							 inPs_posL1,
							 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
							 hlms_shadowmap@counter(CurrentShadowMap)_uv_param );
		
			if( inPs.depth > passBuf.pssmBlendPoints@value(CurrentShadowMapBlend) )
			{
				fShadowBlend = getShadow( hlms_shadowmap@value(CurrentShadowMap), shadowSampler, 
										  inPs_posL@value(CurrentShadowMap),
										  passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
										  hlms_shadowmap@value(CurrentShadowMap)_uv_param );
				fShadow = lerp(
					fShadow, fShadowBlend,
					midf_c( ( inPs.depth - passBuf.pssmBlendPoints@value( CurrentShadowMapBlend ) ) /
							( passBuf.pssmSplitPoints@value( CurrentShadowMapBlend ) -
							  passBuf.pssmBlendPoints@counter( CurrentShadowMapBlend ) ) ) );
			}
							}
	else if( inPs.depth <= passBuf.pssmSplitPoints@value(CurrentShadowMap) )
	{
		fShadow = getShadow( hlms_shadowmap@value(CurrentShadowMap), shadowSampler, 
							 inPs_posL2,
							 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
							 hlms_shadowmap@counter(CurrentShadowMap)_uv_param );
		
			if( inPs.depth > passBuf.pssmFadePoint )
			{
				fShadow = lerp( fShadow, _h( 1.0 ),
								midf_c( ( inPs.depth - passBuf.pssmFadePoint ) /
										( passBuf.pssmSplitPoints@value( hlms_pssm_splits_minus_one ) -
										  passBuf.pssmFadePoint ) ) );
			}
							}	

	

	
		
//Everything's in Camera space

	
		pixelData.viewDir	= midf3_c( normalize( -inPs.pos ) );
	
	pixelData.NdotV		= saturate( dot( pixelData.normal, pixelData.viewDir ) );



	midf3 finalColour = midf3_c(0, 0, 0);



	float3 lightDir;
	float fDistance;
	midf3 tmpColour;
	midf spotCosAngle;





	pixelData.reflDir = _h( 2.0 ) * dot( pixelData.viewDir, pixelData.normal ) * pixelData.normal -
						pixelData.viewDir;



	midf ambientWD =
		dot( midf3_c( passBuf.ambientHemisphereDir.xyz ), pixelData.normal ) * _h( 0.5 ) + _h( 0.5 );
	midf ambientWS =
		dot( midf3_c( passBuf.ambientHemisphereDir.xyz ), pixelData.reflDir ) * _h( 0.5 ) + _h( 0.5 );



		

		
			

	if( (objLightMask & light0Buf.lights[@counter(fineMaskLightIdx)].lightMask) != 0u )
		finalColour += BRDF( midf3_c( light0Buf.lights[0].position.xyz ),
							 midf3_c( light0Buf.lights[0].diffuse.xyz ),
							 midf3_c( light0Buf.lights[0].specular ), pixelData PASSBUF_ARG ) * fShadow;




	


		

		




		





		
		

		

		
			pixelData.envColourS = midf3_c( 0, 0, 0 );
			pixelData.envColourD = midf3_c( 0, 0, 0 );



	
		float tmpAmbientWS = ambientWD;
		float tmpAmbientWD = ambientWS;
							pixelData.envColourS += lerp( midf3_c( passBuf.ambientLowerHemi.xyz ),
										  midf3_c( passBuf.ambientUpperHemi.xyz ), tmpAmbientWS );
			pixelData.envColourD += lerp( midf3_c( passBuf.ambientLowerHemi.xyz ),
										  midf3_c( passBuf.ambientUpperHemi.xyz ), tmpAmbientWD );
		


		
			
//Normally we'd use VdotH. However:
//	H = normalize(lightDir + viewDir)
//since:
//	lightDir = pixelData.reflDir
//then:
//	H = geomNormal
//Thus H = N, and therefore we use VdotN (NdotV)
//float VdotH = saturate( dot( pixelData.viewDir, normalize( pixelData.reflDir + pixelData.viewDir ) ) );
float_fresnel fresnelS = pixelData.F0 + pow( _h( 1.0 ) - pixelData.NdotV, _h( 5.0 ) ) * (max( make_float_fresnel( _h( 1.0 ) - pixelData.perceptualRoughness ), pixelData.F0 ) - pixelData.F0);


	#define brdfLUT ltcMatrix
	midf3 envBRDF = OGRE_SampleArray2DF16( brdfLUT, ltcSampler,
										   float2( pixelData.NdotV,
												   1.0 - pixelData.perceptualRoughness ), 2 ).xyz;



	
		midf fresnelD = _h( 1.0f ) - fresnelS;
	


    midf3 Rd = pixelData.envColourD * pixelData.diffuse.xyz * _h( 3.141592654 ) * fresnelD * envBRDF.z;
    midf3 Rs = pixelData.envColourS * pixelData.specular.xyz *

                ( fresnelS * envBRDF.x + envBRDF.y );




finalColour += Rd + Rs;

		

		

		
	///!hlms_prepass

///!hlms_normal || hlms_qtangent


	
		
			
				outPs_colour0.xyz	= finalColour;
			

			

	midf finalAlpha = _h( 1.0f );


			outPs_colour0.w = finalAlpha;

return outPs;

}

If planet is created, i set:

Code: Select all

planet->create(r, segH, segV, bts, this->gameObjectPtr->getSceneNode(), "PlanetTerraDefaultMaterial")

bool PlanetTerra::create(float r, int segH, int segV, int blendTex, Ogre::SceneNode* attachNode, const Ogre::String& datablockName)
{
    this->radius = r;
    this->segmentsH = segH;
    this->segmentsV = segV;
    this->blendTexSize = blendTex;
    this->attachedNode = attachNode;

// Build CPU geometry (safe on any thread)
generateBaseSphere();
rebuildGeometryFromHeight();
recalculateNormals();
recalculateTangents();
buildVertexAdjacency();

// Default blend: fully layer-0
blendData.assign(static_cast<size_t>(blendTexSize) * blendTexSize * 4u, 0u);
for (size_t i = 0u; i < blendData.size(); i += 4u)
{
    blendData[i] = 255u;
    blendData[i + 1] = 0u;
    blendData[i + 2] = 0u;
    blendData[i + 3] = 0u;
}

const Ogre::String meshName = objectName + "_PlanetMesh";
planetItem = buildItemFromCPUArrays(meshName);
if (!planetItem)
{
    return false;
}

setDatablockByName(datablockName);
createBlendWeightTexture();
uploadBlendData();
attachedNode->attachObject(planetItem); 

Ogre::LogManager::getSingletonPtr()->logMessage(Ogre::LML_TRIVIAL, "[PlanetTerra] Created planet '" + objectName + "' radius=" + Ogre::StringConverter::toString(radius) + " segH=" + Ogre::StringConverter::toString(segmentsH) +
                                                                       " segV=" + Ogre::StringConverter::toString(segmentsV) + " verts=" + Ogre::StringConverter::toString(static_cast<unsigned int>(vertexCount)));

return true;
}

void PlanetTerra::setDatablockByName(const Ogre::String& name)
{
    if (nullptr == this->planetItem || name.empty())
    {
        return;
    }

Ogre::HlmsPbsDatablock* db = static_cast<Ogre::HlmsPbsDatablock*>(Ogre::Root::getSingleton().getHlmsManager()->getDatablockNoDefault(name));

if (nullptr == db)
{
    Ogre::LogManager::getSingletonPtr()->logMessage(Ogre::LML_CRITICAL, "[PlanetTerra] Datablock '" + name + "' not found.");
    return;
}

// Blend weight is a runtime RenderToTexture — set directly, no pool needed.
if (nullptr != this->getBlendTex())
{
    db->setTexture(Ogre::PBSM_DETAIL_WEIGHT, this->getBlendTex());
}

this->planetItem->getSubItem(0)->setDatablock(db);
}

Set is this material json:

Code: Select all

{
    "comment" :
    [
        "PlanetTerra default PBS material - INITIAL TEMPLATE ONLY.",
        "DatablockPbsComponent clones this on first use and stores its own per-instance data.",
        "",
        "Normal maps: all detail NMs must be BC5_SNORM DDS.",
        "UV scale: adjust via PlanetTerraComponent AttrDetailUVScale (default 128)."
    ],

"samplers" :
{
    "PlanetTerra_Sampler" :
    {
        "min"              : "anisotropic",
        "mag"              : "anisotropic",
        "mip"              : "anisotropic",
        "u"                : "wrap",
        "v"                : "wrap",
        "w"                : "wrap",
        "miplodbias"       : 0,
        "max_anisotropic"  : 8,
        "compare_function" : "disabled",
        "border"           : [1, 1, 1, 1],
        "min_lod"          : -3.40282e+38,
        "max_lod"          : 3.40282e+38
    }
},

"macroblocks" :
{
    "PlanetTerra_Macroblock" :
    {
        "scissor_test"           : false,
        "depth_check"            : true,
        "depth_write"            : true,
        "depth_function"         : "less_equal",
        "depth_bias_constant"    : 0,
        "depth_bias_slope_scale" : 0,
        "cull_mode"              : "clockwise",
        "polygon_mode"           : "solid"
    }
},

"blendblocks" :
{
    "PlanetTerra_Blendblock" :
    {
        "alpha_to_coverage"  : false,
        "blendmask"          : "rgba",
        "separate_blend"     : false,
        "src_blend_factor"   : "one",
        "dst_blend_factor"   : "zero",
        "blend_operation"    : "add"
    }
},

"pbs" :
{
    "PlanetTerraDefaultMaterial" :
    {
        "macroblock"        : "PlanetTerra_Macroblock",
        "blendblock"        : "PlanetTerra_Blendblock",
        "shadow_const_bias" : 0.001,

        "workflow" : "specular_fresnel",
        "brdf"     : "cook_torrance",

        "roughness" : 0.85,

        "fresnel" :
        {
            "value" : 0.02,
            "mode"  : "coeff"
        },

        "specular" :
        {
            "value" : [0.04, 0.04, 0.04]
        },

        "diffuse" :
        {
            "value"      : [1, 1, 1],
            "background" : [1, 1, 1, 1],
            "texture"    : "ground_dirt_gardenD.png",
            "sampler"    : "PlanetTerra_Sampler"
        },
		
		"normal" :
        {
            "comment" : "flat_normal.dds (BC5_SNORM) - required to declare textureMaps array in shader.",
            "value"   : 0.0,
            "texture" : "ground_dirt_gardenN.dds",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_weight" :
        {
            "texture" : "PlanetTerraBlendDefault.png",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_diffuse0" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "adesert_cracks_d.jpg",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_normal0" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "adesert_cracks_n.dds",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_diffuse1" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "grass_green_d.jpg",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_normal1" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "grass_green_n.dds",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_diffuse2" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "island_sand_d.jpg",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_normal2" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "island_sand_n.dds",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_diffuse3" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "mntn_black_d.jpg",
            "sampler" : "PlanetTerra_Sampler"
        },

        "detail_normal3" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [128, 128],
            "texture" : "mntn_black_n.dds",
            "sampler" : "PlanetTerra_Sampler"
        }
    }
}
}

Best Regards
Lax

http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5560
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1403

Re: Ogre::PBSM_DETAIL0_NM Bug in Ogre-Next?

Post by dark_sylinc »

OK I see that something went so wrong the Hlms parser aborted and decided to dump raw Hlms code. Hence the shader compiler error.

Usually these errors end up being swallowed by "printf" calls (that should've been logMessage... sigh, that is an old mistake)in OgreHlms.cpp (do not trust the line count it says, it's wrong).

You may find what went wrong there. If not, can I ask you if you can repro that with a modifier version of PbsMaterials? That will be the fastest way for me to take a look at the problem.

Lax
Orc Shaman
Posts: 711
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 75

Re: Ogre::PBSM_DETAIL0_NM Bug in Ogre-Next?

Post by Lax »

Hi @dark_sylinc,
here is a minimal repro using only the standard PbsMaterials sample textures — no custom assets needed.
Steps to reproduce:

Save the following JSON as repro.material.json and place it in:

Code: Select all

Ogre2.2SDK\Samples\2.0\Showcase\PbsMaterials

Code: Select all

In PbsMaterialsGameState::createScene01(), add the following snippet anywhere after the scene manager is available:

cppOgre::Item* reproItem = sceneManager->createItem(
    "Sphere1000.mesh",
    Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME,
    Ogre::SCENE_DYNAMIC );

reproItem->setDatablock( "ReproCrashMaterial" );

Ogre::SceneNode* reproNode = sceneManager->getRootSceneNode( Ogre::SCENE_DYNAMIC )
                                 ->createChildSceneNode( Ogre::SCENE_DYNAMIC );
reproNode->setPosition( 0.0f, 2.0f, -6.0f );
reproNode->setScale( 0.65f, 0.65f, 0.65f );
reproNode->attachObject( reproItem );

Run the PbsMaterials sample. The crash occurs at first render when the shader is compiled.

Material JSON (repro.material.json):

Code: Select all

json{
    "samplers" :
    {
        "Repro_Sampler" :
        {
            "min"              : "anisotropic",
            "mag"              : "anisotropic",
            "mip"              : "anisotropic",
            "u"                : "wrap",
            "v"                : "wrap",
            "w"                : "wrap",
            "miplodbias"       : 0,
            "max_anisotropic"  : 8,
            "compare_function" : "disabled",
            "border"           : [1, 1, 1, 1],
            "min_lod"          : -3.40282e+38,
            "max_lod"          : 3.40282e+38
        }
    },

"macroblocks" :
{
    "Repro_Macroblock" :
    {
        "scissor_test"           : false,
        "depth_check"            : true,
        "depth_write"            : true,
        "depth_function"         : "less_equal",
        "depth_bias_constant"    : 0,
        "depth_bias_slope_scale" : 0,
        "cull_mode"              : "clockwise",
        "polygon_mode"           : "solid"
    }
},

"blendblocks" :
{
    "Repro_Blendblock" :
    {
        "alpha_to_coverage"  : false,
        "blendmask"          : "rgba",
        "separate_blend"     : false,
        "src_blend_factor"   : "one",
        "dst_blend_factor"   : "zero",
        "blend_operation"    : "add"
    }
},

"pbs" :
{
    "ReproCrashMaterial" :
    {
        "macroblock"        : "Repro_Macroblock",
        "blendblock"        : "Repro_Blendblock",
        "shadow_const_bias" : 0.001,

        "workflow"  : "specular_fresnel",
        "roughness" : 0.4,

        "fresnel" :
        {
            "value" : 1.33,
            "mode"  : "ior"
        },

        "specular" :
        {
            "value" : [1.0, 1.0, 1.0]
        },

        "diffuse" :
        {
            "value"   : [1, 1, 1],
            "texture" : "Rocks_Diffuse.tga",
            "sampler" : "Repro_Sampler"
        },

        "normal" :
        {
            "value"   : 1.0,
            "texture" : "Rocks_Normal.tga",
            "sampler" : "Repro_Sampler"
        },

        "detail_weight" :
        {
            "texture" : "nm_up.png",
            "sampler" : "Repro_Sampler"
        },

        "detail_diffuse0" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [5, 5],
            "value"   : 1.0,
            "texture" : "1d_debug.png",
            "sampler" : "Repro_Sampler"
        },

        "detail_normal0" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [5, 5],
            "texture" : "NMBumpsOut.png",
            "sampler" : "Repro_Sampler"
        },

        "detail_diffuse1" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [5, 5],
            "value"   : 1.0,
            "texture" : "MRAMOR6X6.jpg",
            "sampler" : "Repro_Sampler"
        },

        "detail_normal1" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [5, 5],
            "texture" : "NMBalls.png",
            "sampler" : "Repro_Sampler"
        },

        "detail_diffuse2" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [5, 5],
            "value"   : 1.0,
            "texture" : "nm_bk.png",
            "sampler" : "Repro_Sampler"
        },

        "detail_normal2" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [5, 5],
            "texture" : "NMBumpsOut.png",
            "sampler" : "Repro_Sampler"
        },

        "detail_diffuse3" :
        {
            "mode"    : "NormalNonPremul",
            "offset"  : [0, 0],
            "scale"   : [5, 5],
            "value"   : 1.0,
            "texture" : "MtlPlat2.jpg",
            "sampler" : "Repro_Sampler"
        },

        "detail_normal3" :
        {
            "value"   : 1.0,
            "offset"  : [0, 0],
            "scale"   : [5, 5],
            "texture" : "NMBalls.png",
            "sampler" : "Repro_Sampler"
        }
    }
}
}

BUT: I tested it by myself in the PbsMaterials and there it is not crashing!

So i use the same json in my NOWA-Engine. Created a fresh scene, added the sphere1000.mesh as item and set the datablock.

UPDATE:

Found it!

It was the whole time the registerHlms configuration:

Code: Select all

void Core::setupHlms(bool useFog)
{
	Ogre::HlmsManager* hlmsManager = Ogre::Root::getSingletonPtr()->getHlmsManager();

// Check if HLMS is already registered (first-time setup vs. refresh)
bool alreadyRegistered = (hlmsManager->getHlms(Ogre::HLMS_PBS) != nullptr);

if (!alreadyRegistered)
{
	// First time - do full HLMS registration
	this->registerHlms();
}

// Now reload PBS library with all needed piece files
Ogre::String dataFolder = "../../media/";
Ogre::RenderSystem* renderSystem = this->root->getRenderSystem();

Ogre::String shaderSyntax = "GLSL";
if (renderSystem->getName() == "OpenGL ES 2.x Rendering Subsystem")
{
	shaderSyntax = "GLSLES";
}
else if (renderSystem->getName() == "Direct3D11 Rendering Subsystem")
{
	shaderSyntax = "HLSL";
}
else if (renderSystem->getName() == "Metal Rendering Subsystem")
{
	shaderSyntax = "Metal";
}

Ogre::ArchiveManager& archiveManager = Ogre::ArchiveManager::getSingleton();

// Get PBS and its data folder
Ogre::Hlms* hlmsPbs = hlmsManager->getHlms(Ogre::HLMS_PBS);
Ogre::Archive* archivePbs = hlmsPbs->getDataFolder();

// Build library with default PBS paths
Ogre::String mainFolderPath;
Ogre::StringVector libraryFoldersPaths;
Ogre::HlmsPbs::getDefaultPaths(mainFolderPath, libraryFoldersPaths);

Ogre::ArchiveVec library;
for (const auto& path : libraryFoldersPaths)
{
	library.push_back(archiveManager.load(dataFolder + path, "FileSystem", true));
}

// Always add Terra shadows piece files (Terra is always registered)
library.push_back(archiveManager.load(dataFolder + "Hlms/Terra/" + shaderSyntax + "/PbsTerraShadows", "FileSystem", true));

// Always add Ocean piece files (Ocean is always registered)
library.push_back(archiveManager.load(dataFolder + "Hlms/Ocean/" + shaderSyntax, "FileSystem", true));

// Conditionally add Fog piece files
if (useFog)
{
	library.push_back(archiveManager.load(dataFolder + "Hlms/Fog/Any", "FileSystem", true));
}

// Reload PBS with the complete library
// Causes afterwards crashes if detail normal maps are used!
// hlmsPbs->reloadFrom(archivePbs, &library);
}

So this line causes detail normal map setting errors:

hlmsPbs->reloadFrom(archivePbs, &library);

I do not understand why?

I commented it out and then it works!

Best Regards
Lax

http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62