# OpenGL Easy OpenGL Directional Lighting Question

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

## Recommended Posts

Hey all, this should be a REALLY simple question that someone should hopefully be able to explain.

When defining directional lighting, I'm getting extremely confused by how we should define it. I realize the final coordinate, the w-coordinate, should be 0.

But suppose that up is a positive Z axis, down is a negative Z axis, and West/East are Negative/Positive X axis and South/North are Negative/Positive Y axis -- say I want a directional light to shine from the upper-west, what would my directional light look like? Would my direction vector (simplifying it, I realize I'd use cos/sin) (-1,0,1,0) or (1,0,-1,0)?

Also, are there any gotcha's with lighting when it comes to directional lighting? I saw something about having to apply the light's position AFTER pushing in all of your geometry, otherwise it doesn't translate/move correctly... In addition, when working with the fixed pipeline before, my directional lighting was off ALWAYS. I ended up having to use a spotlight and make it really wide (which worked), however I'd like to do this the correct way.

Thank you!

##### Share on other sites
[quote name='Terin' timestamp='1342492737' post='4959845']
I realize the final coordinate, the w-coordinate, should be 0.
[/quote]
This is the case, because you don't want to affect the vector by a translation, when multiplying with a transformation matrix. The transformation should only rotate the vector.

[quote name='Terin' timestamp='1342492737' post='4959845']
upper-west
[/quote]
[i](1,0,1)[/i]
Then you should define a source point, I think you want to have (0,0,0), right ?

The direction is (target-source):
[i](1,0,1) - [/i][i](0,0,0) = (1,0,1)[/i]

After that you need to normalize it, directions are often needed in unit length:
[i](1,0,1) * (1/length(1,0,1))[/i]

[quote name='Terin' timestamp='1342492737' post='4959845']
Also, are there any gotcha's with lighting when it comes to directional lighting? I saw something about having to apply the light's position AFTER pushing in all of your geometry, otherwise it doesn't translate/move correctly.
[/quote]
When you transform a vertex or vector you move it from one space (i.e. world space) into an other space (i.e. camera space aka eye view). Lighting is often done in camera space, therefore you need to transform all vectors/vertices into the same space. When transforming a model this is done automatically by the transformation matrix, when you set a direction vector for lightning you need to transform it before uploading it to the GPU, that is [i]transform * (lx,ly,lz,0)[/i] .

Edit: correction due to the comment of dpadam450. Edited by Ashaman73

##### Share on other sites
The direction in regards to lights is the direction pointing to the light. Not the direction the rays are coming.

Unless you have a modified coordinate system, openGL y-axis is up.

##### Share on other sites
[quote name='Terin' timestamp='1342492737' post='4959845']Also, are there any gotcha's with lighting when it comes to directional lighting?[/quote]From [url="http://www.opengl.org/sdk/docs/man/xhtml/glLight.xml"]http://www.opengl.or...tml/glLight.xml[/url] : When glLight* is called with the GL_POSITION argument, the "position is transformed by the modelview matrix when glLight is called (just as if it were a point), and it is stored in eye coordinates."

##### Share on other sites
Lots of good responses, thank you all.

So, let me see if I can make some sense of this. First, yes, suppose 0,0,0 is the center always of the screen. Wouldn't to the west and up (as per my prior description) be (-1,0,1)? Assuming that for whatever reason I had translated to some arbitrary point, making it the center (say, [x, y, z]), the resulting light would require the light direction to be (x -(-1), y, z - 1) => (x + 1, y, z -1), correct?

In any case, furthermore, if I were to specify the glLight's Position to -1, 0, 1 -- that wouldn't be enough, since I need to normalize it to unit length... What exactly is "unit length?" Apologies for what is most likely considered a simple question.

##### Share on other sites
[quote]Wouldn't to the west and up (as per my prior description) be (-1,0,1)[/quote]
yes

[quote]Assuming that for whatever reason I had translated to some arbitrary point, making it the center (say, [x, y, z]), the resulting light would require the light direction to be (x -(-1), y, z - 1) => (x + 1, y, z -1), correct?[/quote]
A light with w = 0, means it is directional and not effected by translation basically 0*translation is what the math comes out to be. If you want a positional light such as a lamp post then yea something like that.

I'm pretty sure the lights position is normalized if you use GL without shaders. The vector 1,0,1 is bigger than 1,0,0. If you don't know the Pythagorean theorem then thats what it is for.

##### Share on other sites
I am using GL with Shaders. Trying to get my shadow code working -- had a lot of help from a few other people, just trying to get the final pieces correct.

Good to confirm/know everything, but yeah, it looks like I need to normalize the light's direction...

After reading again (and again) -- is the length(x,y,z) supposed to be the length of the vector, ala the Pythagorean theorem, to normalize it? Then just scale each dimension of the light's direction with that length?

i.e.

(-1, 0, 1) * ( 1 / sqrt(2) ) => (-1 / sqrt(2), 0, 1/ sqrt(2)) ?

If so, I think I finally got it. Oy.

##### Share on other sites
......what shadow technique are you using. Considering you don't know what normalize means, shadowing is a bit scary to be doing. There is a function called normalize() in GLSL.

##### Share on other sites
I'm using Shadow Mapping, dropping the depth buffer, then re-applying it to the scene. Everything works perfectly, minus the light source being kind of in a funky position, which is why I'm trying to figure this part out. I do realize there's a function in GLSL for normalize -- I figured I'd probably be able to use that, but wanted to make sure I knew it in the standard pipeline as well.

I understand normalizing puts things into a specific scale/unit length, as you said, but I get very confused at the different matrices, i.e. World Matrix vs View Matrix vs ModelView. I know it seems silly, but I don't do this every day -- I do this on the side, when I have time, so I'm not always working with it and need to be reminded.

Regardless, let me try this out and see if it does what I want it to. Thank you for everyone's help so far.

##### Share on other sites
So you are most likely doing it wrong because shadow mapping does not require a vector to the sun at all, and will have nothing to do with normalizing it either.

When learning shadow mapping, try projecting an image texture instead of a depth buffer, this way you can get the math part down and then just replace the image with a depth buffer, because sometimes you will user a depth buffer that is not what you thought it was.

##### Share on other sites

Here's what I have so far.

My shader for building the depth buffer and shadows is done as follows and works correctly:

[source lang="cpp"] //Vertex
varying vec4 LightPosition;

void main()
{
gl_Position = ftransform(); // Get the actual in-scene vector position.
}

//Fragment
varying vec4 LightPosition;

void main()
{
gl_FragColor = vec4(LightPosition.z / LightPosition.w); // The color is the depth ratio.
}[/source]

This builds everything fine, and I've checked.

The actual code for the shaders that draw the scene are as follows:

[source lang="cpp"] //Vertex
uniform mat4 LightModelViewProjectionMatrix;
uniform mat4 WorldMatrix;

varying vec3 Normal;
varying vec4 LightCoordinate; // Position in model view projection space from the lights view.
varying vec4 WorldPosition; // Position in world space.

void main()
{
Normal = gl_Normal;
WorldPosition = WorldMatrix * gl_Vertex;
LightCoordinate = LightModelViewProjectionMatrix * gl_Vertex;
gl_Position = ftransform(); // Transform via fixed function into the viewer's view
gl_TexCoord[0] = gl_MultiTexCoord0;
}

//Fragment
uniform sampler2D DiffuseMap;
uniform mat4 WorldMatrix;

varying vec3 Normal;
varying vec4 LightCoordinate;
varying vec4 WorldPosition;

void main()
{
// Direct lighting
// ------------------------------
vec4 Color = gl_LightSource[0].ambient;
vec3 l = normalize(gl_LightSource[0].position.xyz - WorldPosition.xyz); // direction to the light source

vec3 view_normal = normalize(gl_NormalMatrix * Normal);
vec3 view_light_direction = normalize(vec3(gl_LightSource[0].position)); //(WorldMatrix * vec4( LightPosition.x, LightPosition.y, LightPosition.z, 0 ) ).xyz;

//float lambert = max(dot(view_normal, view_light_direction), 0.2);
float lambert = max(dot(Normal, l), MinimumShadow);
Color.xyz *= lambert;

//Blend in Color from primary texture unit
Color.wxyz *= texture2D(DiffuseMap, vec2(gl_TexCoord[0])).wxyz;

// ------------------------------
vec4 lcoord = LightCoordinate; // Fragment position in light space.
lcoord /= lcoord.w; // Project to cartesian space
lcoord.xy = lcoord.xy * 0.5 + 0.5; // Scale since light clipping space is in [-1,1] but texture space is [0,1]

float fragmentDepth = lcoord.w; // Depth of the fragment in light space.

float eps = 0.001; // depth bias

}[/source]

This appears to be where I start having the screw-ups. Everything in the scene renders right -- except for the light. The Shadow Mapping part works great at the bottom, but the top part seems to be screwing up somehow. Mind you, I realize the correct code should be the first lambert (that is commented out). However, there are no shadows in this situation.

Now, I've got the position building correctly to what I believe it should be. In fact, it's at the point where I can render from the Light's viewpoint and it shows how I expect it to.

[source lang="csharp"] Single LightX = (Single)( Math.Cos( Radians ) );
Single LightY = 0.0f;
Single LightZ = (Single)( Math.Sin( Radians ) );
Double LightAngle = Radians / Math.PI * 180.0d;

Single[] LightDirection = new Single[] { LightX, LightY, LightZ, 0.0f };
Gl.glLightfv( Gl.GL_LIGHT0, Gl.GL_POSITION, LightDirection );[/source]

Does anything appear to be outwardly wrong?

##### Share on other sites
So what I would suggest again, is instead of binding the shadow texture, Bind an image of a tree or anything and see if you can see any of the image at all noticeable.

[quote]The Shadow Mapping part works great at the bottom, but the top part seems to be screwing up somehow.[/quote]
So you have shadows but not lighting? Post a pic.

You mentioned you have a 0 for the w coordinate but you are subtracting light position from world position as if it is a point light.

##### Share on other sites
This current code actually renders the shadows and light (but the light is incorrect).

Here's what that looks like:

That is the problem I have with that code. When I do it with the other stuff that's commented out, I have flat shading with no shadows. It's as if I had just put a film over the screen and changed the color of it to darken the entire scene.

EDIT:

Just want to note that I changed the discussion of this and posted to a different topic (since this is no longer an accurate title and is a completely different issue altogether) : http://www.gamedev.net/topic/628307-help-with-shadow-mapping-and-multi-texturing/ Edited by Terin

• 9
• 11
• 9
• 16
• 18
• ### Similar Content

• i got error 1282 in my code.
#version 450 core layout(location=0) in vec3 inPos; layout(location=1) in vec2 inTexCoord; out vec2 TexCoord; void main() { gl_Position=vec4(inPos,1.0); TexCoord=inTexCoord; } and the fragment shader
#version 450 core in vec2 TexCoord; uniform sampler2D inTextureOne; uniform sampler2D inTextureTwo; out vec4 FragmentColor; void main() { FragmentColor=mix(texture(inTextureOne,TexCoord),texture(inTextureTwo,TexCoord),0.2); } I was expecting awesomeface.png on top of container.jpg

• By khawk
We've just released all of the source code for the NeHe OpenGL lessons on our Github page at https://github.com/gamedev-net/nehe-opengl. code - 43 total platforms, configurations, and languages are included.
Now operated by GameDev.net, NeHe is located at http://nehe.gamedev.net where it has been a valuable resource for developers wanting to learn OpenGL and graphics programming.

View full story
• By TheChubu
The Khronos™ Group, an open consortium of leading hardware and software companies, announces from the SIGGRAPH 2017 Conference the immediate public availability of the OpenGL® 4.6 specification. OpenGL 4.6 integrates the functionality of numerous ARB and EXT extensions created by Khronos members AMD, Intel, and NVIDIA into core, including the capability to ingest SPIR-V™ shaders.
SPIR-V is a Khronos-defined standard intermediate language for parallel compute and graphics, which enables content creators to simplify their shader authoring and management pipelines while providing significant source shading language flexibility. OpenGL 4.6 adds support for ingesting SPIR-V shaders to the core specification, guaranteeing that SPIR-V shaders will be widely supported by OpenGL implementations.
OpenGL 4.6 adds the functionality of these ARB extensions to OpenGL’s core specification:
GL_ARB_gl_spirv and GL_ARB_spirv_extensions to standardize SPIR-V support for OpenGL GL_ARB_indirect_parameters and GL_ARB_shader_draw_parameters for reducing the CPU overhead associated with rendering batches of geometry GL_ARB_pipeline_statistics_query and GL_ARB_transform_feedback_overflow_querystandardize OpenGL support for features available in Direct3D GL_ARB_texture_filter_anisotropic (based on GL_EXT_texture_filter_anisotropic) brings previously IP encumbered functionality into OpenGL to improve the visual quality of textured scenes GL_ARB_polygon_offset_clamp (based on GL_EXT_polygon_offset_clamp) suppresses a common visual artifact known as a “light leak” associated with rendering shadows GL_ARB_shader_atomic_counter_ops and GL_ARB_shader_group_vote add shader intrinsics supported by all desktop vendors to improve functionality and performance GL_KHR_no_error reduces driver overhead by allowing the application to indicate that it expects error-free operation so errors need not be generated In addition to the above features being added to OpenGL 4.6, the following are being released as extensions:
GL_KHR_parallel_shader_compile allows applications to launch multiple shader compile threads to improve shader compile throughput WGL_ARB_create_context_no_error and GXL_ARB_create_context_no_error allow no error contexts to be created with WGL or GLX that support the GL_KHR_no_error extension “I’m proud to announce OpenGL 4.6 as the most feature-rich version of OpenGL yet. We've brought together the most popular, widely-supported extensions into a new core specification to give OpenGL developers and end users an improved baseline feature set. This includes resolving previous intellectual property roadblocks to bringing anisotropic texture filtering and polygon offset clamping into the core specification to enable widespread implementation and usage,” said Piers Daniell, chair of the OpenGL Working Group at Khronos. “The OpenGL working group will continue to respond to market needs and work with GPU vendors to ensure OpenGL remains a viable and evolving graphics API for all its customers and users across many vital industries.“
The OpenGL 4.6 specification can be found at https://khronos.org/registry/OpenGL/index_gl.php. The GLSL to SPIR-V compiler glslang has been updated with GLSL 4.60 support, and can be found at https://github.com/KhronosGroup/glslang.
Sophisticated graphics applications will also benefit from a set of newly released extensions for both OpenGL and OpenGL ES to enable interoperability with Vulkan and Direct3D. These extensions are named:
GL_EXT_memory_object GL_EXT_memory_object_fd GL_EXT_memory_object_win32 GL_EXT_semaphore GL_EXT_semaphore_fd GL_EXT_semaphore_win32 GL_EXT_win32_keyed_mutex They can be found at: https://khronos.org/registry/OpenGL/index_gl.php
Industry Support for OpenGL 4.6
“With OpenGL 4.6 our customers have an improved set of core features available on our full range of OpenGL 4.x capable GPUs. These features provide improved rendering quality, performance and functionality. As the graphics industry’s most popular API, we fully support OpenGL and will continue to work closely with the Khronos Group on the development of new OpenGL specifications and extensions for our customers. NVIDIA has released beta OpenGL 4.6 drivers today at https://developer.nvidia.com/opengl-driver so developers can use these new features right away,” said Bob Pette, vice president, Professional Graphics at NVIDIA.
"OpenGL 4.6 will be the first OpenGL release where conformant open source implementations based on the Mesa project will be deliverable in a reasonable timeframe after release. The open sourcing of the OpenGL conformance test suite and ongoing work between Khronos and X.org will also allow for non-vendor led open source implementations to achieve conformance in the near future," said David Airlie, senior principal engineer at Red Hat, and developer on Mesa/X.org projects.

View full story
• By _OskaR
Hi,
I have an OpenGL application but without possibility to wite own shaders.
I need to perform small VS modification - is possible to do it in an alternative way? Do we have apps or driver modifictions which will catch the shader sent to GPU and override it?
• By xhcao
Does sync be needed to read texture content after access texture image in compute shader?
My simple code is as below,
glUseProgram(program.get());
glBindImageTexture(0, texture[0], 0, GL_FALSE, 3, GL_READ_ONLY, GL_R32UI);
glBindImageTexture(1, texture[1], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
glDispatchCompute(1, 1, 1);
// Does sync be needed here?
glUseProgram(0);