HLSL - Flat Shading

  • (2 Pages)
  • +
  • 1
  • 2

24 Replies - 4692 Views - Last Post: 31 August 2012 - 07:49 AM Rate Topic: -----

#1 ichkanns  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 24-August 12

HLSL - Flat Shading

Posted 24 August 2012 - 09:45 AM

I'm trying to render a bunch of textured cubes right next to each other with a universal light source, in this case the sun. In other words the light source shouldn't diffuse with distance, only angle. So, my though on how to do this would be to not transpose the normals according to their position in the world but rather to take the dot product of the normals and the light direction as the normals stand. I'm glad to say it's shading every block the same, but it's diffusing at the edges of the block. Not sure why. I just want an entire face of the block to be one shade. Any suggestions?
 float4x4 World;
float4x4 View;
float4x4 Projection;

float4 AmbientColor = float4(1, 1, 1, 1);
float AmbientIntensity = 0.1f;

float4x4 WorldInverseTranspose;

float3 DiffuseLightDirection = float3(1, 0, 0);
float4 DiffuseColor = float4(1, 1, 1, 1);
float DiffuseIntensity = 1.0f;

float Shininess = 200;
float4 SpecularColor = float4(1, 1, 1, 1);
float SpecularIntensity = 1;
float3 ViewVector = float3(1, 0, 0);

texture ModelTexture;
sampler2D textureSampler = sampler_state {
	Texture = (ModelTexture);
	MinFilter = Linear;
    MagFilter = Linear;
    AddressU = Clamp;
    AddressV = Clamp;
};

struct VertexShaderInput
{
    float4 Position : POSITION0;
	float4 Normal : NORMAL0;
	float2 TextureCoordinate : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
	float4 Normal : TEXCOORD0;
	float4 Color : COLOR0;
	float2 TextureCoordinate : TEXCOORD1;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    float4 normal = input.Normal;
	float lightIntensity = max(0, dot(normal, DiffuseLightDirection));
	output.Color = lightIntensity * DiffuseColor * DiffuseIntensity + AmbientColor * AmbientIntensity;
	output.Color.a = 1;

	output.Normal = normalize(normal);

	output.TextureCoordinate = input.TextureCoordinate;

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	float3 light = DiffuseLightDirection;
	float3 normal = input.Normal;
	float3 r = normalize(2 * dot(light, normal) * normal - light);
	float3 v = normalize(mul(normalize(ViewVector), World));

	float dotProduct = dot(r,v);
	float4 specular = SpecularIntensity * SpecularColor * max(pow(dotProduct, Shininess), 0) * length(input.Color);

	float4 textureColor = tex2D(textureSampler, input.TextureCoordinate);
	textureColor.a = 1;

    return saturate(textureColor * (input.Color) + specular);
}

technique Specular
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}


The result looks like the attached image. I'm really knew to shader languages, around 3 days new, though I've understood the principle for a while. I'm still getting the intricacies down.

Thanks,
Ichkanns

Attached image(s)

  • Attached Image


Is This A Good Question/Topic? 0
  • +

Replies To: HLSL - Flat Shading

#2 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 570
  • View blog
  • Posts: 1,270
  • Joined: 24-April 12

Re: HLSL - Flat Shading

Posted 24 August 2012 - 12:10 PM

Your ambient intensity is 0.1 and your diffuse intensity is 1.0. If you want the lighting to be even across the entire surface set ambient to 1.0 and diffuse to 0.0.
Was This Post Helpful? 0
  • +
  • -

#3 ichkanns  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 24-August 12

Re: HLSL - Flat Shading

Posted 24 August 2012 - 12:17 PM

View PostBBeck, on 24 August 2012 - 12:10 PM, said:

Your ambient intensity is 0.1 and your diffuse intensity is 1.0. If you want the lighting to be even across the entire surface set ambient to 1.0 and diffuse to 0.0.


Thanks, but perhaps I need to rephrase what I want. I still want a directional light, but I want an entire face to be uniform. So every up facing face should be one shade, every right facing face should be one shade... etc. Ambient light just gives me a uniform shade on all sides of the block. Does that make sense? Sometimes I'm bad at explaining.
Was This Post Helpful? 0
  • +
  • -

#4 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 570
  • View blog
  • Posts: 1,270
  • Joined: 24-April 12

Re: HLSL - Flat Shading

Posted 24 August 2012 - 01:02 PM

I was real worried that I wasn't going to solve this one. :-)

I'm just exploring HLSL right now too in XNA. So, I'm at about the same place you are.

I think the problem is that you are not tranlating your normals.


I'm looking at RBWhitaker's website (a great website by the way) and he's got an example of a diffuse shader. He translates every normal of every object.


http://rbwhitaker.wi...lighting-shader

I kept thinking, "Well. You've got to either have the light direction vector move or the normal on the face move or it's going to draw the same way every time.

Anyway, it looks to me that this code in his example is what you are missing:

   float4 normal = mul(input.Normal, WorldInverseTranspose);
    float lightIntensity = dot(normal, DiffuseLightDirection);




WorldInverseTranspose being the key, I think.

This post has been edited by BBeck: 24 August 2012 - 01:04 PM

Was This Post Helpful? 1
  • +
  • -

#5 ichkanns  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 24-August 12

Re: HLSL - Flat Shading

Posted 24 August 2012 - 01:08 PM

View PostBBeck, on 24 August 2012 - 01:02 PM, said:

I was real worried that I wasn't going to solve this one. :-)

I'm just exploring HLSL right now too in XNA. So, I'm at about the same place you are.

I think the problem is that you are not tranlating your normals.


I'm looking at RBWhitaker's website (a great website by the way) and he's got an example of a diffuse shader. He translates every normal of every object.


http://rbwhitaker.wi...lighting-shader

I kept thinking, "Well. You've got to either have the light direction vector move or the normal on the face move or it's going to draw the same way every time.

Anyway, it looks to me that this code in his example is what you are missing:

   float4 normal = mul(input.Normal, WorldInverseTranspose);
    float lightIntensity = dot(normal, DiffuseLightDirection);




WorldInverseTranspose being the key, I think.


Actually that's the exact site I've been using to learn all this. I tried using his exact diffuse shader and that's where this problem originally came up. What I posted is an altered version, which to me made sense for what I wanted to do. Since a want to treat every block the same in relation to the light, I figured it would be best to treat them all as if they were in the same place, thus not translating the normals. Which worked, every block is treated the same, but for some reason it doesn't treat a single surface as uniformly the same. Which I don't understand because seeing as it is a flat surface the normal should be the same at every point. Holy crap I think I just figured it out... I'll get back to you.
Was This Post Helpful? 0
  • +
  • -

#6 ichkanns  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 24-August 12

Re: HLSL - Flat Shading

Posted 24 August 2012 - 01:18 PM

Nevermind. Didn't figure it out. If anyone can tell me how to make a face uniformly shaded with a directional shader... I'd appreciate it.
Was This Post Helpful? 0
  • +
  • -

#7 ichkanns  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 24-August 12

Re: HLSL - Flat Shading

Posted 24 August 2012 - 02:48 PM

Alright, I think what I've figured out is that the shader is using the vertex normals to calculate light when I want it to use the face normals. So my new question is, how do I do that? I assume it would involve finding the normals in the pixel shader and doing the calculations there, not sure how to go about it though.
Was This Post Helpful? 0
  • +
  • -

#8 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 570
  • View blog
  • Posts: 1,270
  • Joined: 24-April 12

Re: HLSL - Flat Shading

Posted 27 August 2012 - 01:41 PM

I'll take another stab at it here. I backed off on answering a bit, this weekend, because I was busy with my own project and I also realize that I don't know much more about HLSL than you do. But, I've been looking at HLSL and there are a couple of things that come to mind.

First, it looks odd to me that you've got so much going on in your pixel shader for Phong shading. I think almost every example I've seen does those calculations in the vertex shader, which could be contributing to the problem. I certainly can't say that for certain, but it does look a bit odd to me.

As far as using face normals instead of vertex normals, I see what you're saying there, and you're probably at least partially right on that.

I haven't seen anything, especially on shaders as simple as this where face normals were used. I'm pretty certain that the normals coming in are vertex normals, which makes sense. I mean cubes are by far in the minority for 3D objects these days, most objects have thousands - if not millions - of polygons, and you generally want those shaded without the hard edges that face normals would give you. Something like a cube, with it's hard edges, is kind of the exception.

So, I imagine the vertices at the corners of the cube only have one normal per vertex, and logically that normal is probably pointing in a direction that is an average of the three faces that it connects (for every vertex). My guess, is that the vertices are all pointing straight out from the corners, and that would probably - at least partially - explain why you get a difference in shading from one side of the polygon/triangle to the opposite.

You could "probably" redefine the normals in your cube model, so that the four corners on top have their normals all pointing up and the normals on the bottom all have their normals pointing straight down.

That "should" give you a more uniform shading across the top surface, and the differing position of each of the normals should cause the specular highlight and directional lighting to be applied evenly across the entire area.

Unless you are doing this to learn HLSL, you might be much better off using BasicEffect for this. There's nothing you're doing here that's not built into BasicEffect.
Was This Post Helpful? 1
  • +
  • -

#9 ichkanns  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 24-August 12

Re: HLSL - Flat Shading

Posted 27 August 2012 - 02:23 PM

View PostBBeck, on 27 August 2012 - 01:41 PM, said:

I'll take another stab at it here. I backed off on answering a bit, this weekend, because I was busy with my own project and I also realize that I don't know much more about HLSL than you do. But, I've been looking at HLSL and there are a couple of things that come to mind.

First, it looks odd to me that you've got so much going on in your pixel shader for Phong shading. I think almost every example I've seen does those calculations in the vertex shader, which could be contributing to the problem. I certainly can't say that for certain, but it does look a bit odd to me.

As far as using face normals instead of vertex normals, I see what you're saying there, and you're probably at least partially right on that.

I haven't seen anything, especially on shaders as simple as this where face normals were used. I'm pretty certain that the normals coming in are vertex normals, which makes sense. I mean cubes are by far in the minority for 3D objects these days, most objects have thousands - if not millions - of polygons, and you generally want those shaded without the hard edges that face normals would give you. Something like a cube, with it's hard edges, is kind of the exception.

So, I imagine the vertices at the corners of the cube only have one normal per vertex, and logically that normal is probably pointing in a direction that is an average of the three faces that it connects (for every vertex). My guess, is that the vertices are all pointing straight out from the corners, and that would probably - at least partially - explain why you get a difference in shading from one side of the polygon/triangle to the opposite.

You could "probably" redefine the normals in your cube model, so that the four corners on top have their normals all pointing up and the normals on the bottom all have their normals pointing straight down.

That "should" give you a more uniform shading across the top surface, and the differing position of each of the normals should cause the specular highlight and directional lighting to be applied evenly across the entire area.

Unless you are doing this to learn HLSL, you might be much better off using BasicEffect for this. There's nothing you're doing here that's not built into BasicEffect.


Yeah. I know it's the vertex normals that are causing the problem, and I for sure it's because the natural state now adays is to have smooth edges rather than hard edges. I'm really trying to learn HLSL and I plan on extending these shaders to be a lot more complex. Real time shadows, reflective surfaces, that kind of jazz. So I want all the shaders to be hand built so I can manipulate them as becomes necessary.

The complexity of the pixel shader is the specular shading which will need some crazy revamping once I figure this out.

I really just need a way to tell the different faces inside the shader program and at that point I can make the normals myself, seeing as they are float3(0,0,1), float3(0,0,-1), float3(0,1,0)... and so forth. So if I can figure out which face the current pixel I'm shading is on, then I can do this no problem.
Was This Post Helpful? 0
  • +
  • -

#10 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 570
  • View blog
  • Posts: 1,270
  • Joined: 24-April 12

Re: HLSL - Flat Shading

Posted 27 August 2012 - 02:35 PM

I'm "with you" on all the advantages of HLSL. I've been trying to get as much mileage out of the built in shaders, like BasicEffect as possible, but I'm working on interiors now. All my exterior stuff looked fine without any special lighting, but the interiors look completely un-natural. I mean if you think about it, almost all interior lighting is point lighting coming from a light bulb or a torch or something. So, I've been getting kind of jazzed about learning HLSL myself.

Anyway, I'll keep your stuff in mind as I study this some more. This last weekend, I worked on other stuff in my game/level editor (which was really good because it was kind of semi-complicated collision stuff that I was dreading digging into and wanted to go study HLSL instead; but now that it's done I can feel guilt free about dedicating more time to HLSL. I'm also finding that studying HLSL is helping me understand some of the stuff that's built into XNA better like the texture sampler for example). So, as I study HLSL, I'll keep this issue in mind and let you know if I think I have something that might be helpful.
Was This Post Helpful? 1
  • +
  • -

#11 ichkanns  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 24-August 12

Re: HLSL - Flat Shading

Posted 27 August 2012 - 02:38 PM

View PostBBeck, on 27 August 2012 - 02:35 PM, said:

I'm "with you" on all the advantages of HLSL. I've been trying to get as much mileage out of the built in shaders, like BasicEffect as possible, but I'm working on interiors now. All my exterior stuff looked fine without any special lighting, but the interiors look completely un-natural. I mean if you think about it, almost all interior lighting is point lighting coming from a light bulb or a torch or something. So, I've been getting kind of jazzed about learning HLSL myself.

Anyway, I'll keep your stuff in mind as I study this some more. This last weekend, I worked on other stuff in my game/level editor (which was really good because it was kind of semi-complicated collision stuff that I was dreading digging into and wanted to go study HLSL instead; but now that it's done I can feel guilt free about dedicating more time to HLSL. I'm also finding that studying HLSL is helping me understand some of the stuff that's built into XNA better like the texture sampler for example). So, as I study HLSL, I'll keep this issue in mind and let you know if I think I have something that might be helpful.


Thanks man!
Was This Post Helpful? 0
  • +
  • -

#12 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 570
  • View blog
  • Posts: 1,270
  • Joined: 24-April 12

Re: HLSL - Flat Shading

Posted 27 August 2012 - 02:40 PM

Incidenty, to the moderators, this really is not an XNA question. It's pretty firmly a HLSL question which spans multiple languages including C++. So, it would have been better to have it in the main game forum where there would be a greater chance of someone familiar with HLSL to answer the question. The answer to this question is likely to be the same in C++ as it would be in XNA.
Was This Post Helpful? 0
  • +
  • -

#13 Kilorn  Icon User is offline

  • XNArchitect
  • member icon



Reputation: 1356
  • View blog
  • Posts: 3,528
  • Joined: 03-May 10

Re: HLSL - Flat Shading

Posted 28 August 2012 - 05:57 AM

Yea, I'm going to remove the XNA from the title, and toss it back to the Game Development section real quick so that other people can see it a little more easily.
Was This Post Helpful? 0
  • +
  • -

#14 stayscrisp  Icon User is offline

  • フカユ
  • member icon

Reputation: 998
  • View blog
  • Posts: 4,173
  • Joined: 14-February 08

Re: HLSL - Flat Shading

Posted 28 August 2012 - 07:33 AM

Give this a try

float4x4 World;
float4x4 View;
float4x4 Projection;

float4 AmbientColor = float4(1, 1, 1, 1);
float AmbientIntensity = 0.1;

float4x4 WorldInverseTranspose;

float3 DiffuseLightDirection = float3(1, 0, 0);
float4 DiffuseColor = float4(1, 1, 1, 1);
float DiffuseIntensity = 1.0;

texture ModelTexture;
sampler2D textureSampler = sampler_state {
    Texture = (ModelTexture);
    MagFilter = Linear;
    MinFilter = Linear;
    AddressU = Clamp;
    AddressV = Clamp;
};

struct VertexShaderInput
{
    float4 Position : POSITION0;    
    float4 Normal : NORMAL0;
    float2 TextureCoordinate : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float4 Color : COLOR0;
    float2 TextureCoordinate : TEXCOORD1;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    float4 normal = mul(input.Normal, WorldInverseTranspose);
    float lightIntensity = dot(normal, DiffuseLightDirection);
    output.Color = saturate(DiffuseColor * DiffuseIntensity * lightIntensity);

    output.TextureCoordinate = input.TextureCoordinate;

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	float4 textureColor = tex2D(textureSampler, input.TextureCoordinate);
	textureColor.a = 1;
	
    return saturate(textureColor * (input.Color) + AmbientColor * AmbientIntensity);
}

technique Ambient
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}



If it works I will explain why :)
Was This Post Helpful? 2
  • +
  • -

#15 ichkanns  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 24-August 12

Re: HLSL - Flat Shading

Posted 30 August 2012 - 08:20 AM

So, I figured it out. Here is the working shader:

float4x4 World;
float4x4 View;
float4x4 Projection;

float4 AmbientColor = float4(1, 1, 1, 1);
float AmbientIntensity = 0.1f;

float3 DiffuseLightDirection = float3(1, 0, 0);
float4 DiffuseColor = float4(1, 1, 1, 1);
float DiffuseIntensity = 1.0f;

texture ModelTexture;
sampler2D textureSampler = sampler_state {
	Texture = (ModelTexture);
	MinFilter = Linear;
    MagFilter = Linear;
    AddressU = Clamp;
    AddressV = Clamp;
};

struct VertexShaderInput
{
    float4 Position : POSITION0;
	float4 Normal : NORMAL0;
	float2 TextureCoordinate : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
	float4 PositionWorld : TEXCOORD0;
	float2 TextureCoordinate : TEXCOORD1;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
	output.PositionWorld = worldPosition;

	output.TextureCoordinate = input.TextureCoordinate;

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	float3 Normal = cross(ddy(input.PositionWorld.xyz), ddx(input.PositionWorld.xyz));
	Normal = normalize(Normal);

	float lightIntensity = dot(Normal, DiffuseLightDirection);
	float4 lightColor = lightIntensity * DiffuseColor * DiffuseIntensity + AmbientColor * AmbientIntensity;
	lightColor.a = 1;

	float4 textureColor = tex2D(textureSampler, input.TextureCoordinate);
	textureColor.a = 1;

    return saturate(textureColor * lightColor);
}

technique FlatTextured
{
    pass Pass1
    {
        VertexShader = compile vs_3_0 VertexShaderFunction();
        PixelShader = compile ps_3_0 PixelShaderFunction();
    }
}



Basically I just calculated the normals in the pixel shader based on the world position of the current pixel. Works great! If anyone wants to use it they can feel free.



Attached Image
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2