I want to have two light sources: a directional one and a spotlight. I cannot seem to get what I am doing wrong -- probably not understanding how shaders work! I get the first light fine but no sign of the effects of the second one (aka spotlight). Here is the fragement shader that I came up with:
varying vec4 diffuse,ambientGlobal, ambient;
varying vec3 normal,lightDir,halfVector;
varying float dist;
void main()
{
vec3 n, halfV, viewV, ldir;
float NdotL, NdotHV;
vec4 color = ambientGlobal;
float att, spotEffect;
n = normalize(normal);
NdotL = max(dot(n,normalize(lightDir)),0.0);
if (NdotL > 0.0) {
att = 1.0 / (gl_LightSource[0].constantAttenuation +
gl_LightSource[0].linearAttenuation * dist +
gl_LightSource[0].quadraticAttenuation * dist * dist);
color += att * (diffuse * NdotL + ambient);
halfV = normalize(halfVector);
NdotHV = max(dot(n,halfV),0.0);
color += att * gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV,gl_FrontMaterial.shininess);
spotEffect = dot(normalize(gl_LightSource[1].spotDirection), normalize(-lightDir));
if (spotEffect > gl_LightSource[1].spotCosCutoff) {
spotEffect = pow(spotEffect, gl_LightSource[1].spotExponent);
att = spotEffect / (gl_LightSource[1].constantAttenuation +
gl_LightSource[1].linearAttenuation * dist +
gl_LightSource[1].quadraticAttenuation * dist * dist);
color += att * (diffuse * NdotL + ambient);
halfV = normalize(halfVector);
NdotHV = max(dot(n,halfV),0.0);
color += att * gl_FrontMaterial.specular * gl_LightSource[1].specular * pow(NdotHV,gl_FrontMaterial.shininess);
}
}
gl_FragColor = color;
}
PS: Surely this is a problem that has been solved.... Anyone?
Here is what I came up with:
The vertex shader:
varying vec3 N;
varying vec3 v;
void main(void)
{
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
And the fragment shader:
varying vec3 N;
varying vec3 v;
#define MAX_LIGHTS 2
void main (void)
{
vec4 finalColour;
for (int i=0; i<MAX_LIGHTS; i++)
{
vec3 L = normalize(gl_LightSource[i].position.xyz - v);
vec3 E = normalize(-v);
vec3 R = normalize(-reflect(L,N));
vec4 Iamb = gl_FrontLightProduct[i].ambient;
vec4 Idiff = gl_FrontLightProduct[i].diffuse * max(dot(N,L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0);
vec4 Ispec = gl_FrontLightProduct[i].specular
* pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
Ispec = clamp(Ispec, 0.0, 1.0);
finalColour += Iamb + Idiff + Ispec;
}
gl_FragColor = gl_FrontLightModelProduct.sceneColor + finalColour;
}
Which give this image:
Related
I want to create a similar background with a shader to these images:
:
These are just blurred blobs with colors, distributed across the whole page:
Here's my current progress: https://codesandbox.io/s/lucid-bas-wvlzl9?file=/src/components/Background/Background.tsx
Vertex shader:
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
Fragment shader:
precision highp float;
uniform float uTime;
uniform float uAmplitude;
uniform float uFrequency;
varying vec2 vUv;
uniform vec2 uResolution;
vec4 Sphere(vec2 position, float radius)
{
// float dist = radius / distance(vUv, position);
// float strength = 0.01 / distance(vUv, position);
float strength = 0.1 / distance(vec2(vUv.x, (vUv.y - 0.5) * 8. + 0.5), vec2(0.));
return vec4(strength * strength);
}
void main()
{
vec2 uv = vUv;
vec4 pixel = vec4(0.0, 0.0, 0.0, 0.0);
vec2 positions[4];
positions[0] = vec2(.5, .5);
// positions[1] = vec2(sin(uTime * 3.0) * 0.5, (cos(uTime * 1.3) * 0.6) + vUv.y);
// positions[2] = vec2(sin(uTime * 2.1) * 0.1, (cos(uTime * 1.9) * 0.8) + vUv.y);
// positions[3] = vec2(sin(uTime * 1.1) * 1.1, (cos(uTime * 2.6) * 0.7) + vUv.y);
for (int i = 0; i < 2; i++)
pixel += Sphere(positions[i], 0.22);
pixel = pixel * pixel;
gl_FragColor = pixel;
}
For each blob, you can multiply it's color by a a noise function and then a 2D gaussian curve centered in a random point. Then add all the blobs together. I only added the ones of the adjacent cells to make it scrollable and the numbers in the for loops might be increased for bigger blobs.
here is my code :
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
const float blobSize = 0.125;
const float cellSize = .75;
const float noiseScale = .375;
const float background = .125;
const float blobsLuminosity = .75;
const float blobsSaturation = .5;
vec2 random2(vec2 st){
st = vec2( dot(st,vec2(127.1,311.7)),
dot(st,vec2(269.5,183.3)) );
return -1.0 + 2.0*fract(sin(st)*43758.5453123);
}
// Gradient Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/XdXGW8
float noise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
vec2 u = f*f*(3.0-2.0*f);
return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ),
dot( random2(i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x),
mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ),
dot( random2(i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y)*.5+.5;
}
float gaussFunction(vec2 st, vec2 p, float r) {
return exp(-dot(st-p, st-p)/2./r/r);
}
// Function from IƱigo Quiles
// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix( vec3(1.0), rgb, c.y);
}
vec3 hash32(vec2 p)
{
vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
p3 += dot(p3, p3.yxz+33.33);
return fract((p3.xxy+p3.yzz)*p3.zyx);
}
vec3 blobs(vec2 st){
vec2 i = floor(st/cellSize);
vec3 c = vec3(0.);
for(int x = -1; x <= 1; x++)
for(int y = -1; y <= 1; y++){
vec3 h = hash32(i+vec2(x, y));
c += hsb2rgb(vec3(h.z, blobsSaturation, blobsLuminosity)) * gaussFunction(st/cellSize, i + vec2(x, y) + h.xy, blobSize) * smoothstep(0., 1., noise(noiseScale*st/cellSize / blobSize));
//c += hsb2rgb(vec3(h.z, blobsSaturation, blobsLuminosity)) * gaussFunction(st/cellSize, i + vec2(x, y) + h.xy, blobSize) * noise(noiseScale*st/cellSize / blobSize);
}
return c + vec3(background);
}
float map(float x, float a, float b, float c, float d){
return (x-a)/(b-a)*(d-c)+c;
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;
vec3 color = vec3(0.0);
color = vec3(blobs(st - u_mouse/u_resolution.xy*4.));
gl_FragColor = vec4(color,1.0);
}
made in this shader editor.
When I implemented SSR I encountered the problem of artifacts. Below I present the code and screenshots.
Fragment SSR shader:
#version 330 core
uniform sampler2D normalMap; // in view space
uniform sampler2D colorMap;
uniform sampler2D reflectionStrengthMap;
uniform sampler2D positionMap; // in view space
uniform mat4 projection;
uniform vec3 skyColor = vec3(0.1, 0, 0.5);
in vec2 texCoord;
layout (location = 0) out vec4 fragColor;
const int binarySearchCount = 10;
const int rayMarchCount = 30;
const float step = 0.05;
const float LLimiter = 0.2;
const float minRayStep = 0.2;
vec3 getPosition(in vec2 texCoord) {
return texture(positionMap, texCoord).xyz;
}
vec2 binarySearch(inout vec3 dir, inout vec3 hitCoord, inout float dDepth) {
float depth;
vec4 projectedCoord;
for(int i = 0; i < binarySearchCount; i++) {
projectedCoord = projection * vec4(hitCoord, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
depth = getPosition(projectedCoord.xy).z;
dDepth = hitCoord.z - depth;
dir *= 0.5;
if(dDepth > 0.0)
hitCoord += dir;
else
hitCoord -= dir;
}
projectedCoord = projection * vec4(hitCoord, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
return vec2(projectedCoord.xy);
}
vec2 rayCast(vec3 dir, inout vec3 hitCoord, out float dDepth) {
dir *= step;
for (int i = 0; i < rayMarchCount; i++) {
hitCoord += dir;
vec4 projectedCoord = projection * vec4(hitCoord, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
float depth = getPosition(projectedCoord.xy).z;
dDepth = hitCoord.z - depth;
if((dir.z - dDepth) < 1.2 && dDepth <= 0.0) return binarySearch(dir, hitCoord, dDepth);
}
return vec2(-1.0);
}
void main() {
float reflectionStrength = texture(reflectionStrengthMap, texCoord).r;
if (reflectionStrength == 0) {
fragColor = texture(colorMap, texCoord);
return;
}
vec3 normal = texture(normalMap, texCoord).xyz;
vec3 viewPos = getPosition(texCoord);
// Reflection vector
vec3 reflected = normalize(reflect(normalize(viewPos), normalize(normal)));
// Ray cast
vec3 hitPos = viewPos;
float dDepth;
vec2 coords = rayCast(reflected * max(-viewPos.z, minRayStep), hitPos, dDepth);
float L = length(getPosition(coords) - viewPos);
L = clamp(L * LLimiter, 0, 1);
float error = 1 - L;
vec3 color = texture(colorMap, coords.xy).rgb * error;
if (coords.xy != vec2(-1.0)) {
fragColor = mix(texture(colorMap, texCoord), vec4(color, 1.0), reflectionStrength);
return;
}
fragColor = mix(texture(colorMap, texCoord), vec4(skyColor, 1.0), reflectionStrength);
}
Result without blackout (without * error):
Result with blackout:
Note: blue is filled specifically to see artifacts
And one more question, what is the best way to add fresnel without harming scene?
the problem is that i pass few lights to the shader but it showing shadow only for the first one.
the lighting applied also for the lights that their shadows are not seen.
i checked the shadow maps and they being passed correctly.
the fragment shader:
#version 420 compatibility
#define MAX_LIGHTS 8
struct lightSource
{
vec4 position;
vec4 diffuse;
vec4 specular;
float constantAttenuation, linearAttenuation, quadraticAttenuation;
float spotCutoff, spotExponent, intensity;
vec3 spotDirection;
sampler2D TexShadow;
samplerCube TexShadowPoint;
};
struct material
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
uniform material frontMaterial;
uniform lightSource lights[MAX_LIGHTS];
uniform int numberOfLights;
uniform vec4 scene_ambient;
uniform mat4 inversedViewMatrix;
uniform sampler2D Tex;
uniform sampler2D TexNorm;
in vec4 position; // position of the vertex (and fragment) in world space
in vec3 varyingNormalDirection; // surface normal vector in world space
in vec2 ex_UV;
in vec4 ShadowCoords[MAX_LIGHTS];
vec2 poissonDisk[16] = vec2[](
vec2( -0.94201624, -0.39906216 ), vec2( 0.94558609, -0.76890725 ),
vec2( -0.094184101, -0.92938870 ), vec2( 0.34495938, 0.29387760 ),
vec2( -0.91588581, 0.45771432 ), vec2( -0.81544232, -0.87912464 ),
vec2( -0.38277543, 0.27676845 ), vec2( 0.97484398, 0.75648379 ),
vec2( 0.44323325, -0.97511554 ), vec2( 0.53742981, -0.47373420 ),
vec2( -0.26496911, -0.41893023 ), vec2( 0.79197514, 0.19090188 ),
vec2( -0.24188840, 0.99706507 ), vec2( -0.81409955, 0.91437590 ),
vec2( 0.19984126, 0.78641367 ), vec2( 0.14383161, -0.14100790 )
);
float rand(vec2 co)
{
return fract(sin(dot(co, vec2(12.9898, 78.233)) * 43758.5453));
}
float linstep(float low, float high, float v)
{
return clamp((v-low)/(high-low), 0.0, 1.0);
}
float VSM(sampler2D depths, vec2 uv, float compare)
{
vec2 moments = texture2D(depths, uv).xy;
float p = smoothstep(compare - 0.02, compare, moments.x);
float variance = max(moments.y - moments.x*moments.x, -0.001);
float d = compare - moments.x;
float p_max;
p_max = linstep(0.6, 1.0, variance / (variance + d*d));
return clamp(max(p, p_max), 0.0, 1.0) / 2;
}
void main(void)
{
vec3 normalDirection;
//sample the normal map and covert from 0:1 range to -1:1 range
if (texture2D(TexNorm, ex_UV).rgb != vec3(0.0, 0.0, 0.0))
{
vec3 mapped_Normals = texture2D(TexNorm, ex_UV).rgb * 2.0 - 1.0;
normalDirection = normalize(mapped_Normals); //normal mapped normals
}
else
normalDirection = normalize(varyingNormalDirection);
vec4 texColor = texture2D(Tex, ex_UV);// usual processing of texture coordinates
vec3 viewDirection = normalize(vec3(inversedViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) - position));
vec3 lightDirection;
float attenuation;
//initialize total lighting with ambient lighting
vec3 totalAmbientDiffuse = vec3(scene_ambient) * vec3(frontMaterial.ambient);
vec3 totalSpecular;
for (int index = 0; index < numberOfLights; index++) // for all light sources
{
float Visibility;
if (lights[index].position.w == 0.0) // directional light
{
attenuation = 1.0; // no attenuation
lightDirection = normalize(vec3(lights[index].position));
//int num = int(rand(position.xyz) * 16);
Visibility = VSM(lights[index].TexShadow, ShadowCoords[index].xy + poissonDisk[int(rand(position.xy + vec2(position.z,-position.z)) * 16)] /2000, ShadowCoords[index].z);
}
else // point light or spotlight (or other kind of light)
{
vec3 positionToLightSource = vec3(lights[index].position - position);
float Distance = length(positionToLightSource);
lightDirection = normalize(positionToLightSource);
attenuation = 1.0 / (lights[index].constantAttenuation + lights[index].linearAttenuation * Distance + lights[index].quadraticAttenuation * Distance * Distance);
if (lights[index].spotCutoff <= 90.0) // spotlight
{
Visibility = VSM(lights[index].TexShadow, ShadowCoords[index].xy / ShadowCoords[index].w + poissonDisk[int(rand(position.xy + vec2(position.z,-position.z)) * 16)] / 700, ShadowCoords[index].z / ShadowCoords[index].w);
float clampedCosine = max(0.0, dot(-lightDirection, normalize(lights[index].spotDirection)));
if (clampedCosine < cos(radians(lights[index].spotCutoff))) // outside of spotlight cone
{
attenuation = 0.0;
}
else
{
attenuation = attenuation * pow(clampedCosine, lights[index].spotExponent);
}
}
else // point light
{
//point light shadow calculations
}
}
vec3 diffuseReflection = attenuation * vec3(lights[index].diffuse) * vec3(frontMaterial.diffuse) * max(0.0, dot(normalDirection, lightDirection));
vec3 specularReflection;
if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side
{
specularReflection = vec3(0.0, 0.0, 0.0); // no specular reflection
}
else // light source on the right side
{
specularReflection = attenuation * vec3(lights[index].specular) * vec3(frontMaterial.specular)
* pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), frontMaterial.shininess);
}
totalAmbientDiffuse += diffuseReflection * lights[index].intensity * Visibility;
totalSpecular += specularReflection * lights[index].intensity * Visibility;
}
gl_FragColor = vec4(totalAmbientDiffuse, 1.0) * texColor + vec4(totalSpecular, 1.0);
}
I have to write a simple OpenGL game. When I'm running it on my PC everything is good. Unfortunately when I run it on laptop it has some problems.
PC:
http://imagizer.imageshack.us/v2/800x600q90/11/i48o.png
Laptop:
http://imagizer.imageshack.us/v2/800x600q90/543/zdpf.png
This is my code for fragment shader:
varying vec3 normal, lightDir[3], eyeVec;
uniform sampler2D myTexture;
const float cos_outer_cone_angle = 0.73;
void main (void)
{
vec4 final_color = (gl_FrontLightModelProduct.sceneColor * gl_FrontMaterial.ambient) + 1.2*((gl_LightSource[0].ambient) * gl_FrontMaterial.ambient);
for(int j=1;j<2;j++){
final_color+=(gl_FrontLightModelProduct.sceneColor * gl_FrontMaterial.ambient) + ((gl_LightSource[j].ambient) * gl_FrontMaterial.ambient);
}
vec3 L[5];
vec3 D[5];
vec3 E = normalize(eyeVec);
vec3 R[5];
float specular[5];
float cos_cur_angle[5];
float cos_inner_cone_angle[5];
float cos_inner_minus_outer_angle[5];
float spot[5];
vec3 N = normalize(normal);
float lambertTerm[5];
for(int i=0;i<3;i++){
L[i]=normalize(lightDir[i]);
D[i]=normalize(gl_LightSource[i].spotDirection);
cos_cur_angle[i]=dot(-L[i], D[i]);
cos_inner_cone_angle[i] = gl_LightSource[i].spotCosCutoff;
cos_inner_minus_outer_angle[i] = cos_inner_cone_angle[i] - cos_outer_cone_angle;
spot[i] = clamp((cos_cur_angle[i] - cos_outer_cone_angle) / cos_inner_minus_outer_angle[i], 0.0,1.0);
lambertTerm[i] = max( dot(N,L[i]), 0.0);
R[i] = reflect(-L[i], N);
specular[i] = pow( max(dot(R[i], E), 0.0), gl_FrontMaterial.shininess );
if(lambertTerm[i] >0.0){
final_color += gl_LightSource[i].diffuse * gl_FrontMaterial.diffuse * lambertTerm[i] *1.5* spot[i];
final_color += gl_LightSource[i].specular * gl_FrontMaterial.specular * specular[i] *3.0* spot[i];
}
}
gl_FragColor = final_color * texture2D(myTexture, vec2(gl_TexCoord[0]));
}
And this is for Vertex Shader:
varying vec3 normal, lightDir[3], eyeVec;
void main()
{
normal = gl_NormalMatrix * gl_Normal;
vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
for(int i=0;i<3;i++){
lightDir[i] = vec3(gl_LightSource[i].position.xyz - vVertex);
}
eyeVec = -vVertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
}
PC graphics is Radeon HD6770 and Notebook GPU is Geforce GT325M.
I don't know where is the problem. Is it shaders or terrain loading or what.
How can I get this shader to have a smooth edge on the spot light instead of a hard one? In addition, the shader has to cope with a variable value of GL_SPOT_CUTOFF. Note that not all the lights are spot lights -- GL_LIGHT0 is a point light.
varying vec3 N;
varying vec3 v;
#define MAX_LIGHTS 2
void main (void)
{
vec4 finalColour;
float spotEffect;
for (int i=0; i<MAX_LIGHTS; i++)
{
vec3 L = normalize(gl_LightSource[i].position.xyz - v);
vec3 E = normalize(-v);
vec3 R = normalize(-reflect(L,N));
spotEffect = dot(normalize(gl_LightSource[i].spotDirection),
normalize(-L));
if (spotEffect > gl_LightSource[i].spotCosCutoff) {
vec4 Iamb = gl_FrontLightProduct[i].ambient;
vec4 Idiff = gl_FrontLightProduct[i].diffuse * max(dot(N,L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0);
vec4 Ispec = gl_FrontLightProduct[i].specular
* pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
Ispec = clamp(Ispec, 0.0, 1.0);
finalColour += Iamb + Idiff + Ispec;
}
}
gl_FragColor = gl_FrontLightModelProduct.sceneColor + finalColour;
}
The scene looks like this:
This shader from http://www.ozone3d.net/tutorials/glsl_lighting_phong_p3.php produces the soft edges to the spotlight you are after.
[Pixel_Shader]
varying vec3 normal, lightDir, eyeVec;
const float cos_outer_cone_angle = 0.8; // 36 degrees
void main (void)
{
vec4 final_color =
(gl_FrontLightModelProduct.sceneColor * gl_FrontMaterial.ambient) +
(gl_LightSource[0].ambient * gl_FrontMaterial.ambient);
vec3 L = normalize(lightDir);
vec3 D = normalize(gl_LightSource[0].spotDirection);
float cos_cur_angle = dot(-L, D);
float cos_inner_cone_angle = gl_LightSource[0].spotCosCutoff;
float cos_inner_minus_outer_angle =
cos_inner_cone_angle - cos_outer_cone_angle;
//****************************************************
// Don't need dynamic branching at all, precompute
// falloff(i will call it spot)
float spot = 0.0;
spot = clamp((cos_cur_angle - cos_outer_cone_angle) /
cos_inner_minus_outer_angle, 0.0, 1.0);
//****************************************************
vec3 N = normalize(normal);
float lambertTerm = max( dot(N,L), 0.0);
if(lambertTerm > 0.0)
{
final_color += gl_LightSource[0].diffuse *
gl_FrontMaterial.diffuse *
lambertTerm * spot;
vec3 E = normalize(eyeVec);
vec3 R = reflect(-L, N);
float specular = pow( max(dot(R, E), 0.0),
gl_FrontMaterial.shininess );
final_color += gl_LightSource[0].specular *
gl_FrontMaterial.specular *
specular * spot;
}
gl_FragColor = final_color;