I have got problem with my shaders. I am trying to put textures and phong shading in my game using glsl but I can't get any good effect.
I've been searching google for a long time, and I can't find any info how connect ligh and texture together, so I've decided to wrote and ask here.
This is my game without texture:
and this is with texture:
What I want to achive is to make this pinkish texture make better visible with spot on a center - just like without texture, and also repair those per vertex shading on gutters - make it per pixel shading, I don't know what is wrong now.
I have checked about 10 shaders with phong shading and I have got also per vertex not per pixel shading.
This is my fragment vertex code mayby someone can see there something?
varying vec3 N;
varying vec3 v;
uniform sampler2D myTexture;
varying vec2 vTexCoord;
void main (void)
{
vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
vec3 L = normalize(gl_LightSource[0].position.xyz - v);
vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)
vec3 R = normalize(-reflect(L,N));
//calculate Ambient Term:
vec4 Iamb = gl_FrontLightProduct[0].ambient;
//calculate Diffuse Term:
vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
// calculate Specular Term:
vec4 Ispec = gl_FrontLightProduct[0].specular
* pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
finalColor+=Iamb + Idiff + Ispec;
// write Total Color:
gl_FragColor = gl_FrontLightModelProduct.sceneColor + (texture2D(myTexture, vTexCoord)) + finalColor;
}
and my vertex shader
varying vec3 N;
varying vec3 v;
varying vec2 vTexCoord;
void main(void)
{
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_NormalMatrix * gl_Normal);
vTexCoord = vec2(gl_MultiTexCoord0);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
I'll be glad for help.
EDIT:
this is how I put my texture into shader. It works fine ( I think ) because I can edit texture values in shader - in some way.
int my_sampler_uniform_location = glGetUniformLocation(brickProg, "myTexture");
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(my_sampler_uniform_location,0);
CUTIL::drawBox();
glBindTexture(GL_TEXTURE_2D,0);
EDIT 2:
After Nicol Bolas suggestion about colors add I have edited my shader and change it like this:
gl_FragColor = (texture2D(myTexture, vTexCoord)) + finalColor;
Now it is only to bright, but now I have to chenge a little light on stage and would be great. But still I haven't got per pixel shading instead I have got per vertex shading. This is my current screen and I have marked on example what I mean talking about shading:
This equation:
gl_FragColor = gl_FrontLightModelProduct.sceneColor + (texture2D(myTexture, vTexCoord)) + finalColor;
Does not make any sense for most textures. You are taking the color produced from the lighting equation and adding it to the color sampled from the texture. This would only make sense if the values stored in the texture represented light emitting properties of the surface.
Generally, color values of a texture represent the diffuse reflectance of a surface. Which means you need to incorporate them into the lighting equation directly. The texture's color should either fully replace the diffuse color from the material or it should be combined with the material diffuse color in some way.
Related
I'm following the learnopengl website and I'm trying to combine the diffuse texture I have on the object with the calculated reflection/refraction vectors but it makes the object invisible. When I set gl_FragColor = environmentColor; it works fine but the moment I try to multipliy, add, or mix the diffuse texture the object becomes invisible. Here is the code I have:
vec3 norm = normalize(Normal);
vec3 viewVector = normalize(worldPosition.xyz - cameraPosition);
vec3 reflectedVector = reflect(viewVector, norm);
vec3 refractedVector = refract(viewVector, norm, 0.68047f);
vec4 reflectedColor = texture(skybox, reflectedVector);
vec4 refractedColor = texture(skybox, refractedVector);
vec4 environmentColor = mix(reflectedColor, refractedColor, 0.5f);
gl_FragColor = mix(texture(texture_diffuse1, TexCoords), environmentColor, 0.5f);
I found my mistake for anyone else that might have this same issue: I was setting the location of the cubemap textures to be the same as my sampler2D textures. I simply modified the glActiveTexture for the cubemap textures to be using GL_TEXTURE1 instead of GL_TEXTURE0 and initialized the uniforms to point to 1 and everything works now.
I am working on a C++ program which displays a terrain mesh using GLSL shaders. I want it to be able to use different materials based on the elevation.
I am trying to accomplish this by having an uniform array of materials in the fragment shader and then using the y coordinate of the world-space position of the current fragment to determine which material from the array to use.
Here are the relevant parts of my fragment shader:
#version 430
struct Material
{
vec3 ambient;
vec3 diffuse;
vec3 specular;
int shininess;
sampler2D diffuseTex;
bool hasDiffuseTex;
float maxY; //the upper bound of this material's layer in relation to the height of the mesh (in the range 0-1)
};
in vec2 TexCoords;
in vec3 WorldPos;
const int MAX_MATERIALS = 14;
uniform Material materials[MAX_MATERIALS];
uniform int materialCount; //the actual number of materials in the array
uniform float minY; //the minimum world-space y-coordinate in the mesh
uniform float maxY; //the maximum world-space y-coordinate in the mesh
out vec4 fragColor;
void main()
{
//calculate the y-position of this fragment in relation to the height of the mesh (in the range 0-1)
float y = (WorldPos.y - minY) / (maxY - minY);
//calculate the index into the materials array
int index = 0;
for (int i = 0; i < materialCount; ++i)
{
index += int(y > materials[i].maxY);
}
//calculate the ambient color
vec3 ambient = ...
//calculate the diffuse color
vec3 diffuse = ...
//sample from the texture
vec3 texColor = vec3(texture(materials[index].diffuseTex, TexCoords.xy));
//only multiply diffuse color with texture color if the material has a texture
diffuse += int(materials[index].hasDiffuseTex) * ((texColor * diffuse) - diffuse);
//calculate the specular color
vec3 specular = ...
fragColor = vec4(ambient + diffuse + specular, 1.0f);
}
It works fine if textures are not used:
But if one of the materials has a texture associated with it, it shows some black artifacts near the borders of the material layer which has the texture:
When I add this line after the diffuse calculation part:
if (index == 0 && int(materials[index].hasDiffuseTex) == 1 && texColor == vec3(0, 0, 0)) diffuse = vec3(1, 0, 0);
it draws the artifacts in red:
which tells me that the index is correct (0) but nothing is sampled from the texture.
Furthermore if I hardcode the index into the shader like this:
vec3 texColor = vec3(texture(materials[0].diffuseTex, TexCoords.xy));
it renders correctly. So I am guessing it has something to do with the indexing but the index appears to be correct and the texture is there so why doesn't it sample color?
I have also found out that if I switch the order of the materials and move their borders around in the GUI of my program in a certain fashion it starts to render correctly from that point on which I don't understand at all. I first suspected that this might be due to me sending wrong values of uniforms to the shaders initially and then somehow it gets the correct ones after I make the changes in the GUI but then I have tested all the uniform values I am sending to the shader from the C++ side and they all appear to be correct from the start and I don't see any other possible problem which might cause this from the C++ side. So I am now thinking the problem is probably in the shader.
I drawing a set of quads. For each quad I have a defined color in a vertex of it.
E.g. now my set of quads looks like:
I achive such result in rather primitive way just passing into vertex shader as attribute color of each vertex of an quad.
My shaders are pretty simple:
Vertex shader
#version 150 core
in vec3 in_Position;
in vec3 in_Color;
out vec3 pass_Color;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
void main(void) {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1.0);
pass_Color = in_Color;
}
Fragment Shader
#version 150 core
in vec3 pass_Color;
out vec4 out_Color;
void main(void) {
out_Color = vec4(pass_Color, 1.0);
}
Now my goal is to get color non continuous distribution of colors from vertex to vertex. It also can be called "level distribution".
My set of quads should looks like this:
How can I achieve such result?
EDIT:
With vesan and Nico Schertler plate looks like this. (not acceptable variant)
My guess is there will be issues with the hue colours you're using and vertex interpolation (e.g. skipping some bands). Instead, maybe pass in a single channel value and calculate the hue and discrete levels (as #vesan does) within the fragment shader. I use these functions myself...
vec3 hueToRGB(float h)
{
h = fract(h) * 6.0;
vec3 rgb;
rgb.r = clamp(abs(3.0 - h)-1.0, 0.0, 1.0);
rgb.g = clamp(2.0 - abs(2.0 - h), 0.0, 1.0);
rgb.b = clamp(2.0 - abs(4.0 - h), 0.0, 1.0);
return rgb;
}
vec3 heat(float x)
{
return hueToRGB(2.0/3.0-(2.0/3.0)*clamp(x,0.0,1.0));
}
and then
float discrete = floor(pass_Value * steps + 0.5) / steps; //0.5 to round
out_Color = vec4(heat(discrete), 1.0);
where in float in_Value is 0 to 1.
Just expanding on Nico Schertler's comment: you can modify your fragment shader to:
void main(void) {
out_Color = vec4(pass_Color, 1.0);
out_Color = floor(color * steps)/steps;
}
where steps in the number of color steps you want. The floor function will indeed work on a vector, however, the steps will be calculated separately for every color, so the result might not be exactly what you want (the steps might not be as nice as in your example).
Alternatively, you can use some form of "toon shading" (see for example here). That means that you only pass a single number (think a color in grayscale) to your shader, then use your shader to select a color from a color table. The table can either be hardcoded in the shader or selected from a 1-dimensional texture.
I'm trying to implement phong shading in GLSL but am having some issues with the specular component.
The green light is the specular component. The light (a point light) travels in a circle above the plane. The specular highlight always points inward toward the Y axis about which the light rotates and fans out toward the diffuse reflection as seen in the image. It doesn't appear to be affected at all by the positioning of the camera and I'm not sure where I'm going wrong.
Vertex shader code:
#version 330 core
/*
* Phong Shading with with Point Light (Quadratic Attenutation)
*/
//Input vertex data
layout(location = 0) in vec3 vertexPosition_modelSpace;
layout(location = 1) in vec2 vertexUVs;
layout(location = 2) in vec3 vertexNormal_modelSpace;
//Output Data; will be interpolated for each fragment
out vec2 uvCoords;
out vec3 vertexPosition_cameraSpace;
out vec3 vertexNormal_cameraSpace;
//Uniforms
uniform mat4 mvMatrix;
uniform mat4 mvpMatrix;
uniform mat3 normalTransformMatrix;
void main()
{
vec3 normal = normalize(vertexNormal_modelSpace);
//Set vertices in clip space
gl_Position = mvpMatrix * vec4(vertexPosition_modelSpace, 1);
//Set output for UVs
uvCoords = vertexUVs;
//Convert vertex and normal into eye space
vertexPosition_cameraSpace = mat3(mvMatrix) * vertexPosition_modelSpace;
vertexNormal_cameraSpace = normalize(normalTransformMatrix * normal);
}
Fragment Shader Code:
#version 330 core
in vec2 uvCoords;
in vec3 vertexPosition_cameraSpace;
in vec3 vertexNormal_cameraSpace;
//out
out vec4 fragColor;
//uniforms
uniform sampler2D diffuseTex;
uniform vec3 lightPosition_cameraSpace;
void main()
{
const float materialAmbient = 0.025; //a touch of ambient
const float materialDiffuse = 0.65;
const float materialSpec = 0.35;
const float lightPower = 2.0;
const float specExponent = 2;
//--------------Set Colors and determine vectors needed for shading-----------------
//reflection colors- NOTE- diffuse and ambient reflections will use the texture color
const vec3 colorSpec = vec3(0,1,0); //Green spec color
vec3 diffuseColor = texture2D(diffuseTex, uvCoords).rgb; //Get color from the texture at fragment
const vec3 lightColor = vec3(1,1,1); //White light
//Re-normalize normal vectors : after interpolation they make not be unit length any longer
vec3 normVertexNormal_cameraSpace = normalize(vertexNormal_cameraSpace);
//Set camera vec
vec3 viewVec_cameraSpace = normalize(-vertexPosition_cameraSpace); //Since its view space, camera at origin
//Set light vec
vec3 lightVec_cameraSpace = normalize(lightPosition_cameraSpace - vertexPosition_cameraSpace);
//Set reflect vect
vec3 reflectVec_cameraSpace = normalize(reflect(-lightVec_cameraSpace, normVertexNormal_cameraSpace)); //reflect function requires incident vec; from light to vertex
//----------------Find intensity of each component---------------------
//Determine Light Intensity
float distance = abs(length(lightPosition_cameraSpace - vertexPosition_cameraSpace));
float lightAttenuation = 1.0/( (distance > 0) ? (distance * distance) : 1 ); //Quadratic
vec3 lightIntensity = lightPower * lightAttenuation * lightColor;
//Determine Ambient Component
vec3 ambientComp = materialAmbient * diffuseColor * lightIntensity;
//Determine Diffuse Component
float lightDotNormal = max( dot(lightVec_cameraSpace, normVertexNormal_cameraSpace), 0.0 );
vec3 diffuseComp = materialDiffuse * diffuseColor * lightDotNormal * lightIntensity;
vec3 specComp = vec3(0,0,0);
//Determine Spec Component
if(lightDotNormal > 0.0)
{
float reflectDotView = max( dot(reflectVec_cameraSpace, viewVec_cameraSpace), 0.0 );
specComp = materialSpec * colorSpec * pow(reflectDotView, specExponent) * lightIntensity;
}
//Add Ambient + Diffuse + Spec
vec3 phongFragRGB = ambientComp +
diffuseComp +
specComp;
//----------------------Putting it together-----------------------
//Out Frag color
fragColor = vec4( phongFragRGB, 1);
}
Just noting that the normalTransformMatrix seen in the Vertex shader is the inverse-transpose of the model-view matrix.
I am setting a vector from the vertex position to the light, to the camera, and the reflect vector, all in camera space. For the diffuse calculation I am taking the dot product of the light vector and the normal vector, and for the specular component I am taking the dot product of the reflection vector and the view vector. Perhaps there is some fundamental misunderstanding that I have with the algorithm?
I thought at first that the problem could be that I wasn't normalizing the normals entering the fragment shader after interpolation, but adding a line to normalize didn't affect the image. I'm not sure where to look.
I know that there a lot of phong shading questions on the site, but everyone seems to have a problem that is a bit different. If anyone can see where I am going wrong, please let me know. Any help is appreciated.
EDIT: Okay its working now! Just as jozxyqk suggested below, I needed to do a mat4*vec4 operation for my vertex position or lose the translation information. When I first made the change I was getting strange results until I realized that I was making the same mistake in my OpenGL code for the lightPosition_cameraSpace before I passed it to the shader (the mistake being that I was casting down the view matrix to a mat3 for the calculation instead of setting the light position vector as a vec4). Once I edited those lines the shader appears to be working properly! Thanks for the help, jozxqk!
I can see two parts which don't look right.
"vertexPosition_cameraSpace = mat3(mvMatrix) * vertexPosition_modelSpace" should be a mat4/vec4(x,y,z,1) multiply, otherwise it ignores the translation part of the modelview matrix.
2. distance uses the light position relative to the camera and not the vertex. Use lightVec_cameraSpace instead. (edit: missed the duplicated calculation)
Pixel based lighting is a common issue in many OpenGL applications, as the standard OpenGL lighting has very poor quality.
I want to use a GLSL program to have per-pixel based lighting in my OpenGL program instead of per-vertex. Just Diffuse lighting, but with fog, texture and texture-alpha at least.
I started with this shader:
texture.vert:
varying vec3 position;
varying vec3 normal;
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_FrontColor = gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
normal = normalize(gl_NormalMatrix * gl_Normal);
position = vec3(gl_ModelViewMatrix * gl_Vertex);
}
texture.frag:
uniform sampler2D Texture0;
uniform int ActiveLights;
varying vec3 position;
varying vec3 normal;
void main(void)
{
vec3 lightDir;
float attenFactor;
vec3 eyeDir = normalize(-position); // camera is at (0,0,0) in ModelView space
vec4 lightAmbientDiffuse = vec4(0.0,0.0,0.0,0.0);
vec4 lightSpecular = vec4(0.0,0.0,0.0,0.0);
// iterate all lights
for (int i=0; i<ActiveLights; ++i)
{
// attenuation and light direction
if (gl_LightSource[i].position.w != 0.0)
{
// positional light source
float dist = distance(gl_LightSource[i].position.xyz, position);
attenFactor = 1.0/( gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * dist +
gl_LightSource[i].quadraticAttenuation * dist * dist );
lightDir = normalize(gl_LightSource[i].position.xyz - position);
}
else
{
// directional light source
attenFactor = 1.0;
lightDir = gl_LightSource[i].position.xyz;
}
// ambient + diffuse
lightAmbientDiffuse += gl_FrontLightProduct[i].ambient*attenFactor;
lightAmbientDiffuse += gl_FrontLightProduct[i].diffuse * max(dot(normal, lightDir), 0.0) * attenFactor;
// specular
vec3 r = normalize(reflect(-lightDir, normal));
lightSpecular += gl_FrontLightProduct[i].specular *
pow(max(dot(r, eyeDir), 0.0), gl_FrontMaterial.shininess) *
attenFactor;
}
// compute final color
vec4 texColor = gl_Color * texture2D(Texture0, gl_TexCoord[0].xy);
gl_FragColor = texColor * (gl_FrontLightModelProduct.sceneColor + lightAmbientDiffuse) + lightSpecular;
float fog = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale; // Intensität berechnen
fog = clamp(fog, 0.0, 1.0); // Beschneiden
gl_FragColor = mix(gl_Fog.color, gl_FragColor, fog); // Nebelfarbe einmischen
}
Comments are german because it's a german site where this code was posted, sorry.
But all this shader does is make everything very dark. No lighting effects at all - yet the shader codes compile. If I only use GL_LIGHT0 in the fragment shader, then it seems to work, but only reasonable for camera facing polygons and my floor polygon is just extremely dark. Also quads with RGBA textures show no sign of transparency.
I use standard glRotate/Translate for the Modelview matrix, and glVertex/Normal for my polygons. OpenGL lighting works fine apart from the fact that it looks ugly on very large surfaces. I triple checked my normals, they are fine.
Is there something wrong in the above code?
OR
Tell me why there is no generic lighting Shader for this actual task (point based light with distance falloff: a candle if you will) - shouldn't there be just one correct way to do this? I don't want bump/normal/parallax/toon/blur/whatever effects. I just want my lighting to perform better with larger polygons.
All Tutorials I found are only useful for lighting a single object when the camera is at 0,0,0 facing orthogonal to the object. The above is the only one found that at least looks like the thing I want to do.
I would strongly suggest you to read this article to see how the standard ADS lightning is done within GLSL.That is GL 4.0 but not a problem to adjust to your version:
Also you operate in the view (camera) space so DON"T negate the eyes vector :
vec3 eyeDir = normalize(-position);
I had pretty similar issues to yours because I also negated the eye vector forgetting that it is transformed into the view space.Your diffuse and specular calculations seem to be wrong too in the current scenario.In your place I wouldn't use data from the fixed pipeline at all ,otherwise what is the point doing it in a shader?
Here is the method to calculate diffuse and specular in the per fragment ADS point lightning:
void ads( int lightIndex,out vec3 ambAndDiff, out vec3 spec )
{
vec3 s = vec3(lights[lightIndex].Position - posOut) ;
vec3 v = normalize( posOut.xyz );
vec3 n = normalize(normOut);
vec3 h = normalize(v+s) ;// half vector (read in the web on what it is )
vec3 diffuse = ((Ka+ lights[lightIndex].Ld) * Kd * max( 0.0,dot(n, v) )) ;
spec = Ks * pow( max(0.0, dot(n,h) ), Shininess ) ;
ambAndDiff = diffuse ;
/// Ka-material ambient factor
/// Kd-material diffuse factor
/// Ks-material specular factor.
/// lights[lightIndex].Ld-lights diffuse factor;you may also add La and Ls if you want to have even more control of the light shading.
}
Also I wouldn't suggest you using the attenuation equation you have here,it is hard to control.If you want to add light radius based attenuation
there is this nice blog post: