GLSL gl_LightSource point/directional/spot differentiation

半世苍凉 提交于 2020-01-24 20:17:06

问题


I am writing a GLSL program as part of a plugin that runs inside of Maya, a closed-source 3D application. My plugin renders custom geometry into the same image buffer that the application renders it's default polygonal geometry. The application uses the OpenGL fixed pipeline for it's lighting and shading but I am using GLSL to render custom geometry and materials.

My problem is, I want to mimic the behavior of the fixed pipeline lights in my shader. The application defines the lights in the gl_LightSource uniform and I want them to have the same direction, intensity etc when assigned to my custom geometry that they have when assigned to the application's default polygonal geometry.

The gl_LightSource fields are clearly documented but I cannot find definitive documentation of how the fixed-pipeline interprets those fields. There are many examples of how to code point/directional/spot lights in GLSL but they do not seem to exactly mimic the fixed pipeline. For example, how do you determine if a light is a point, directional or spot light if the application defines a mix of them? Can a mix of light types be handled without introducing excessive branching in my shader?

In short, is there any definitive documentation or example of how the fixed function pipeline evaluates gl_LightSource?


回答1:


My problem is, I want to mimic the behavior of the fixed pipeline lights in my fragment shader.

Well there's your first problem, because the "fixed pipeline lights" are implemented in the vertex processor, not per-fragment.

In short, is there any definitive documentation or example of how the fixed function pipeline evaluates gl_LightSource?

Yes. It's called "The OpenGL Graphics System: A Specification." It's available for download on the OpenGL Registry; you want the compatibility profile. Section 2.13 of the 4.2 compatibility specification covers all of the math used for lighting. Simply translate that into GLSL code.

Note that you're not going to be able to exactly mimic the fixed-function pipeline. That is, there is no way to guarantee invariance between shader-based and fixed-function lighting.You'll get something close, but not binary-identical values.

Can a mix of light types be handled without introducing excessive branching in my shader?

How do you define "excessive"? You're going to need to branch, because OpenGL's lighting equations involve conditional logic.

That's generally part of the reason why people don't just re-implement GL's lighting in a shader. You can be much more efficient if you just write GLSL, rather than using a data-driven approach.




回答2:


There is a full source codes of vertex shader that implements of the fixed function pipeline in OpenGL ES 2.0 Programming Guide. (Note that the fixed function pipeline is only per-vertex lighting, so, fragment shader is not needed for lighting calculation.)

I believe OpenGL driver uses this vertex shader internally when it is in fixed function mode. Please check the chapter 8, Vertex Shaders of this book.

It defines a struct of a light with the following properties;

  1. Position,
  2. Ambient Color,
  3. Diffuse Color,
  4. Specular Color,
  5. Spot Direction,
  6. Attenuation Factors (constant, linear, quaratic),
  7. Spot Exponent,
  8. Spot Cutoff Angle,
  9. ComputeDistanceAttanuation (bool)

and, each light is processed in the function, lighting_equation().




回答3:


Here is what I came up with based on the OpenGL Specification document:

#version 410 compatibility

vec3 incedentLight (in gl_LightSourceParameters light, in vec3 position)
{
    if (light.position.w == 0) {
        return normalize (-light.position.xyz);
    } else {
        vec3 offset = position - light.position.xyz;
        float distance = length (offset);
        vec3 direction = normalize (offset);
        float intensity;
        if (light.spotCutoff <= 90.) {
            float spotCos = dot (direction, normalize (light.spotDirection));
            intensity = pow (spotCos, light.spotExponent) *
                    step (light.spotCosCutoff, spotCos);
        } else {
            intensity = 1.;
        }
        intensity /= light.constantAttenuation +
                light.linearAttenuation * distance +
                light.quadraticAttenuation * distance * distance;
        return intensity * direction;
    }
}

From what I understand about GLSL the branching should be reasonably efficient because it only depends on uniform variables.



来源:https://stackoverflow.com/questions/11212933/glsl-gl-lightsource-point-directional-spot-differentiation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!