Jump to content
  • Advertisement
Sign in to follow this  

Strange shader problem (beginner)

This topic is 917 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts



I will try to be short and only provide clear information about my shader problem, it's probably a newbie error, but I have spend my day on it without solution...


On my small 3D engine, it seem that I have a problem rendering UpY normal with my shader.


Let me explain :


- I load a FBX containing a plane composed of 2 triangles, the plane is correctly shaded.


- I generate the same plane, the plane is all black. PixelShader return black on every plane pixel.


The only difference I see it's that FBX file are loaded with up side on the Z axis (so vertex normals are (0, 0, 1)) and then I rotate them with a rotation matrix. When my plane is manually generated with Y as up axis, my normal are (0, 1, 0).


If I generate my plane like in the FBX file, it render correctly.

If I change the normal to something like (0, 1, 1), it render correctly.

If I load complex mesh, like a Teapot or so, they render correctly (probably cause there is no vertex with straigh Y normal).


It really seem that the normal (0, 1, 0) is the problem. If I load a FBX cube, 3 face are all black too.


I am still beginner and haven't totally writed the HLSL file by myself, I have put together snipped from here and there. So I am not able to find wah't wrong with it, maybe somone can help me ?


Here is the files :



struct ParallelLight
	float3 Direction;
	float4 AmbientColor;
	float4 DiffuseColor;
	float4 SpecularColor;

// PerObject constant buffer
cbuffer cbPerObject : register(b0)
	// WorldViewProjection matrix
	float4x4 WorldViewProjection;

	// We need the world matrix so that we can
	// calculate the lighting in world space
	float4x4 World;

	// Inverse transpose of world, used for
	// bringing normals into world space, especially
	// necessary where non-uniform scaling has been applied
	float4x4 WorldInverseTranspose;

	// Matrix to take world coordinates to view/projection
	// Used in the domain shader
	float4x4 ViewProjection;

	// Matrix to take a world position back to local
	float4x4 WorldInverse;

cbuffer cbPerFrame  : register(b1)
	ParallelLight	ParallelLightArray[10];
	//PointLight	gPointLight[10];
	//SpotLight		gSpotLight[10];
	float3			CameraPosition;

cbuffer cbPerMaterial : register (b2)
    float4 MaterialAmbient;
    float4 MaterialDiffuse;
    float4 MaterialSpecular;
    float4 MaterialEmissive;
    float MaterialSpecularPower;
	bool HasTexture;
	float4x4 UVTransform;

struct VS_IN
	float4 Position		: POSITION;
	float3 Normal		: NORMAL;
	float4 Tangent		: TANGENT;
	float4 Color		: COLOR0;
	float2 TextureUV	: TEXCOORD0;

struct VS_OUT
	float4 Position : SV_Position;
	// Interpolation of combined vertex and material diffuse
	float4 Diffuse : COLOR;
	// Interpolation of vertex UV texture coordinate
	float2 TextureUV: TEXCOORD0;

	// We need the WorldNormal for displacement etc..
	float3 WorldNormal : NORMAL;
	float3 WorldPosition : WORLDPOS;

	// To camera vector in tangent space
	float3 ToCameraTangentSpace : TEXCOORD3;

	// Tangent/Surface space normal for tangent space calculations
	float3 Normal: TEXCOORD5;

	// To light vector in tangent space
	float3 ToLightTangentSpace: TEXCOORD6;

// Create a TBN matrix for tangent operations
float3x3 CreateTBNMatrix(float3 normal, float4 tangent)
	// Ensure tangent is orthogonal to normal vector - Gram-Schmidt orthogonalize
	float3 T = tangent.xyz;
	T = normalize(T - normal * dot(normal, T));

	// Create the Bitangent (tangent.w contains handedness)
	float3 bitangent = cross(normal, T) * tangent.w;

	// Create the TBN matrix
	return float3x3(T, bitangent, normal);


#include "Common.hlsl"

	VS_OUT result = (VS_OUT)0;
	// Change the position vector to be 4 units for matrix transformation
	vIn.Position.w = 1.0;

	result.Position = mul(vIn.Position, WorldViewProjection);
	result.Diffuse = vIn.Color * MaterialDiffuse;

	// Apply material UV transformation
	result.TextureUV = mul(float4(vIn.TextureUV.x, vIn.TextureUV.y, 0, 1), (float4x2)UVTransform).xy;

	// We use the inverse transpose of the world so that if there is non uniform
	// scaling the normal is transformed correctly. We also use a 3x3 so that 
	// the normal is not affected by translation (i.e. a vector has the same direction
	// and magnitude regardless of translation)
	result.WorldNormal = mul(vIn.Normal, (float3x3)WorldInverseTranspose);
	result.Normal = vIn.Normal;

	result.WorldPosition = mul(vIn.Position, World).xyz;

	// Create TBN matrix - note: the transpose of TBN is the equivalent of inverse because it is orthogonal
	float3x3 worldToTangent = mul((float3x3)WorldInverse, transpose(CreateTBNMatrix(result.Normal, vIn.Tangent)));

	// Calculate ToCamera/ToLight
	result.ToCameraTangentSpace = normalize(mul(CameraPosition - result.WorldPosition, worldToTangent));
	result.ToLightTangentSpace = normalize(mul(-ParallelLightArray[0].Direction, worldToTangent));

	return result;


#include "Common.hlsl"

Texture2D Texture0 : register(t0);
SamplerState Sampler : register(s0);

// combines a float3 RGB value with an alpha value into a float4
float4 CombineRGBWithAlpha(float3 rgb, float a)
	return float4(rgb.r, rgb.g, rgb.b, a);

// lambert lighting function
float3 LambertLighting(
	float3 lightNormal,
	float3 surfaceNormal,
	float3 materialAmbient,
	float3 lightAmbient,
	float3 lightColor,
	float3 pixelColor
	// compute amount of contribution per light
	float diffuseAmount = saturate(dot(lightNormal, surfaceNormal));
	float3 diffuse = diffuseAmount * lightColor * pixelColor;

	// combine ambient with diffuse
	return saturate((materialAmbient * lightAmbient) + diffuse);

// specular contribution function
float3 SpecularContribution(
	float3 toEye,
	float3 lightNormal,
	float3 surfaceNormal,
	float3 materialSpecularColor,
	float materialSpecularPower,
	float lightSpecularIntensity,
	float3 lightColor
	// compute specular contribution
	float3 vHalf = normalize(lightNormal + toEye);
	float specularAmount = saturate(dot(surfaceNormal, vHalf));
	specularAmount = pow(specularAmount, max(materialSpecularPower, 0.0001f)) * lightSpecularIntensity;
	float3 specular = materialSpecularColor * lightColor * specularAmount;

	return specular;

float4 PS(VS_OUT pIn) : SV_Target
	// we need to normalize incoming vectors
	float3 normal = normalize(pIn.Normal);
	float3 toEye = normalize(pIn.ToCameraTangentSpace);
	float3 toLight = normalize(pIn.ToLightTangentSpace);

	float3 local0 = SpecularContribution(toEye, toLight, normal, MaterialSpecular.rgb, MaterialSpecularPower, 8, ParallelLightArray[0].DiffuseColor.rgb);
	float3 local2 = LambertLighting(toLight, normal, MaterialAmbient.rgb, ParallelLightArray[0].AmbientColor.rgb, ParallelLightArray[0].DiffuseColor.rgb, pIn.Diffuse.rgb);
	float3 local3 = local0 + local2;
	float4 fragment = CombineRGBWithAlpha(local3, pIn.Diffuse.a);

	if (fragment.a == 0.0f) discard;

	return fragment;

Edited by karnaltaB

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!