I have a particle system in a cylinder shape. How can I "light" half of it and have it smoothly transition to the darker color while having control over the max brightness of the light color?
This does what I want, but when I change the radius of the cylinder, the lightest color of the lighter side gets lighter because the particle position is getting further away from 0..
varying vec3 fpDL; <-- incoming particle position
vec3 objPos = vec3(0.0, 0.0, 0.0);
float fragLS = objPos.x + fpDL.x;
vec3 pColor = vec3(0.3, 0.3, 0.3);
float lightStrength = 0.001;
vec3 result = pColor * fragLS * lightStrength;
gl_FragColor = vec4(result, opacity);
I'm obviously missing some factors to this equation..
I figured out a way to do what I asked..
varying vec3 fpDL; <-- incoming particle position
vec3 pColor = vec3(0.3, 0.3, 0.3);
vec3 lColor = vec3(0.6, 0.6, 0.6);
float lStrength = 1.0;
vec3 objPos = vec3(0.0, fpDL.y, 0.0);
vec3 fragDir = normalize(fpDL - objPos);
vec3 dirLight = clamp(fragDir * lStrength, 0.0, lStrength) ;
vec3 result = pColor + (dirLight.x * lColor);
gl_FragColor = vec4(result, opacity);
Related
In the code below I am trying to implement a fragment shader program for Phong:
// Inputs from application.
// Generally, "in" like the position and normal vectors for things that change frequently,
// and "uniform" for things that change less often (think scene versus vertices).
in vec3 position_cam, normal_cam;
uniform mat4 view_mat;
// This light setup would usually be passed in from the application.
vec3 light_position_world = vec3 (10.0, 25.0, 10.0);
vec3 Ls = vec3 (1.0, 1.0, 1.0); // neutral, full specular color of light
vec3 Ld = vec3 (0.8, 0.8, 0.8); // neutral, lessened diffuse light color of light
vec3 La = vec3 (0.12, 0.12, 0.12); // ambient color of light - just a bit more than dk gray bg
// Surface reflectance properties for Phong model below.
vec3 Ks = vec3 (1.0, 1.0, 1.0); // fully reflect specular light
vec3 Kd = vec3 (0.32, 0.18, 0.5); // purple diffuse surface reflectance
vec3 Ka = vec3 (1.0, 1.0, 1.0); // fully reflect ambient light
float specular_exponent = 400.0; // specular 'power' -- controls "roll-off"
// Shader programs can also designate outputs.
out vec4 fragment_color; // color of surface to draw in this case
void main ()
{
fragment_color = vec4 (Kd, 1.0);
}
I have two questions:
How do I add 2 additional directional light sources to my code? Do I simply add more vec3 Ld variables to my light setup or is there something else I must do?
How do I set the Phong exponent high enough to produce sharp and bright highlights?
In glsl you can use arrays and structures. Define an array of light sources. See Array constructors and Struct constructors:
const int no_of_lights = 2;
struct TLightSource
{
vec3 lightPos;
vec3 Ls;
vec3 Ld;
vec3 La;
float shininess;
};
TLightSource lightSources[no_of_lights] = TLightSource[no_of_lights](
TLightSource(vec3(10.0, 25.0, 10.0), vec3(1.0, 1.0, 1.0), vec3(0.8, 0.8, 0.8), vec3(0.12, 0.12, 0.12), 10.0),
TLightSource(vec3(-10.0, 25.0, 10.0), vec3(1.0, 0.0, 0.0), vec3(0.8, 0.0, 0.0), vec3(0.12, 0.0, 0.0), 10.0)
);
User a for loop to iterate through the light sources and sum up the light color for ambient, diffuse and specular light (e.g Phong reflection model):
void main()
{
vec3 normalInterp;
vec3 vertPos;
vec3 normal = normalize(normalInterp);
vec3 color = vec3(0.0);
for (int i=0; i < no_of_lights; i++)
{
color += Ka * lightSources[i].La;
vec3 lightDir = normalize(lightSources[i].lightPos - vertPos);
float lambertian = max(dot(lightDir, normal), 0.0);
color += lambertian * lightSources[i].Ld;
if (lambertian > 0.0)
{
vec3 viewDir = normalize(-vertPos);
vec3 reflectDir = reflect(-lightDir, normal);
float RdotV = max(dot(reflectDir, viewDir), 0.0);
float specular = pow(RdotV, lightSources[i].shininess/4.0);
color += specular * lightSources[i].Ls;
}
}
frag_color = vec4(color, 1.0);
}
So I am currently working on trying to create a spotlight in my vertex shader, currently I can produce directional and/or point light by using the Phong lighting model.
Im finding it hard to calculate the correct angles for the spotlight, basically just want a spotlight that comes from 0,0,0 in eye space and looks down the Z co-ord.
I am trying to just make everything (for now) in the cone to be bright white and everything outside it dark
#version 130
uniform mat4 model_view_matrix;
uniform mat4 projection_matrix;
uniform mat3 normal_matrix;
uniform int light_mode;
uniform vec4 light_pos;
uniform vec3 light_ambient;
uniform vec3 light_diffuse;
uniform vec3 light_specular;
uniform vec3 mtl_ambient;
uniform vec3 mtl_diffuse;
uniform vec3 mtl_specular;
uniform float mtl_shininess;
// Spotlight test
const float spotCutOff = 100.00f;
in vec3 position;
in vec3 normal;
in vec2 texCoord;
out vec2 st;
out vec4 litColour;
vec3 phongLight(in vec4 position, in vec3 norm)
{
// s is the direction from the light to the vertex
vec3 s;
if (light_pos.w == 0.0) {
s = normalize(light_pos.xyz);
}
else {
s = normalize(vec3(light_pos - position));
}
// v is the direction from the eye to the vertex
vec3 v = normalize(-position.xyz);
// r is the direction of light reflected from the vertex
vec3 r = reflect(-s, norm);
vec3 ambient = light_ambient * mtl_ambient;
// The diffuse component
float sDotN = max(dot(s,norm), 0.0);
vec3 diffuse = light_diffuse * mtl_diffuse * sDotN;
// Specular component
vec3 spec = vec3(0.0);
if (sDotN > 0.0)
spec = light_specular * mtl_specular * pow(max(dot(r,v), 0.0), mtl_shininess);
return ambient + diffuse + spec;
}
vec3 spotLight(in vec4 position, in vec3 norm)
{
vec3 ambient = vec3(0.2, 0.2, 0.2);
vec3 lightDir = normalize(vec3(light_pos - position));
vec3 spotDir = vec3(0.0, 0.0, -1.0);
float angle = degrees(acos(dot(spotDir, lightDir)));
//angle = max (angle, 0);
if ((angle) < spotCutOff) {
return vec3(1.0, 1.0, 1.0);
}
float dist = sqrt(positon.x * position.x + position.y + position.y + position.z * position.z);
if (dist < 1) {
return vec3(1.0,1.0,0.0);
}
return vec3(0.2, 0.2, 0.2);
}
void main(void)
{
// Convert normal and position to eye coords
vec3 eyeNorm = normalize(normal_matrix * normal);
vec4 eyePos = model_view_matrix * vec4(position, 1.0);
// No lighting effect
if (light_mode == 0)
{
litColour = vec4(1.0, 1.0, 1.0, 1.0);
}
// Directional overhead light
else if (light_mode == 1)
{
litColour = vec4(phongLight(eyePos, eyeNorm), 1.0);
}
// Point light
else if (light_mode == 2)
{
litColour = vec4(phongLight(eyePos, eyeNorm), 1.0);
}
else if (light_mode == 3)
{
litColour = vec4(spotLight(eyePos, eyeNorm), 1.0);
}
//litColour = vec4(normal*1000, 1.0);
gl_Position = projection_matrix * eyePos;
st = texCoord;
}
Your spotlight is defined by a position (ps) and a direction (ds). So for every vertex at position vp you can compute d=vp-ps, normalize that to dn=normalize(d), and then dot(dn,ds) will give you the angle in the spotlight. Just scale it or compare it to a cut off to get a scalar!
Alternatively, and in the long term better, is to think of a spotlight as a camera. Do the same as you do for your camera: A model and view matrix! Transform every vertex into that space, and project it from x,y,z,w to x,y,z. z is the distance which is always useful for lighting and x,y you can use to look up in a texture that has a round shape (or any other).
One thing to mind with both techniques is back projection: Make sure you check that the light only points forward! Check the sign of z or the dot product!
I found a good example of environment mapping equirectangular. Here's the code:
VERTEX SHADER
varying vec3 Normal;
varying vec3 EyeDir;
varying float LightIntensity;
uniform vec3 LightPos;
void main(void){
gl_Position = ftransform();
Normal = normalize(gl_NormalMatrix * gl_Normal);
vec4 pos = gl_ModelViewMatrix * gl_Vertex;
EyeDir = pos.xyz;
LightIntensity = max(dot(normalize(LightPos - EyeDir), Normal), 0.0);
}
FRAGMENT SHADER
const vec3 Xunitvec = vec3 (1.0, 0.0, 0.0);
const vec3 Yunitvec = vec3 (0.0, 1.0, 0.0);
uniform vec3 BaseColor;
uniform float MixRatio;
uniform sampler2D EnvMap;
varying vec3 Normal;
varying vec3 EyeDir;
varying float LightIntensity;
void main (void){
// Compute reflection vector
vec3 reflectDir = reflect(EyeDir, Normal);
// Compute altitude and azimuth angles
vec2 index;
index.y = dot(normalize(reflectDir), Yunitvec);
reflectDir.y = 0.0;
index.x = dot(normalize(reflectDir), Xunitvec) * 0.5;
// Translate index values into proper range
if (reflectDir.z >= 0.0)
index = (index + 1.0) * 0.5;
else
{
index.t = (index.t + 1.0) * 0.5;
index.s = (-index.s) * 0.5 + 1.0;
}
// if reflectDir.z >= 0.0, s will go from 0.25 to 0.75
// if reflectDir.z < 0.0, s will go from 0.75 to 1.25, and
// that's OK, because we've set the texture to wrap.
// Do a lookup into the environment map.
vec3 envColor = vec3 (texture2D(EnvMap, index));
// Add lighting to base color and mix
vec3 base = LightIntensity * BaseColor;
envColor = mix(envColor, base, MixRatio);
gl_FragColor = vec4 (envColor, 1.0);
}
My problem is in the vertex shader.
LightIntensity = max(dot(normalize(LightPos - EyeDir), Normal), 0.0);
I'm subtracting the eye direction to the direction of light. But if I have more than one light source ... What I should do the calculation?
I use version 1.2 of GLSL.
Light is additive, so you just need to sum up the contributions of each light. If you have a fixed number of them, you can do that in a single pass through the shader—you just define a uniform for each light (position to start with, though you’ll probably want intensity/color as well) and calculate the final intensity like this:
LightIntensity = max(dot(normalize(Light1Pos - EyeDir), Normal), 0.0) + max(dot(normalize(Light2Pos - EyeDir), Normal), 0.0) + max(dot(normalize(Light3Pos - EyeDir), Normal), 0.0);
I'm trying to do point source directional lighting in OpenGL using my textbooks examples. I'm showing a rectangle centered at the origin, and doing the lighting computations in the shader. The rectangle appears, but it is black even when I try to put colored lights on it. Normals for the rectangle are all (0, 1.0, 0). I'm not doing any non-uniform scaling, so the regular model view matrix should also transform the normals.
I have code that sets the light parameters(as uniforms) and material parameters(also as uniforms) for the shader. There is no per vertex color information.
void InitMaterial()
{
color material_ambient = color(1.0, 0.0, 1.0);
color material_diffuse = color(1.0, 0.8, 0.0);
color material_specular = color(1.0, 0.8, 0.0);
float material_shininess = 100.0;
// set uniforms for current program
glUniform3fv(glGetUniformLocation(Programs[lightingType], "materialAmbient"), 1, material_ambient);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "materialDiffuse"), 1, material_diffuse);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "materialSpecular"), 1, material_specular);
glUniform1f(glGetUniformLocation(Programs[lightingType], "shininess"), material_shininess);
}
For the lights:
void InitLight()
{
// need light direction and light position
point4 light_position = point4(0.0, 0.0, -1.0, 0.0);
color light_ambient = color(0.2, 0.2, 0.2);
color light_diffuse = color(1.0, 1.0, 1.0);
color light_specular = color(1.0, 1.0, 1.0);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightPosition"), 1, light_position);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightAmbient"), 1, light_ambient);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightDiffuse"), 1, light_diffuse);
glUniform3fv(glGetUniformLocation(Programs[lightingType], "lightSpecular"), 1, light_specular);
}
The fragment shader is a simple pass through shader that sets the color to the one input from the vertex shader. Here is the vertex shader :
#version 150
in vec4 vPosition;
in vec3 vNormal;
out vec4 color;
uniform vec4 materialAmbient, materialDiffuse, materialSpecular;
uniform vec4 lightAmbient, lightDiffuse, lightSpecular;
uniform float shininess;
uniform mat4 modelView;
uniform vec4 lightPosition;
uniform mat4 projection;
void main()
{
// Transform vertex position into eye coordinates
vec3 pos = (modelView * vPosition).xyz;
vec3 L = normalize(lightPosition.xyz - pos);
vec3 E = normalize(-pos);
vec3 H = normalize(L + E);
// Transform vertex normal into eye coordinates
vec3 N = normalize(modelView * vec4(vNormal, 0.0)).xyz;
// Compute terms in the illumination equation
vec4 ambient = materialAmbient * lightAmbient;
float Kd = max(dot(L, N), 0.0);
vec4 diffuse = Kd * materialDiffuse * lightDiffuse;
float Ks = pow(max(dot(N, H), 0.0), shininess);
vec4 specular = Ks * materialSpecular * lightSpecular;
if(dot(L, N) < 0.0) specular = vec4(0.0, 0.0, 0.0, 1.0);
gl_Position = projection * modelView * vPosition;
color = ambient + diffuse + specular;
color.a = 1.0;
}
Ok, it's working now. The solution was to replace glUniform3fv with glUniform4fv, I guess because the glsl counterpart is a vec4 instead of a vec3. I thought that it would be able to recognize this and simply add a 1.0 to the end, but no.
i have been trying to implement deferred rendering for past 2 weeks. I have finally come to the spot lighting pass part using stencil buffer and linearized depth. I hold 3 framebuffer textures : albedo, normal+depth (X,Y,Z,EyeViewLinearDepth), Lighting texture. So I draw my light (sphere) and apply this fragment shader :
void main(void)
{
vec2 texCoord = gl_FragCoord.xy * u_inverseScreenSize.xy;
float linearDepth = texture2D(u_normalDepth, texCoord.st).a;
// vector to far plane
vec3 viewRay = vec3(v_vertex.xy * (-farClip/v_vertex.z), -farClip);
// scale viewRay by linear depth to get view space position
vec3 vertex = viewRay * linearDepth;
vec3 normal = texture2D(u_normalDepth, texCoord.st).xyz*2.0 - 1.0;
vec4 ambient = vec4(0.0, 0.0, 0.0, 1.0);
vec4 diffuse = vec4(0.0, 0.0, 0.0, 1.0);
vec4 specular = vec4(0.0, 0.0, 0.0, 1.0);
vec3 lightDir = lightpos - vertex ;
vec3 R = normalize(reflect(lightDir, normal));
vec3 V = normalize(vertex);
float lambert = max(dot(normal, normalize(lightDir)), 0.0);
if (lambert > 0.0) {
float distance = length(lightDir);
if (distance <= u_lightRadius) {
//CLASSICAL LIGHTING COMPUTATION PART
}
}
vec4 final_color = vec4(ambient + diffuse + specular);
gl_FragColor = vec4(final_color.xyz, 1.0);
}
The variables you need to know : v_vertex is eye space position of the vertex (of sphere), lightpos is the position/center of the light in eye space, linearDepth is generated on geometry pass stage in eye space.
The problem is that, the code fail this if check : if (distance <= u_lightRadius). The light is never computed until i remove the distance check. I am sure that i pass these values correctly, radius is 170.0, light position is only like 40-50 units away from the model. There is definitely something wrong but i can't find it somehow. I tried many possibilities of radius and other variables.