Access GLSL vec4 components by ivec4 indices - glsl

In GLSL I can do
vec4 data = vec4(1.0, 2.0, 3.0, 4.0);
gl_FragColor = data.xxyy;
But can I somehow do?
vec4 data = vec4(1.0, 2.0, 3.0, 4.0);
ivec4 indices = ivec4(0, 0, 1, 1);
gl_FragColor = data[indices];

No you cannot. Actually you want to Swizzle something like data.indices.
You have to construct a vec4:
gl_FragColor =
vec4(data[indices[0]], data[indices[1]], data[indices[2]], data[indices[3]]);
Alternatively you can use matrix multiplication:
indices = mat4(vec4(1,1,0,0), vec4(0,0,1,1), vec4(0,0,0,0), vec4(0,0,0,0));
gl_FragColor = indices * data;

Related

How to avoid black lines between triangles on modern GPUs?

I am building a parametric 3d modeler with obj export.
I am really puzzled.
I have changed my GPU last night and now, there are cracks between the vertices, I can see what is behind. My old card was an Nvidia GTX275 and the one, NVIDIA GTX960. I didn't change anything in the code, shader or otherwise. I use only flat colors (not textures).
On the image below, the black lines that cut the pentagon into triangle shouldn't be there.
It seems to be purely an OpenGL problem as when I export the model and look in Blender, the faces are contiguous and there is no duplicate vertices.
the shader code is quite simple :
_VERTEX2 = """
#version 330
#extension GL_ARB_explicit_uniform_location : enable
layout(location = 0 ) in vec3 position;
layout(location = 1 ) in vec4 color;
layout(location = 2 ) in vec3 normal;
varying vec4 baseColor;
// uniform mat4 proj;
layout(location = 0) uniform mat4 view;
layout(location = 4) uniform mat4 proj;
varying vec3 fragVertexEc;
void main(void) {
gl_Position = proj * view * vec4(position, 1.0);
fragVertexEc = (view * vec4(position, 1.0)).xyz;
baseColor = color;
}
"""
_FRAGMENT2 = """
#version 330
#extension GL_OES_standard_derivatives : enable
varying vec3 fragVertexEc;
varying vec4 baseColor;
const vec3 lightPosEc = vec3(0,0,10);
const vec3 lightColor = vec3(1.0,1.0,1.0);
void main()
{
vec3 X = dFdx(fragVertexEc);
vec3 Y = dFdy(fragVertexEc);
vec3 normal=normalize(cross(X,Y));
vec3 lightDirection = normalize(lightPosEc - fragVertexEc);
float light = max(0.0, dot(lightDirection, normal));
gl_FragColor = vec4(normal, 1.0);
gl_FragColor = vec4(baseColor.xyz * light, baseColor.w);
}
"""
the rendering code is also quite simple :
def draw(self, view_transform, proj, transform):
self.shader.use()
gl_wrap.glBindVertexArray(self.vao)
try:
self.vbo.bind()
view_transform = view_transform * transform
GL.glUniformMatrix4fv(0, 1, False, (ctypes.c_float*16)(*view_transform.toList()))
GL.glUniformMatrix4fv(4, 1, False, (ctypes.c_float*16)(*proj.toList()))
GL.glEnableVertexAttribArray(self.shader.attrib['position'])
GL.glEnableVertexAttribArray(self.shader.attrib['color'])
GL.glEnableVertexAttribArray(self.shader.attrib['normal'])
STRIDE = 40
GL.glVertexAttribPointer(
self.shader.attrib['position'], len(Vector._fields), GL.GL_FLOAT,
False, STRIDE, self.vbo)
GL.glVertexAttribPointer(
self.shader.attrib['color'], len(Color._fields), GL.GL_FLOAT,
False, STRIDE, self.vbo+12)
GL.glVertexAttribPointer(
self.shader.attrib['normal'], len(Vector._fields), GL.GL_FLOAT,
False, STRIDE, self.vbo+28)
GL.glDrawElements(
GL.GL_TRIANGLES,
len(self.glindices),
self.index_type,
self.glindices)
finally:
self.vbo.unbind()
gl_wrap.glBindVertexArray(0)
self.shader.unuse()
A simple quad has the following data sent to OpenGL :
vertices ( flat array of pos+rgba+normal) :
[5.0, -3.061616997868383e-16, 5.0, 0.898, 0.0, 0.0, 1.0, 0.0, 1.0, 6.123233995736766e-17,
-5.0, 3.061616997868383e-16, -5.0, 0.898, 0.0, 0.0, 1.0, 0.0, 1.0, 6.123233995736766e-17,
-5.0, -3.061616997868383e-16, 5.0, 0.898, 0.0, 0.0, 1.0, 0.0, 1.0, 6.123233995736766e-17,
5.0, 3.061616997868383e-16, -5.0, 0.898, 0.0, 0.0, 1.0, 0.0, 1.0, 6.123233995736766e-17]
indices :: [0, 1, 2, 0, 3, 1]
ok, got it !
the strange display is due to glEnabled(GL_POLYGON_SMOOTH).
I had completely forgotten about it as my old card wasn't doing anything with this setting. It wasn't visible at least.
But the new one has the correct behaviour : it tries to anti-alias each triangle independently, hence the black lines.
Many thanks to #Jerem who helped me cover the other possibilities.

OpenGl 4.x ADS phong shading, plane not fully colored instead bullseye-like coloring

Here is a picture of the program running:
I can't figure out why my plane is getting a bullseye coloring, I'm pretty sure I'm doing something wrong with the shaders but I'm not entirely sure what's the problem.
this is my fragment shader.
#version 430 core
in vec4 color;
in vec4 position;
uniform float fTime;
uniform vec3 lookat;
out vec4 fColor;
vec4 calculateMyNormal(vec4 mposition)
{
float dfdx = 2*(mposition.x) * 4 * cos(radians((mposition.x*mposition.x)+ (mposition.z*mposition.z)+fTime));
float dfdz = 2*(mposition.z) * 4 * cos(radians((mposition.x*mposition.x)+(mposition.z*mposition.z)+fTime));
vec3 a = vec3(1, dfdx, 0);
vec3 b = vec3(0, dfdz, 1);
vec3 normal = normalize(cross(a, b));
return vec4(normal, 1.0);
}
vec4 ADSLightModel(vec4 myNormal, vec4 myPosition)
{
const vec4 myLightPosition = vec4(1.0, 0.5, 0.0, 1.0 );
const vec4 myLightAmbient = vec4( 0.2, 0.2, 0.2, 1.0 );
const vec4 myLightDiffuse = vec4( 1.0 , 1.0 , 1.0, 1.0 );
const vec4 myLightSpecular = vec4( 1.0 , 1.0 , 1.0 , 1.0);
const vec4 myMaterialAmbient = vec4( 1.0 , 0.5, 0.0, 1.0 );
const vec4 myMaterialDiffuse = vec4( 0.5 , 0.1, 0.5, 1.0 );
const vec4 myMaterialSpecular = vec4( 0.6, 0.6, 0.6, 1.0 );
const float myMaterialShininess = 80;
vec4 norm = normalize( myNormal );
vec4 lightv = normalize( myLightPosition - myPosition );
vec4 viewv = normalize( vec4(lookat, 1.0) - myPosition );
vec4 refl = reflect( vec4(lookat, 1.0) - lightv, norm );
vec4 ambient = myMaterialAmbient*myLightAmbient;
vec4 diffuse = max(0.0, dot(lightv, norm)) * myMaterialDiffuse * myLightDiffuse;
vec4 specular = vec4( 0.0, 0.0, 0.0, 1.0 );
if( dot(lightv, viewv) > 0)
{
specular = pow(max(0.0, dot(viewv,refl)), myMaterialShininess)*myMaterialSpecular* myLightSpecular;
}
return clamp(ambient + diffuse + specular, 0.0, 1.0);
}
void main()
{
vec4 norml = calculateMyNormal(position);
fColor = ADSLightModel(norml, position);
}
the plane moves and I do that in the vertex shader, I don't know if that might be the problem.
#version 430 core
layout (location = 0) in vec4 vPosition;
uniform float fTime;
uniform mat4 mTransform;
out vec4 color;
out vec4 position;
float calculaY(float x, float z, float time)
{
return 0.5 * sin(time + (x*x + z*z) / 50.0);
}
void main()
{
vec4 vNewpos = vPosition;
vNewpos.y = calculaY(vNewpos.x, vNewpos.z, fTime);
color = vec4(0.0, 0.0, 1.0, 1.0);
position = vNewpos;
gl_Position = mTransform * vNewpos;
}
The last thing I can imagine being wrong, would be the normals, but I'm using a the code of my teacher to generate the plane and his plane had a solid color all over the plane so either he did something wrong and fixed it or as I think, the problem is in my shaders.
Your reflection vector does not really make sense:
vec4 refl = reflect( vec4(lookat, 1.0) - lightv, norm );
There are a couple of things which should make you suspicious:
refl is not normalized. The reflect operation will preserve the length of the input vector, but the input vec4(lookat, 1.0) - lightv is not normalized.
The value of vec4(lookat, 1.0) - lightv references a point, not a direction vector, since it is the difference between a point and another direction vector.
The term vec4(lookat, 1.0) - lightv does not make sense geometrically. What you want is the reflection of the light incidence vector lightv around the normal. The viewing position is totally irrelevant for determining the direction an incident light ray will be reflected to at some surface point.
The reflection vector should just be:
refl = reflect(lightv, normal);

Lighting doesn't show in OpenGL

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.

glsl light doesn't seem to be working

I'm working on some basic lighting in my application, and am unable to get a simple light to work (so far..).
Here's the vertex shader:
#version 150 core
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 pvmMatrix;
uniform mat3 normalMatrix;
in vec3 in_Position;
in vec2 in_Texture;
in vec3 in_Normal;
out vec2 textureCoord;
out vec4 pass_Color;
uniform LightSources {
vec4 ambient = vec4(0.5, 0.5, 0.5, 1.0);
vec4 diffuse = vec4(0.5, 0.5, 0.5, 1.0);
vec4 specular = vec4(0.5, 0.5, 0.5, 1.0);
vec4 position = vec4(1.5, 7, 0.5, 1.0);
vec4 direction = vec4(0.0, -1.0, 0.0, 1.0);
} lightSources;
struct Material {
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
Material mymaterial = Material(
vec4(1.0, 0.8, 0.8, 1.0),
vec4(1.0, 0.8, 0.8, 1.0),
vec4(1.0, 0.8, 0.8, 1.0),
0.995
);
void main() {
gl_Position = pvmMatrix * vec4(in_Position, 1.0);
textureCoord = in_Texture;
vec3 normalDirection = normalize(normalMatrix * in_Normal);
vec3 lightDirection = normalize(vec3(lightSources.direction));
vec3 diffuseReflection = vec3(lightSources.diffuse) * vec3(mymaterial.diffuse) * max(0.0, dot(normalDirection, lightDirection));
/*
float bug = 0.0;
bvec3 result = equal( diffuseReflection, vec3(0.0, 0.0, 0.0) );
if(result[0] && result[1] && result[2]) bug = 1.0;
diffuseReflection.x += bug;
*/
pass_Color = vec4(diffuseReflection, 1.0);
}
And here's the fragment shader:
#version 150 core
uniform sampler2D texture;
in vec4 pass_Color;
in vec2 textureCoord;
void main() {
vec4 out_Color = texture2D(texture, textureCoord);
gl_FragColor = pass_Color;
//gl_FragColor = out_Color;
}
I'm rendering a textured wolf to the screen as a test. If I change the fragment shader to use out_Color, I see the wolf rendered properly. If I use the pass_Color, I see nothing on the screen.
This is what the screen looks like when I use out_Color in the fragment shader:
I know the diffuseReflection vector is full of 0's, by uncommenting this code in the vertex shader:
...
/*
float bug = 0.0;
bvec3 result = equal( diffuseReflection, vec3(0.0, 0.0, 0.0) );
if(result[0] && result[1] && result[2]) bug = 1.0;
diffuseReflection.x += bug;
*/
...
This will make the x component of the diffuseReflection vector 1.0, which turns the wolf red.
Does anyone see anything obvious I'm doing wrong here?
As suggested in the comments, try debugging incrementally. I see a number of ways your shader could be wrong. Maybe your normalMatrix isn't being passed properly? Maybe your in_Normal isn't mapped to the appropriate input? Maybe when you're casting lightSources.direction to a vec3, the compiler's doing something funky? Maybe your shader isn't even running at all, but you think it is? Maybe you have geometry or tessellation units and it's not passing correctly?
No one really has a chance of answering this correctly. As for me, it looks fine--but again, any of the factors above could happen--and probably more.
To debug this, you need to break it down. As suggested in the comments, try rendering the normals. Then, you should try rendering the light direction. Then render your n dot l term. Then multiply by your material parameters, then by your texture. Somewhere along the way you'll figure out the problem. As an additional tip, change your clear color to something other than black so that any black-rendered objects stand out.
It's worth noting that the above advice--break it down--is applicable to all things debugging, not just shaders. As I see it, you haven't done so here.

Phong lighting model is not actually lighting anything

I currently have an assignment to implement the Phong Lighting Model in openGL / GLSL. The two shaders that I am currently working with are below. The problem is that in the fragment shader, if I do not add vColor to gl_FragColor then the entire shape is black. However, if I DO add vColor, then the entire shape is that color with no lighting at all. I have been trying to solve this for a couple of hours now to no luck. What is the reason for this? Is it a problem in my shaders, or a problem perhaps in the openGL code? I am using one material and one point light source, which I'll show after the shaders.
Edit: If I set gl_FragColor = vec4(N, 1.0) then the object looks like this:
vertex shader:
#version 150
in vec4 vPosition;
in vec3 vNormal;
uniform mat4 vMatrix;
uniform vec4 LightPosition;
out vec3 fNorm;
out vec3 fEye;
out vec3 fLight;
void main() {
fNorm = vNormal;
fEye = vPosition.xyz;
fLight = LightPosition.xyz;
if(LightPosition.w != 0.0) {
fLight = LightPosition.xyz - vPosition.xyz;
}
gl_Position = vMatrix * vPosition;
}
fragment shader:
#version 150
in vec3 fNorm;
in vec3 fLight;
in vec3 fEye;
uniform vec4 vColor;
uniform vec4 AmbientProduct, DiffuseProduct, SpecularProduct;
uniform mat4 vMatrix;
uniform vec4 LightPosition;
uniform float Shininess;
void main(){
vec3 N = normalize(fNorm);
vec3 E = normalize(fEye);
vec3 L = normalize(fLight);
vec3 H = normalize(L + E);
vec4 ambient = AmbientProduct;
float Kd = max(dot(L, N), 0.0);
vec4 diffuse = Kd * DiffuseProduct;
float Ks = pow(max(dot(N, H), 0.0), Shininess);
vec4 specular = Ks * SpecularProduct;
if(dot(L,N) < 0.0)
specular = vec4(0.0, 0.0, 0.0, 1.0);
gl_FragColor = vColor + ambient + diffuse + specular;
}
Setting materials and light:
void init() {
setMaterials(vec4(1.0, 0.0, 0.0, 0.0), //ambient
vec4(1.0, 0.8, 0.0, 1.0), //diffuse
vec4(1.0, 1.0, 1.0, 1.0), //specular
100.0); //shine
setLightSource(vec4(1.0, 0.0, 0.0, 1.0), //ambient
vec4(1.0, 0.0, 0.0, 1.0), //diffuse
vec4(1.0, 0.0, 0.0, 1.0), //specular
vec4(1.0, 2.0, 3.0, 1.0)); //position
setProducts();
....
}
/*
* Sets the material properties for Phong lighting model.
*/
void setMaterials(vec4 amb, vec4 dif, vec4 spec, GLfloat s) {
ambient = amb;
diffuse = dif;
specular = spec;
shine = s;
glUniform1f(vShininess, shine);
}
/*
* Set light source properties.
*/
void setLightSource(vec4 amb, vec4 dif, vec4 spec, vec4 pos) {
ambient0 = amb;
diffuse0 = dif;
specular0 = spec;
light0_pos = pos;
glUniform4fv(vLightPosition, 1, light0_pos);
}
/*
* Find the products of materials components and light components.
*/
void setProducts(){
vec4 ambientProduct = ambient * ambient0;
vec4 diffuseProduct = diffuse * diffuse0;
vec4 specularProduct = specular * specular0;
glUniform4fv(vAmbientProduct, 1, ambientProduct);
glUniform4fv(vDiffuseProduct, 1, diffuseProduct);
glUniform4fv(vSpecularProduct, 1, specularProduct);
}
Your final lighting composition doesn't look right:
gl_FragColor = vColor + ambient + diffuse + specular;
It should be something like
gl_FragColor = vColor * (ambient + diffuse) + specular;
i.e. the illumination modulated by the albedo of the object.