here's an example object shader, I've marked the important parts with ***
Code:
//==========

#define ANGLE_SURFACE_DARKEN 0.75 // *** strength of the darkening effect; range [0 - 1]

//==========

const float     fAmbient; // used as per-entity brightness factor here

const float4    vecViewPos;

const float4x4  matWorld;
const float4x4  matViewProj;

//==========

const texture entSkin1;
sampler2D smpTex = sampler_state
{
	Texture = <entSkin1>;
	
	MipFilter = Linear;
	MagFilter = Point;
	MinFilter = Point;
	
	AddressU = Wrap;
	AddressV = Wrap;
};

//==========

struct VertexShaderInput
{
	float4 Position : POSITION0;
	float2 Tex : TEXCOORD0;
	float3 Normal : NORMAL; // *** contains the object space normals of the block
};

struct VertexShaderOutput
{
	float4 Position : POSITION0;
	float2 Tex : TEXCOORD0;
	float3 Light : TEXCOORD1; // *** used to store the calculated light value for the object
};

//==========

VertexShaderOutput VShader(VertexShaderInput input)
{
	VertexShaderOutput output;
	
	//
	
	float4 vWorldPos = mul(input.Position, matWorld); // transform the coordinates in two steps (matWorld & matViewProj instead of matWorldViewProj) because the world position is needed
	output.Position = mul(vWorldPos, matViewProj); // transform to the final screen-space coordinates
	
	output.Tex = input.Tex; // pass the texture coordinates
	
	float3 vPixelToViewDir = normalize(vecViewPos.xyz - vWorldPos.xyz); // *** direction vector from the surface to the camera
	
	float3 vNormal = normalize(mul(float4(input.Normal, 0), matWorld).xyz); // *** transform surface normal from object space to world space
	
	float dot_result = dot(vPixelToViewDir, vNormal); // *** get the angle ( cos(angle) ) between these vectors; both vectors in the dot product have to be normalized (length = 1)
	
	output.Light = fAmbient.xxx; // *** light (= entity brightness) is defined by ent->ambient
	output.Light *= saturate(1.0 - (1.0 - dot_result) * ANGLE_SURFACE_DARKEN); // *** apply the darkening factor with adjustable intensity; saturate() to prevent negative numbers (and numbers > 1)
	
	//
	
	return output;
}

//==========

float4 PShader(VertexShaderOutput In) : COLOR0
{
	float4 Color = tex2D(smpTex, In.Tex);
	
	Color.rgb *= In.Light; // *** simply apply the Light value recieved from the vertex shader to the texture
	
	return Color;
}

//==========

technique Tech_PP
{
	pass Pass_1
	{
		Lighting = False;
		
		AlphaBlendEnable = False;
		AlphaTestEnable = True;
		
		VertexShader = compile vs_3_0 VShader();
		PixelShader = compile ps_3_0 PShader();
	}
}

if you're already using an object shader for your level it shouldn't be too hard to implement it.

I've put the light-calculation in the vertexshader for performance reasons. It wouldn't be that much slower when it's in the pixel shader but there are way fewer vertices than pixels in your scene so it's a free preformance boost laugh

edit: it doesn't use fog though. if you're using the default shader, fog still needs to be implemented.

Last edited by Kartoffel; 06/20/16 14:55.

POTATO-MAN saves the day! - Random