• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Medo Mex

Light doesn't work without bump map

26 posts in this topic

I created a point light on the terrain and it works perfectly, however when I remove the bump map, it doesn't work anymore.

 

When I do the following I don't see the light on the terrain:

float3 n = normalize(IN.Normal);

When I do the following I see the light:

float3 n = normalize(tex2D(normalMap, IN.UV).rgb * 2.0f - 1.0f);

I checked to see if the mesh has normal and found that it has normal.

0

Share this post


Link to post
Share on other sites

Are you multiplying the normal with the world inverse transposed inside the vertex shader?

OUT.normal = mul(IN.normal, (float3x3)worldInverseTransposeMatrix);
0

Share this post


Link to post
Share on other sites

3 suggestions:

 

1. Even though you know the mesh has normals, check that the normals are passed all the way from your Direct3D code (C/C++?) to the shader where you're doing the lighting (HLSL). Does your vertex declaration include a normal? If you're doing per pixel lighting, perhaps the normal is available in the vertex shader, but it's not being passed to the pixel shader?

2. You can use PIX to debug graphics issues (just google "pix debug tutorial")

3. Post the full shader code here

0

Share this post


Link to post
Share on other sites

Here is the shader code:

float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 worldInverseTransposeMatrix;

float3 cameraPos;
float materialPower;
float4 materialDiffuse;
float4 materialAmbient;
float4 materialSpecular;

float3 lightPosition;
float4 lightDiffuse;
float4 lightSpecular;
float lightRange;

float4 globalAmbient;

texture colorMapTexture;
sampler2D colorMap = sampler_state
{
    Texture = <colorMapTexture>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

// Bump map
texture normalMapTexture;
sampler2D normalMap = sampler_state
{
    Texture = <normalMapTexture>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

struct VERTEX
{
    float3 Pos : POSITION;
    float3 Normal : NORMAL;
    float2 UV : TEXCOORD0;
};

struct VS_OUTPUT
{
   float4 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
   float4 worldPos : TEXCOORD2;
};

VS_OUTPUT VS( VERTEX IN )
{
     VS_OUTPUT OUT;
     OUT = (VS_OUTPUT)0;
     float4x4 WVP = mul(World, mul(View, Projection));
     OUT.Pos = mul(float4(IN.Pos, 1.0f), WVP);
     OUT.Normal = mul(IN.Normal, (float3x3)worldInverseTransposeMatrix);
     OUT.UV = IN.UV;
     OUT.worldPos = mul(float4(IN.Pos, 1.0f), World);
     return OUT;
}

float4 PS( VS_OUTPUT IN ) : COLOR
{
    float3 viewDir = cameraPos - IN.worldPos;
    float3 lightDir = (lightPosition - IN.worldPos) / lightRange;
    float atten = saturate(1.0f - dot(lightDir, lightDir));


    float3 n =  normalize(IN.Normal); 
    // *** LIGHT ONLY WORKS WHEN I REPLACE THE ABOVE LINE WITH THIS LINE --> normalize(tex2D(normalMap, IN.UV).rgb * 2.0f - 1.0f); ***
    float3 l = normalize(lightDir);
    float3 v = normalize(viewDir);
    float3 h = normalize(l + v);
    
    float nDotL = saturate(dot(n, l));
    float nDotH = saturate(dot(n, h));
    float power = (nDotL == 0.0f) ? 0.0f : pow(nDotH, materialPower);


    float4 diffuse = materialDiffuse * lightDiffuse;
    float4 specular = materialSpecular * lightSpecular;
    float4 lightColor = (materialAmbient + globalAmbient) + 
                             (diffuse * nDotL * atten) + 
                             (specular * power * atten);
    return tex2D(colorMap, IN.UV) * lightColor;
}

technique TerrainTech
{
    pass p0
    {
        VertexShader = compile vs_3_0 VS();
        PixelShader  = compile ps_3_0 PS();
    }
}

Yes, the vertex declaration include Normal.

0

Share this post


Link to post
Share on other sites

I agree with gfxgansta, even though you have the normals in the vertex declarations, it may be possible that they are not correctly passed from the cpu to the gpu.

 

Try visualising the normals, like: PS: return float4(IN.Normal, 1.0f);

Edited by Migi0027
0

Share this post


Link to post
Share on other sites

I'm sure this problem is related to the light shader itself.

 

The light DOES work on some meshes, while it doesn't work on the terrain, also I THINK it's not working correctly on other meshes, the mesh sometimes is lighting from one side even the mesh is over the light (it should light from other sides as well) then when I move it it get some light from sides.

 

I believe the shader light is not correct, can someone check the shader and let me know if it's a VALID light shader?

 

@Migi0027: Tried that, it doesn't work.

Edited by Medo3337
0

Share this post


Link to post
Share on other sites

I created a point light on the terrain and it works perfectly, however when I remove the bump map, it doesn't work anymore.

 

When I do the following I don't see the light on the terrain:

float3 n = normalize(IN.Normal);

When I do the following I see the light:

float3 n = normalize(tex2D(normalMap, IN.UV).rgb * 2.0f - 1.0f);

I checked to see if the mesh has normal and found that it has normal.

 

The first line depends on IN.Normal. The second line only depends on IN.UV. I'm no lighting expert, but I'm fairly sure that the normals from your texture are supposed to be transformed in some way.

 

How does your bump map work perfectly? You are calculating a normal for each vertex and then throwing them away. That cannot be intentional.

Edited by Pink Horror
0

Share this post


Link to post
Share on other sites

@Pink Horror: Check out my shader above, when I apply bump map it DOES look very well.

 

When I remove the bump map I don't see the light, I tried to move the terrain upwards, now I get to see the light, I also get to see the light when I set large amount of "point light radius".

 

I guess the light get positioned incorrectly when I don't use bump map.

 

In Vertex Shader, I'm transforming the normal as the following:

OUT.Normal = mul(IN.Normal, (float3x3)worldInverseTransposeMatrix);
Edited by Medo3337
0

Share this post


Link to post
Share on other sites

What do you mean by, it does not work? Is it black?

 

Try normalizing them and then visualize them, if there is literally no color change around the terrain, with the normal visualisation, that means that the normals are not passed to the shader.

0

Share this post


Link to post
Share on other sites

@Migi0027: The light EXISTS, but it's not on the valid position (on the terrain), I can only see it when I move the terrain up or increase the light radius.

 

Though, the light is affecting other objects over the terrain.

 

EDIT: After testing, I notice that the light ONLY affect the terrain when its position is colliding with the terrain, however you know that point light position doesn't necessarily have to collide with the mesh, it could affect the mesh from some distance (according to the light radius/range).

 

I also tested to make sure that the normals are passed and found that the program pass it to the shader, however, still the same issue.

Edited by Medo3337
0

Share this post


Link to post
Share on other sites

 

@Pink Horror: Check out my shader above, when I apply bump map it DOES look very well.

 

When I remove the bump map I don't see the light, I tried to move the terrain upwards, now I get to see the light, I also get to see the light when I set large amount of "point light radius".

 

I guess the light get positioned incorrectly when I don't use bump map.

 

In Vertex Shader, I'm transforming the normal as the following:

OUT.Normal = mul(IN.Normal, (float3x3)worldInverseTransposeMatrix);

 

Why are you computing this normal?

0

Share this post


Link to post
Share on other sites

Of course you need to transform the normal because it depends on object orientation.

 

Can you create minimal project, zip it and share a link here so it will be easier to help you.

Edited by belfegor
0

Share this post


Link to post
Share on other sites

@belfegor: I created a new project, in this project I have a plane and a box

 

When I set:

Light position to (XYZ: 0.0f, 0.0f, 0.0f)

Plane position to (XYZ: 0.0f, 0.0f, 0.0f)

Light range: 5000.0f

 

I don't see the light

 

BUT, when I move the light up, I start to see the light:

Light position to (XYZ: 0.0f, 10.0f, 0.0f)

Plane position to (XYZ: 0.0f, 0.0f, 0.0f)

Light range: 5000.0f

 

Project: http://www.2shared.com/file/F-SF9SLo/Light_Problem_Sample.html

 

EDIT:

Another problem I noticed now, when I apply bump map, the light get positioned incorrectly.

 

I do that by replacing float3 n = normalize(IN.Normal); to normalize(tex2D(normalMap, IN.UV).rgb * 2.0f - 1.0f); and passing a bump map texture to the shader.

Edited by Medo3337
0

Share this post


Link to post
Share on other sites

Try the project from attachment.

 

edit: Forgat to note about camera controls: w-s-a-d movement, left mouse press and move to rotate.

Edited by belfegor
0

Share this post


Link to post
Share on other sites

@belfegor: When I apply bump map, the light change its position to invalid position.

 

I modified your project to support bump mapping and I can notice the problem:

[attachment=17043:Terrain modified.rar]

 

After running the program hold 'B' to enable bump mapping and see that the light position is not the same.

Edited by Medo3337
0

Share this post


Link to post
Share on other sites

You can't just stitch normal map texture and be done, you need tangent and binormal vectors in mesh VB to have bump mapping! Try this now.

 

 

0

Share this post


Link to post
Share on other sites

Well you can always compute them, with something similar to this:

/// <summary>
        /// Given the 3 vertices (position and texture coordinate) and the
        /// face normal of a triangle calculate and return the triangle's
        /// tangent vector. This method is designed to work with XNA's default
        /// right handed coordinate system and clockwise triangle winding order.
        /// Undefined behavior will result if any other coordinate system
        /// and/or winding order is used. The handedness of the local tangent
        /// space coordinate system is stored in the tangent's w component.
        /// </summary>
        /// <param name="pos1">Triangle vertex 1 position</param>
        /// <param name="pos2">Triangle vertex 2 position</param>
        /// <param name="pos3">Triangle vertex 3 position</param>
        /// <param name="texCoord1">Triangle vertex 1 texture coordinate</param>
        /// <param name="texCoord2">Triangle vertex 2 texture coordinate</param>
        /// <param name="texCoord3">Triangle vertex 3 texture coordinate</param>
        /// <param name="normal">Triangle face normal</param>
        /// <param name="tangent">Calculated tangent vector</param>
        public static void CalcTangent(ref Vector3 pos1,
                                       ref Vector3 pos2,
                                       ref Vector3 pos3,
                                       ref Vector2 texCoord1,
                                       ref Vector2 texCoord2,
                                       ref Vector2 texCoord3,
                                       ref Vector3 normal,                                       
                                       out Vector4 tangent)
        {
            // Create 2 vectors in object space.
            // edge1 is the vector from vertex positions pos1 to pos3.
            // edge2 is the vector from vertex positions pos1 to pos2.
            Vector3 edge1 = pos3 - pos1;
            Vector3 edge2 = pos2 - pos1;
            
            edge1.Normalize();
            edge2.Normalize();

            // Create 2 vectors in tangent (texture) space that point in the
            // same direction as edge1 and edge2 (in object space).
            // texEdge1 is the vector from texture coordinates texCoord1 to texCoord3.
            // texEdge2 is the vector from texture coordinates texCoord1 to texCoord2.
            Vector2 texEdge1 = texCoord3 - texCoord1;
            Vector2 texEdge2 = texCoord2 - texCoord1;

            texEdge1.Normalize();
            texEdge2.Normalize();

            // These 2 sets of vectors form the following system of equations:
            //
            //  edge1 = (texEdge1.x * tangent) + (texEdge1.y * bitangent)
            //  edge2 = (texEdge2.x * tangent) + (texEdge2.y * bitangent)
            //
            // Using matrix notation this system looks like:
            //
            //  [ edge1 ]     [ texEdge1.x  texEdge1.y ]  [ tangent   ]
            //  [       ]  =  [                        ]  [           ]
            //  [ edge2 ]     [ texEdge2.x  texEdge2.y ]  [ bitangent ]
            //
            // The solution is:
            //
            //  [ tangent   ]        1     [ texEdge2.y  -texEdge1.y ]  [ edge1 ]
            //  [           ]  =  -------  [                         ]  [       ]
            //  [ bitangent ]      det A   [-texEdge2.x   texEdge1.x ]  [ edge2 ]
            //
            //  where:
            //        [ texEdge1.x  texEdge1.y ]
            //    A = [                        ]
            //        [ texEdge2.x  texEdge2.y ]
            //
            //    det A = (texEdge1.x * texEdge2.y) - (texEdge1.y * texEdge2.x)
            //
            // From this solution the tangent space basis vectors are:
            //
            //    tangent = (1 / det A) * ( texEdge2.y * edge1 - texEdge1.y * edge2)
            //  bitangent = (1 / det A) * (-texEdge2.x * edge1 + texEdge1.x * edge2)
            //     normal = cross(tangent, bitangent)

            Vector3 t;
            Vector3 b;
            float det = (texEdge1.X * texEdge2.Y) - (texEdge1.Y * texEdge2.X);

            if ((float)Math.Abs(det) < 1e-6f)    // almost equal to zero
            {
                t = Vector3.UnitX;
                b = Vector3.UnitY;
            }
            else
            {
                det = 1.0f / det;

                t.X = (texEdge2.Y * edge1.X - texEdge1.Y * edge2.X) * det;
                t.Y = (texEdge2.Y * edge1.Y - texEdge1.Y * edge2.Y) * det;
                t.Z = (texEdge2.Y * edge1.Z - texEdge1.Y * edge2.Z) * det;

                b.X = (-texEdge2.X * edge1.X + texEdge1.X * edge2.X) * det;
                b.Y = (-texEdge2.X * edge1.Y + texEdge1.X * edge2.Y) * det;
                b.Z = (-texEdge2.X * edge1.Z + texEdge1.X * edge2.Z) * det;

                t.Normalize();
                b.Normalize();
            }

            // Calculate the handedness of the local tangent space.
            // The bitangent vector is the cross product between the triangle face
            // normal vector and the calculated tangent vector. The resulting bitangent
            // vector should be the same as the bitangent vector calculated from the
            // set of linear equations above. If they point in different directions
            // then we need to invert the cross product calculated bitangent vector. We
            // store this scalar multiplier in the tangent vector's 'w' component so
            // that the correct bitangent vector can be generated in the normal mapping
            // shader's vertex shader.

            Vector3 bitangent = Vector3.Cross(normal, t);
            float handedness = (Vector3.Dot(bitangent, b) < 0.0f) ? -1.0f : 1.0f;

            tangent.X = t.X;
            tangent.Y = t.Y;
            tangent.Z = t.Z;
            tangent.W = handedness;
        }

foe each vertex in your mesh, figure out the other two vertices that make up the triangle using the index array, and call this method.

1

Share this post


Link to post
Share on other sites

@belfegor: I'm using Panda Exporter in 3Ds Max, it's not exporting the mesh with tangent and binormal...

 

You can calculate them as DwarvesH showed or use D3DXComputeTangentFrame as i have written in the demo since you didn't spot it.

1

Share this post


Link to post
Share on other sites

@belfegor: After checking for awhile, I notice that when I set the light color to a certain color (for example: red) and set material ambient to something like 0.8

 

The whole terrain become reddish

 

Light gLight = { D3DXVECTOR3(0.0f, 2.0f, 0.0f), 5.0f, D3DXVECTOR3(1.0f, 0.0f, 0.0f) };
Material gMaterial = { D3DXVECTOR3(1.0f, 1.0f, 1.0f), 80.0f, 0.8f };

 

0

Share this post


Link to post
Share on other sites

Well, yes. You are using your point light as a normal point light with attenuation, but it also provides the ambient lighting to your terrain. So the terrain ambient lighting and the light color are the same. You only have one light, so what is not touched by the light is black.

 

You should provide the terrain ambient lighting by a different light source, probably directional. Alternatively, you could add a flat ambient lighting to the terrain, independent on any light source.

0

Share this post


Link to post
Share on other sites

@DwarvesH: I don't want the terrain to be black when there is no light in certain places.

 

If there is no light source on certain parts, it should be affected by global ambient.

Edited by Medo3337
0

Share this post


Link to post
Share on other sites

I would recommend that you first have a go at playing around with the shader and make sure you understand what is what and what it does. This way you will be able to build upon the foundation shader on your own.

 

For starters, you could go int you bump mapped pixel shader, and replace:

float atten     = saturate(1.0f - dot(lightDir, lightDir)) + MaterialAmbient;

with:


float atten     = saturate(1.0f - dot(lightDir, lightDir));

Now you can see the actual extents of a classical point light. You can then use the controls of your demo to change position and radius and see how the light looks in isolation.

 

Then you can try removing the attenuation and see how the shading looks only with direction being important:

float atten     = 1;

Then you can try a very simple and very ugly basic ambient coefficient:

float atten     = saturate(1.0f - dot(lightDir, lightDir));

...

float3 diffuse  = LightDiffuse * MaterialDiffuse * texDiffuse * (nDotL * atten );
float3 specular = LightDiffuse * power * atten;
float3 ambient = float3(0.4f, 0.4f, 0.4f) * texDiffuse;

OUT.Color.rgb = diffuse + specular + ambient;
OUT.Color.a   = 1.0f;

This will look like crap and you will only have bump mapping and specular effect in the area lit by the point light.

 

Now that you have a global ambient component, you can replace the values that give ugly results with better one. Like in the step where we set atten to 1:

float3x3 tangentBasis = float3x3(normalize(IN.TangentW), normalize(IN.BinormalW), normalize(IN.NormalW));
	float3 n              = normalize(mul(bump.xyz, tangentBasis));

    float3 l = normalize(lightDir);
    float3 v = normalize(viewDir);
    float3 h = normalize(l + v);
    
    float nDotL = saturate(dot(n, l));
    float nDotH = saturate(dot(n, h));
    float power = pow(nDotH, MaterialPower);

	float3 diffuse  = LightDiffuse * MaterialDiffuse * texDiffuse * (nDotL * atten );
	float3 specular = LightDiffuse * power * atten;
	float3 ambient = LightDiffuse * MaterialAmbient * texDiffuse * nDotL;

	OUT.Color.rgb = diffuse + specular + ambient;
	OUT.Color.a   = 1.0f;

This will give a very dark result. The material properties are not set up correctly for these equations, especially since I changed the interpretation of the values.

 

I'm not saying that things look good, or are correct. There are a lot of ways to do what you want and first you need to decide exactly on the lighting scheme you want. For interior scenes, especially with a lot of rooms, you can use multiple point lights. Exterior scenes, especially terrain are well served by one master directional light, which does a fair job of approximating the Sun. A point light is not well suited for approximating the sun because it has a radius and the intensity of the light changes rapidly when moving in that radius. If you place the point light as a sun too far, one corner of you map will be brighter than the others. If you place it in a central position, the problem repeats. If you lower it too much, the middle of the map will be shinny while the corners will be just right.

2

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0