Strange shader problem (beginner)

Started by
-1 comments, last by karnaltaB 7 years, 10 months ago

Hi,

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 :

Common.HLSL


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);
}

VertexShader.HLSL


#include "Common.hlsl"

VS_OUT VS(VS_IN vIn)
{
	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;
}

PixelShader.HLSL


#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);

	// BEGIN GENERATED CODE
	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);
	// END GENERATED CODE

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

	return fragment;

}

This topic is closed to new replies.

Advertisement