[2.1] Hlms shader compile error with detail normals

Problems building or running the engine, queries about how to use features etc.
Post Reply
User avatar
SamiTheGreat
Bronze Sponsor
Bronze Sponsor
Posts: 102
Joined: Sat Aug 30, 2008 11:57 am
Location: Finland
x 8

[2.1] Hlms shader compile error with detail normals

Post by SamiTheGreat »

Hi! I have been doing tilemap based terrain for us. I've done that by baking detail weight map texture from tilemap data and then use four detail textures in PBS to create the final material. I can't get detail normal maps to work because I get shader compile error:

Code: Select all

Cannot compile d3d11 high-level shader Errors:
warning: 'Sample': implicit truncation of vector type
error x3017: 'getTSDetailNormal': cannot implicitly convert from 'const Texture2DArray<float4>' to 'Texture2D<float4>' in D3D11HLSLProgram::compileMicrocode "Pathtofile"\Ogre3DD11HLSLProgram.cpp (line 544)
I am using U8V8 pixel format .dds files that I exported from Photoshop via nVidia texture tool.

Here is my code to create mesh and HLMS datablock:

Code: Select all

void TerrainManager::createModuleTerrain(DataInterface::ModuleData* moduleData, tow::ModulePlacementData* placementData)
	{
		assert(moduleData);

		if (moduleData)
		{
			//Create module terrain mesh
			std::string v1planeName = "module_mesh1_" + std::to_string(placementData->x) + "_" + std::to_string(placementData->y);
			Ogre::v1::MeshPtr planeMeshV1 = Ogre::v1::MeshManager::getSingleton().createPlane(v1planeName,
				Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
				Ogre::Plane(Ogre::Vector3::UNIT_Y, 0.0f), ModuleSize*ModuleTileSize, ModuleSize*ModuleTileSize,
				1, 1, true, 1, 1.0f, 1.0f, Ogre::Vector3::UNIT_Z,
				Ogre::v1::HardwareBuffer::HBU_STATIC,
				Ogre::v1::HardwareBuffer::HBU_STATIC);

			std::string v2planeName = "module_mesh2_" + std::to_string(placementData->x) + "_" + std::to_string(placementData->y);
			Ogre::MeshPtr planeMesh = Ogre::MeshManager::getSingleton().createManual(
				v2planeName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

			planeMesh->importV1(planeMeshV1.get(), true, true, true);

			planeMeshV1->unload();

			Ogre::Item *item = mWorkingSceneMgr->createItem(planeMesh, Ogre::SCENE_STATIC);

			Ogre::SceneNode *sceneNode = mWorkingSceneMgr->getRootSceneNode(Ogre::SCENE_STATIC)->createChildSceneNode(Ogre::SCENE_STATIC);
			sceneNode->setPosition(Ogre::Vector3(placementData->x*ModuleSize*ModuleTileSize + ModuleSize*ModuleTileSize*0.5f, 0, placementData->y*ModuleSize*ModuleTileSize + ModuleSize*ModuleTileSize*0.5f));
			sceneNode->attachObject(item);

			//Create material datablock
			Ogre::HlmsManager *hlmsManager = Director::getInstance()->getHlmsManager();
			Ogre::HlmsTextureManager *hlmsTextureManager = hlmsManager->getTextureManager();

			assert(dynamic_cast<Ogre::HlmsPbs*>(hlmsManager->getHlms(Ogre::HLMS_PBS)));

			Ogre::HlmsPbs *hlmsPbs = static_cast<Ogre::HlmsPbs*>(hlmsManager->getHlms(Ogre::HLMS_PBS));

			std::string hlsmDatablockName = "db_terrain_" + std::to_string(placementData->x) + "_" + std::to_string(placementData->y) + "_" + moduleData->ID.toString();
			Ogre::HlmsPbsDatablock* datablock = static_cast<Ogre::HlmsPbsDatablock*>(hlmsPbs->createDatablock(
				hlsmDatablockName, hlsmDatablockName, Ogre::HlmsMacroblock(), Ogre::HlmsBlendblock(), Ogre::HlmsParamVec() ));

			datablock->setDiffuse(Ogre::Vector3(1.0f, 1.0f, 1.0f));
			datablock->setRoughness(0.5f);
			datablock->setFresnel(Ogre::Vector3(0.05f, 0.05f, 0.05f), false);
			datablock->setWorkflow(Ogre::HlmsPbsDatablock::Workflows::SpecularWorkflow);

			//DIFFUSE DETAIL TEXTURES
			Ogre::HlmsTextureManager::TextureLocation detailTextureLocation[4];
			detailTextureLocation[0] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_diffuse_0.png", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL);
			detailTextureLocation[1] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_diffuse_1.png", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL);
			detailTextureLocation[2] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_diffuse_2.png", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL);
			detailTextureLocation[3] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_diffuse_3.png", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL);

			datablock->setTexture(Ogre::PBSM_DETAIL0, detailTextureLocation[0].xIdx, detailTextureLocation[0].texture);
			datablock->setTexture(Ogre::PBSM_DETAIL1, detailTextureLocation[1].xIdx, detailTextureLocation[1].texture);
			datablock->setTexture(Ogre::PBSM_DETAIL2, detailTextureLocation[2].xIdx, detailTextureLocation[2].texture);
			datablock->setTexture(Ogre::PBSM_DETAIL3, detailTextureLocation[3].xIdx, detailTextureLocation[3].texture);

			datablock->setDetailMapOffsetScale(0, Ogre::Vector4(0, 0, 10.0f, 10.0f));
			datablock->setDetailMapOffsetScale(1, Ogre::Vector4(0, 0, 10.0f, 10.0f));
			datablock->setDetailMapOffsetScale(2, Ogre::Vector4(0, 0, 10.0f, 10.0f));
			datablock->setDetailMapOffsetScale(3, Ogre::Vector4(0, 0, 10.0f, 10.0f));

			//NORMAL DETAIL TEXTURES
			Ogre::HlmsTextureManager::TextureLocation detailNormalLocation[4];
			detailNormalLocation[0] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_normal_0.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL_NORMAL_MAP);
			detailNormalLocation[1] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_normal_1.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL_NORMAL_MAP);
			detailNormalLocation[2] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_normal_2.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL_NORMAL_MAP);
			detailNormalLocation[3] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_normal_3.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL_NORMAL_MAP);

			datablock->setTexture(Ogre::PBSM_DETAIL0_NM, detailNormalLocation[0].xIdx, detailNormalLocation[0].texture);
			datablock->setTexture(Ogre::PBSM_DETAIL1_NM, detailNormalLocation[1].xIdx, detailNormalLocation[1].texture);
			datablock->setTexture(Ogre::PBSM_DETAIL2_NM, detailNormalLocation[2].xIdx, detailNormalLocation[2].texture);
			datablock->setTexture(Ogre::PBSM_DETAIL3_NM, detailNormalLocation[3].xIdx, detailNormalLocation[3].texture);

			datablock->setDetailMapOffsetScale(4, Ogre::Vector4(0, 0, 5.0f, 5.0f));
			datablock->setDetailMapOffsetScale(5, Ogre::Vector4(0, 0, 5.0f, 5.0f));
			datablock->setDetailMapOffsetScale(6, Ogre::Vector4(0, 0, 5.0f, 5.0f));
			datablock->setDetailMapOffsetScale(7, Ogre::Vector4(0, 0, 5.0f, 5.0f));

			//Get cached module weight map
			std::string weightTexName = "mtw_" + std::to_string(placementData->x) + "_" + std::to_string(placementData->y) + "_" + moduleData->ID.toString();
			std::string cacheName = weightTexName + "_cac.png";
			Ogre::HlmsTextureManager::TextureLocation weightMapLocation = hlmsTextureManager->createOrRetrieveTexture(cacheName, Ogre::HlmsTextureManager::TEXTURE_TYPE_DIFFUSE);
			datablock->setTexture(Ogre::PBSM_DETAIL_WEIGHT, weightMapLocation.xIdx, weightMapLocation.texture);

			item->setDatablock(datablock);

			mItemMaterialMap.insert(std::pair<Ogre::Item*, Ogre::HlmsPbsDatablock*>(item, datablock));
		}
	}
Hlms generates this shader code:

Code: Select all


// START UNIFORM DECLARATION

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

struct Light
{
	float3 position;
	float3 diffuse;
	float3 specular;
};

//Uniforms that change per pass
cbuffer PassBuffer : register(b0)
{
	struct PassData
	{
	//Vertex shader (common to both receiver and casters)
	float4x4 viewProj;


	//Vertex shader
	float4x4 view;
	
	//-------------------------------------------------------------------------

	//Pixel shader
	float3x3 invViewMatCubemap;
	float padding; //Compatibility with GLSL.
	

	float4 ambientUpperHemi;

	float4 ambientLowerHemi;
	float4 ambientHemisphereDir;
	Light lights[1];
	
	} passBuf;
};

	
	
//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 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 detailOffsetScaleD[4];
	float4 detailOffsetScaleN[4];

	uint4 indices0_3;
	//asfloat( indices4_7.w ) contains mNormalMapWeight.
	uint4 indices4_7;
};

cbuffer MaterialBuf : register(b1)
{
	Material materialArray[273];
};

	
//Uniforms that change per Item/Entity
cbuffer InstanceBuffer : register(b2)
{
    //.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
	uint4 worldMaterialIdx[4096];
};



// END UNIFORM DECLARATION
struct PS_INPUT
{

    
		nointerpolation uint drawId	: TEXCOORD0;
		
			float3 pos	: TEXCOORD1;
			float3 normal	: TEXCOORD2;
			float3 tangent	: TEXCOORD3;
				nointerpolation float biNormalReflection	: TEXCOORD4;							
			float2 uv0	: TEXCOORD5;
					
				
	
	

};





#define ROUGHNESS material.kS.w
Texture2DArray textureMaps[3] : register(t1);


SamplerState samplerStates[3] : register(s1);













float3 getTSDetailNormal( SamplerState samplerState, Texture2D normalMap, float3 uv )
{
	float3 tsNormal;

	//Normal texture must be in U8V8 or BC5 format!
	tsNormal.xy = normalMap.Sample( samplerState, uv ).xy;

	tsNormal.z	= sqrt( max( 0, 1.0 - tsNormal.x * tsNormal.x - tsNormal.y * tsNormal.y ) );

	return tsNormal;
}
	
		
	
		
	
		
	
		
	




//Default BRDF
float3 BRDF( float3 lightDir, float3 viewDir, float NdotV, float3 lightDiffuse, float3 lightSpecular, Material material, float3 nNormal , float4 diffuseCol )
{
	float3 halfWay= normalize( lightDir + viewDir );
	float NdotL = saturate( dot( nNormal, lightDir ) );
	float NdotH = saturate( dot( nNormal, halfWay ) );
	float VdotH = saturate( dot( viewDir, halfWay ) );

	float sqR = ROUGHNESS * ROUGHNESS;

	//Roughness/Distribution/NDF term (GGX)
	//Formula:
	//	Where alpha = roughness
	//	R = alpha^2 / [ PI * [ ( NdotH^2 * (alpha^2 - 1) ) + 1 ]^2 ]
	float f = ( NdotH * sqR - NdotH ) * NdotH + 1.0;
	float R = sqR / (f * f + 1e-6f);

	//Geometric/Visibility term (Smith GGX Height-Correlated)

	float Lambda_GGXV = NdotL * sqrt( (-NdotV * sqR + NdotV) * NdotV + sqR );
	float Lambda_GGXL = NdotV * sqrt( (-NdotL * sqR + NdotL) * NdotL + sqR );

	float G = 0.5 / (( Lambda_GGXV + Lambda_GGXL + 1e-6f ) * 3.141592654);


	//Formula:
	//	fresnelS = lerp( (1 - V*H)^5, 1, F0 )
	float fresnelS = material.F0.x + pow( 1.0 - VdotH, 5.0 ) * (1.0 - material.F0.x);

	//We should divide Rs by PI, but it was done inside G for performance
	float3 Rs = ( fresnelS * (R * G) ) * material.kS.xyz * lightSpecular;

	//Diffuse BRDF (*Normalized* Disney, see course_notes_moving_frostbite_to_pbr.pdf
	//"Moving Frostbite to Physically Based Rendering" Sebastien Lagarde & Charles de Rousiers)
	float energyBias	= ROUGHNESS * 0.5;
	float energyFactor	= lerp( 1.0, 1.0 / 1.51, ROUGHNESS );
	float fd90			= energyBias + 2.0 * VdotH * VdotH * ROUGHNESS;
	float lightScatter	= 1.0 + (fd90 - 1.0) * pow( 1.0 - NdotL, 5.0 );
	float viewScatter	= 1.0 + (fd90 - 1.0) * pow( 1.0 - NdotV, 5.0 );


	float fresnelD = 1.0f - fresnelS;

	//We should divide Rd by PI, but it is already included in kD
	float3 Rd = (lightScatter * viewScatter * fresnelD) * diffuseCol.xyz * lightDiffuse;

	return NdotL * (Rs + Rd);
}






float4 main( PS_INPUT inPs
) : SV_Target0
{
	

	Material material;
	float4 outColour;
	




	uint weightMapIdx;

	uint detailMapIdx0;
	uint detailMapIdx1;
	uint detailMapIdx2;
	uint detailMapIdx3;

	uint detailNormMapIdx0;
	uint detailNormMapIdx1;
	uint detailNormMapIdx2;
	uint detailNormMapIdx3;


float4 diffuseCol;



	
	float3 nNormal;
	

	uint materialId	= worldMaterialIdx[inPs.drawId].x & 0x1FFu;
	material = materialArray[materialId];




	weightMapIdx		= material.indices0_3.z & 0x0000FFFFu;
	detailMapIdx0		= material.indices0_3.z >> 16u;
	detailMapIdx1		= material.indices0_3.w & 0x0000FFFFu;
	detailMapIdx2		= material.indices0_3.w >> 16u;
	detailMapIdx3		= material.indices4_7.x & 0x0000FFFFu;
	detailNormMapIdx0	= material.indices4_7.x >> 16u;
	detailNormMapIdx1	= material.indices4_7.y & 0x0000FFFFu;
	detailNormMapIdx2	= material.indices4_7.y >> 16u;
	detailNormMapIdx3	= material.indices4_7.z & 0x0000FFFFu;


	


	//Prepare weight map for the detail maps.
	
		float4 detailWeights = textureMaps[0].Sample( samplerStates[0], float3(inPs.uv0.xy, weightMapIdx) );
		
	


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

	float4 detailCol0	= textureMaps[1].Sample( samplerStates[1], float3( inPs.uv0.xy * material.detailOffsetScaleD[0].zw + material.detailOffsetScaleD[0].xy, detailMapIdx0 ) );
	
	detailWeights.x *= detailCol0.w;
	detailCol0.w = detailWeights.x;

	float4 detailCol1	= textureMaps[1].Sample( samplerStates[1], float3( inPs.uv0.xy * material.detailOffsetScaleD[1].zw + material.detailOffsetScaleD[1].xy, detailMapIdx1 ) );
	
	detailWeights.y *= detailCol1.w;
	detailCol1.w = detailWeights.y;

	float4 detailCol2	= textureMaps[1].Sample( samplerStates[1], float3( inPs.uv0.xy * material.detailOffsetScaleD[2].zw + material.detailOffsetScaleD[2].xy, detailMapIdx2 ) );
	
	detailWeights.z *= detailCol2.w;
	detailCol2.w = detailWeights.z;

	float4 detailCol3	= textureMaps[1].Sample( samplerStates[1], float3( inPs.uv0.xy * material.detailOffsetScaleD[3].zw + material.detailOffsetScaleD[3].xy, detailMapIdx3 ) );
	
	detailWeights.w *= detailCol3.w;
	detailCol3.w = detailWeights.w;




	/// 'insertpiece( SampleDiffuseMap )' must've written to diffuseCol. However if there are no
	/// diffuse maps, we must initialize it to some value. If there are no diffuse or detail maps,
	/// we must not access diffuseCol at all, but rather use material.kD directly (see piece( kD ) ).
	diffuseCol = float4( 0.0, 0.0, 0.0, 0.0 );

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

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

	/// Apply the material's diffuse over the textures

	
		diffuseCol.xyz *= material.kD.xyz;
	





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

	//Get the TBN matrix
	float3 vBinormal	= normalize( cross( vTangent, geomNormal ) * inPs.biNormalReflection );
	float3x3 TBN		= float3x3( vTangent, vBinormal, geomNormal );

	
	







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

	
	


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

	float3 vDetail = getTSDetailNormal( samplerStates[2], textureMaps[2], float3( inPs.uv0.xy * material.detailOffsetScaleN[0].zw + material.detailOffsetScaleN[0].xy, detailNormMapIdx0 ) ) * detailWeights.x ;
	nNormal.xy	= vDetail.xy;
	nNormal.z	= vDetail.z + 1.0 - detailWeights.x ;

	vDetail = getTSDetailNormal( samplerStates[2], textureMaps[2], float3( inPs.uv0.xy * material.detailOffsetScaleN[1].zw + material.detailOffsetScaleN[1].xy, detailNormMapIdx1 ) ) * detailWeights.y ;
	nNormal.xy	+= vDetail.xy;
	nNormal.z	*= vDetail.z + 1.0 - detailWeights.y ;
	vDetail = getTSDetailNormal( samplerStates[2], textureMaps[2], float3( inPs.uv0.xy * material.detailOffsetScaleN[2].zw + material.detailOffsetScaleN[2].xy, detailNormMapIdx2 ) ) * detailWeights.z ;
	nNormal.xy	+= vDetail.xy;
	nNormal.z	*= vDetail.z + 1.0 - detailWeights.z ;
	vDetail = getTSDetailNormal( samplerStates[2], textureMaps[2], float3( inPs.uv0.xy * material.detailOffsetScaleN[3].zw + material.detailOffsetScaleN[3].xy, detailNormMapIdx3 ) ) * detailWeights.w ;
	nNormal.xy	+= vDetail.xy;
	nNormal.z	*= vDetail.z + 1.0 - detailWeights.w ;


	nNormal = normalize( mul( nNormal, TBN ) );


	//Everything's in Camera space

	float3 viewDir	= normalize( -inPs.pos );
	float NdotV		= saturate( dot( nNormal, viewDir ) );


	float3 finalColour = float3(0, 0, 0);


	





	finalColour += BRDF( passBuf.lights[0].position, viewDir, NdotV, passBuf.lights[0].diffuse, passBuf.lights[0].specular, material, nNormal , diffuseCol.xyzw );


	float3 lightDir;
	float fDistance;
	float3 tmpColour;
	float spotCosAngle;

	//Point lights


	//Spot lights
	//spotParams[0].x = 1.0 / cos( InnerAngle ) - cos( OuterAngle )
	//spotParams[0].y = cos( OuterAngle / 2 )
	//spotParams[0].z = falloff





	float3 reflDir = 2.0 * dot( viewDir, nNormal ) * nNormal - viewDir;
	
	
	
		float ambientWD = dot( passBuf.ambientHemisphereDir.xyz, nNormal ) * 0.5 + 0.5;
		float ambientWS = dot( passBuf.ambientHemisphereDir.xyz, reflDir ) * 0.5 + 0.5;

		
			float3 envColourS = lerp( passBuf.ambientLowerHemi.xyz, passBuf.ambientUpperHemi.xyz, ambientWD );
			float3 envColourD = lerp( passBuf.ambientLowerHemi.xyz, passBuf.ambientUpperHemi.xyz, ambientWS );
		
	

	
	float NdotL = saturate( dot( nNormal, reflDir ) );
	float VdotH = saturate( dot( viewDir, normalize( reflDir + viewDir ) ) );
	float fresnelS = material.F0.x + pow( 1.0 - VdotH, 5.0 ) * (1.0 - material.F0.x);

	
		float fresnelD = 1.0f - fresnelS;

	finalColour += envColourD * diffuseCol.xyz * fresnelD +
					envColourS * material.kS.xyz * fresnelS;




	outColour.xyz	= finalColour;



	outColour.w		= 1.0;
	


	

	return outColour;
}
Thanks! :D
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1280
Contact:

Re: [2.1] Hlms shader compile error with detail normals

Post by dark_sylinc »

Just update your version of Ogre 2.1's repo to the latest :)

This bug was fixed 2 weeks ago.

Take care if you're manually copying the Hlms data files to a different folder, that they are updated as well.
User avatar
SamiTheGreat
Bronze Sponsor
Bronze Sponsor
Posts: 102
Joined: Sat Aug 30, 2008 11:57 am
Location: Finland
x 8

Re: [2.1] Hlms shader compile error with detail normals

Post by SamiTheGreat »

dark_sylinc wrote:Just update your version of Ogre 2.1's repo to the latest :)

This bug was fixed 2 weeks ago.

Take care if you're manually copying the Hlms data files to a different folder, that they are updated as well.
Ohh, yes I forgot to copy hlms files when I last updated Ogre :lol:
Thanks again!
User avatar
SamiTheGreat
Bronze Sponsor
Bronze Sponsor
Posts: 102
Joined: Sat Aug 30, 2008 11:57 am
Location: Finland
x 8

Re: [2.1] Hlms shader compile error with detail normals

Post by SamiTheGreat »

Hi! I faced another problem with normals in detail maps.

Setting texture PSBM_DETAIL3_NM doesn't affect. Instead, DETAIL3 gets normal map from PSBM_DETAIL1_NM. Even if I comment the code line where I set normal for DETAIL3, DETAIL3 gets normal map from DETAIL1. I've checked multiple times that textures are right and tried to figure out if there is a bug in ogre source but I didn't find anything.

Code: Select all

//NORMAL DETAIL TEXTURES
			Ogre::HlmsTextureManager::TextureLocation detailNormalLocation[4];
			detailNormalLocation[0] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_normal_0.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL_NORMAL_MAP);
			detailNormalLocation[1] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_normal_1.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL_NORMAL_MAP);
			detailNormalLocation[2] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_normal_2.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL_NORMAL_MAP);
			detailNormalLocation[3] = hlmsTextureManager->createOrRetrieveTexture("theme_1_terrain_normal_3.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_DETAIL_NORMAL_MAP);

			datablock->setTexture(Ogre::PBSM_DETAIL0_NM, detailNormalLocation[0].xIdx, detailNormalLocation[0].texture);
			datablock->setTexture(Ogre::PBSM_DETAIL1_NM, detailNormalLocation[1].xIdx, detailNormalLocation[1].texture);
			datablock->setTexture(Ogre::PBSM_DETAIL2_NM, detailNormalLocation[2].xIdx, detailNormalLocation[2].texture);
			//datablock->setTexture(Ogre::PBSM_DETAIL3_NM, detailNormalLocation[3].xIdx, detailNormalLocation[3].texture);

			item->setDatablock(datablock);
My render looks like this:
Image
The farthest texture is set as DETAIL3 and as you can see it still gets normal mapped even if I have commented out its normal map texture set. Object is textured DETAIL0, DETAIL1, DETAIL2 and DETAIL3 counting from middle. I am using RGBA texture as weightmap. Could be there a issue that normal maps doesn't act same way as diffuses with same weightmap texture?
Here is also my weight map if you need that: https://dl.dropboxusercontent.com/u/592 ... e4_cac.png


EDIT: I got it working! The problem was in weightmap texture I posted. Areas that are white caused that upper detailmap layers weren't masked properly. I turned white areas to black and it works. It is still quite strange why my diffuse detail texutes were working fine with that weightmap but the problem appeard after I applied normal textures. :roll:
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1280
Contact:

Re: [2.1] Hlms shader compile error with detail normals

Post by dark_sylinc »

Mmm.
Detail diffuse obeys the blending modes:

Code: Select all

"NormalNonPremul", "NormalPremul", "Add", "Subtract", "Multiply",
"Multiply2x", "Screen", "Overlay", "Lighten", "Darken", "GrainExtract",
"GrainMerge", "Difference"
But for detail normal maps, some of these modes make sense (e.g. NormalNonPremul, NormalPremul, Add, Overlay) while some make no sense (e.g. Subtract, Multiply).
Our PBS implementation assumes normal maps want to add to the previous one (see Blending in Detail). You can think of it as a sort of additive mode.

With a white weight texture, the default blending mode will cause only the 3rd diffuse detail to be seen (since it covers everything behind) but for the normals it means each detail normal map is contributing 100% of its power. When I say it out loud, it does sound counter-intuitive.
In this case what you want is the third map to be at 100%; while the rest at 0% (which can be achieved with a blue weight texture)

It is a little difficult to match normals & diffuse modes because most of them don't have a 1:1 correlation; and while a "NormalNonPremul/NormalPremul" mode could be used for normal maps, the quality of the normals wouldn't be exactly the best(*). Perhaps I should start thinking on adding an option for choosing normal map blending mode (separate from diffuse's blending mode) to select between "normal" & "additive".

Any opinions?


(*) By "not exactly the best" I mean that if two details should be blended 50% each (or three details 33% each), it tends to end up with a flat-looking normal map (basically you lose the details)
Post Reply