i have written a fragment shader that works just fine with a single light. Now I am trying to adapt it to work with 8 lights, the implement it in Processing. Clearly I am doing something wrong in the math and I cannot see what it is... I have read other posts about this and try to adapt the answer to my problem, no luck though...
////Fragment/////
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
varying vec4 vertColor;
varying vec3 ecNormal;
varying vec3 lightDir;
void main() {
vec3 direction = normalize(lightDir);
vec3 normal = normalize(ecNormal);
float intensity = max(0.0, dot(direction, normal));
gl_FragColor = vec4(intensity, intensity, intensity, 1) * vertColor;
}
////vertex/////
#define PROCESSING_LIGHT_SHADER
uniform mat4 modelview;
uniform mat4 transform;
uniform mat3 normalMatrix;
uniform vec4 lightPosition;
uniform vec3 lightNormal;
attribute vec4 vertex;
attribute vec4 color;
attribute vec3 normal;
varying vec4 vertColor;
varying vec3 ecNormal;
varying vec3 lightDir;
void main() {
gl_Position = transform * vertex;
vec3 ecVertex = vec3(modelview * vertex);
ecNormal = normalize(normalMatrix * normal);
lightDir = normalize(lightPosition.xyz - ecVertex);
vertColor = color;
}
Just making it compile real quick with an online shader tool (http://shdr.bkcore.com/).
You might need to pass the attributes from the veretex shader to varyings for the fragment shader, but I'm not sure, been a while since I wrote shaders.
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
uniform mat4 modelview;
uniform mat4 normalMatrix;
uniform int lightCount;
uniform vec4 lightPosition[8];
varying vec4 vertex; //was attribute, no such thing in frag shaders
varying vec3 normal; //was attribute
varying vec4 vertColor;
void main() {
vec3 vertexCamera = vec3(modelview * vertex);
vec3 transformedNormal = normalize(normalMatrix * vec4(normal,1)).xyz; //was vec3 = normalize(mat4*vec3);
float intensity = 0.0;
for(int i = 0 ; i<8;i++){ //can't loop over a non-constant variable
if(lightCount<i)
{
vec3 direction = normalize(lightPosition[i].xyz - vertexCamera);
intensity += max(0.0, dot(direction, transformedNormal));
}
}
gl_FragColor = vec4(intensity, intensity, intensity, 1) * vertColor;
}
Related
I'm making some first steps in webgl programming. Created a simple setup following this tutorial. Managed to add a few things of my own, though stumbled with adding light, particularly - specular light.
As I assume, most of it would be implemented in my fragment shader, and maybe some additions in the vertex shader and the Light module. So that's the code I provide below.
Vertex shader:
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
varying vec3 vNormal;
varying vec2 vUv;
void main() {
vUv = uv;
vNormal = (model * vec4(normal, 0.)).xyz;
gl_Position = projection * view * model * vec4(position, 1.);
}
Fragment shader:
#ifdef GL_ES
precision highp float;
#endif
uniform vec3 lightDirection;
uniform float ambientLight;
uniform sampler2D diffuse;
varying vec3 vNormal;
varying vec2 vUv;
void main() {
float lightness = -clamp(dot(normalize(vNormal), normalize(lightDirection)), -1., 0.);
lightness = ambientLight + (1. - ambientLight) * lightness;
gl_FragColor = vec4(texture2D(diffuse, vUv).rgb * lightness, 1.);
}
Light.js module:
function Light () {
this.lightDirection = new Vector3(-1, -1, -1)
this.ambientLight = 0.3
}
Light.prototype.use = function (shaderProgram) {
var dir = this.lightDirection
var gl = shaderProgram.gl
gl.uniform3f(shaderProgram.lightDirection, dir.x, dir.y, dir.z)
gl.uniform1f(shaderProgram.ambientLight, this.ambientLight)
}
I would really appreciate your suggestions here. Thanks in advance!
The most common and simplest light models are the Phong reflection model or the Blinn–Phong model model.
The following shader code, is based on your original code and implements the Blinn–Phong model model. In compare to your code, the light calculations are done in view space, because the specular highlight depends on the view position, which is (0, 0, 0) in view space. So the light direction has to be transformed to view space.
Vertex shader:
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec3 lightDirection;
varying vec3 vPos;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 lightDirectionView;
void main()
{
lightDirectionView = (view * vec4(lightDirection, 0.)).xyz;
mat4 modelView = view * model;
vec4 viewPos = modelView * vec4(position, 1.0)
vPos = viewPos.xyz;
vUv = uv;
vNormal = (modelView * vec4(normal, 0.)).xyz;
gl_Position = projection * viewPos;
}
Fragemnt shader:
#ifdef GL_ES
precision highp float;
#endif
uniform float shininess;
uniform float ambientLight;
uniform sampler2D diffuse;
varying vec3 vPos;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 lightDirectionView;
void main()
{
vec3 color = texture2D(diffuse, vUv).rgb;
vec3 N = normalize( vNormal );
vec3 L = normalize( -lightDirectionView );
vec3 V = normalize( -vPos );
vec3 H = normalize( V + L );
float NdotL = dot(N, L);
float NdotH = dot(N, H);
float kDiffuse = max(0.0, NdotL);
// float kSpecular = (shininess + 2.0) * pow(max(0.0, NdotH), shininess) / (2.0 * 3.14159265);
float kSpecular = pow(max(0.0, NdotH), shininess);
vec3 light_col = color * (kDiffuse + kSpecular);
gl_FragColor = vec4(light_col, 1.0);
}
The value of the uniform shininess has to be a positive value in range [1, 100].
See also Phong and Gouraud Shading WebGL.
So I've currently managed to write a shader using Xoppa tutorials and use an AssetManager, and I managed to bind a texture to the model, and it looks fine.
[[1
Now the next step I guess would be to create diffuse(not sure if thats the word? phong shading?) lighting(?) to give the bunny some form of shading. While I have a little bit of experience with GLSL shaders in LWJGL, I'm unsure how to process that same information so I can use it in libGDX and in the glsl shaders.
I understand that this all could be accomplished using the Environment class etc. But I want to achieve this through the shaders alone or by traditional means simply for the challenge.
In LWJGL, shaders would have uniforms:
in vec3 position;
in vec2 textureCoordinates;
in vec3 normal;
out vec2 pass_textureCoordinates;
out vec3 surfaceNormal;
out vec3 toLightVector;
uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform vec3 lightPosition;
This would be reasonably easy for me to calculate in LWJGL
Vertex file:
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord0;
uniform mat4 u_worldTrans;
uniform mat4 u_projViewTrans;
varying vec2 v_texCoords;
void main() {
v_texCoords = a_texCoord0;
gl_Position = u_projViewTrans * u_worldTrans * vec4(a_position, 1.0);
}
I imagine that I could implement the uniforms similarly to the LWGL glsl example, but I dont know how I can apply these uniforms into libgdx and have it work. I am unsure what u_projViewTrans is, I'm assuming it is a combination of the projection, transformation and view matrix, and setting the uniform with the camera.combined?
If someone could help me understand the process or point to an example of how (per pixel lighting?), can be implemented with just the u_projViewTrans and u_worldTrans, I'd greatly appreciate your time and effort in helping me understand these concepts a bit better.
Heres my github upload of my work in progress.here
You can do the light calculations in world space. A simple lambertian diffuse light can be calculated like this:
vec3 toLightVector = normalize( lightPosition - vertexPosition );
float ligtIntensity = max( 0.0, dot( normal, toLightVector ));
A detailed explanation can be found in the answer to the Stackoverflow question How does this faking the light work on aerotwist?.
While Gouraud shading calculates the light in the the vertex shader, Phong shading calculates the light in the fragment shader.
(see further GLSL fixed function fragment program replacement)
A Gouraud shader may look like this:
Vertex Shader:
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord0;
uniform mat4 u_worldTrans;
uniform mat4 u_projViewTrans;
uniform vec3 lightPosition;
varying vec2 v_texCoords;
varying float v_lightIntensity;
void main()
{
vec4 vertPos = u_worldTrans * vec4(a_position, 1.0);
vec3 normal = normalize(mat3(u_worldTrans) * a_normal);
vec3 toLightVector = normalize(lightPosition - vertPos.xyz);
v_lightIntensity = max( 0.0, dot(normal, toLightVector));
v_texCoords = a_texCoord0;
gl_Position = u_projViewTrans * vertPos;
}
Fragment Shader:
varying vec2 v_texCoords;
varying float v_lightIntensity;
uniform sampler2D u_texture;
void main()
{
vec4 texCol = texture( u_texture, v_texCoords.st );
gl_FragColor = vec4( texCol.rgb * v_lightIntensity, 1.0 );
}
A Phong shading may look like this:
Vertex Shader:
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord0;
uniform mat4 u_worldTrans;
uniform mat4 u_projViewTrans;
varying vec2 v_texCoords;
varying vec3 v_vertPosWorld;
varying vec3 v_vertNVWorld;
void main()
{
vec4 vertPos = u_worldTrans * vec4(a_position, 1.0);
v_vertPosWorld = vertPos.xyz;
v_vertNVWorld = normalize(mat3(u_worldTrans) * a_normal);
v_texCoords = a_texCoord0;
gl_Position = u_projViewTrans * vertPos;
}
Fragment Shader:
varying vec2 v_texCoords;
varying vec3 v_vertPosWorld;
varying vec3 v_vertNVWorld;
uniform sampler2D u_texture;
struct PointLight
{
vec3 color;
vec3 position;
float intensity;
};
uniform PointLight u_pointLights[1];
void main()
{
vec3 toLightVector = normalize(u_pointLights[0].position - v_vertPosWorld.xyz);
float lightIntensity = max( 0.0, dot(v_vertNVWorld, toLightVector));
vec4 texCol = texture( u_texture, v_texCoords.st );
vec3 finalCol = texCol.rgb * lightIntensity * u_pointLights[0].color;
gl_FragColor = vec4( finalCol.rgb * lightIntensity, 1.0 );
}
I'm using ogre3d meshy to view a model. I have written a shader that works with normal maps, reflection, specular maps. But normal maps doesn't work as shown in the picture.
The reflection is working as you see, and sepcular maps is working, but I don't need see the normal maps and bump mapping is working though.
I have tried to disable everything and output the result of the normal maps and its textured and sampled correctly, the same for specular, and for the diffuse map.
Here is the GLSL VS
/*
Environmental Cubic Reflection
NormalMapping
TetxureMapping Scaling
*/
#version 120
#define lowp
#define mediump
#define highp
attribute vec4 vertex;
attribute vec3 normal;
attribute vec4 uv0;
attribute vec4 uv1;
attribute vec4 tangent;
//attribute vec3 binormal;
uniform mat4 normalMatrix;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 modelView;
uniform vec3 camera_world_position;
uniform mat4 textureMatrix0;
varying vec2 texCoord[2];
varying vec3 viewWorld;
varying mat3 world2Tangent;
void main()
{
gl_Position = modelViewProjectionMatrix * vertex;
// transform the uv coordinates
texCoord[0] = (textureMatrix0 * uv0).xy;
texCoord[1] = uv1.xy;
//world.
vec3 vertexWorld = vec3(modelView * vertex);
//transform world to tangent.
//world2Tangent = mat3(normalMatrix) * mat3(tangent, binormal, normal);
// no binormal in ogre?. must reconstruct. Ogre inverts?
vec3 binormal = cross ( normal, tangent.xyz ) * tangent.www;
world2Tangent = mat3(normalMatrix) * mat3(tangent.xyz, binormal, normal);
//Camera Position
//Use Light0 instead of camera position to match phong specular with environment reflection
viewWorld = normalize( - vertexWorld );
}
#version 120
#define lowp
#define mediump
#define highp
uniform sampler2D diffuseColorMap;
uniform sampler2D ambientOcclusionMap;
uniform sampler2D normalMap;
uniform sampler2D specularMap;
uniform samplerCube envMap;
uniform float diffuseFactor;
uniform float reflectionFactor;
uniform float opacity;
varying vec2 texCoord[2];
varying mat3 world2Tangent;
varying vec3 viewWorld;
void main()
{
//unpack current normal in tangent space
vec3 normal = 2.0 * texture2D (normalMap, texCoord[0].st).rgb - 1.0;
// environment reflection in world space
vec3 normalWorld = normalize(world2Tangent * normal);
vec3 refDir = viewWorld - 2.0 * dot(viewWorld,normalWorld) * normalWorld;
vec4 diffuseColor = texture2D( diffuseColorMap, texCoord[0] );
//mix ambient material with reflection
vec4 final = diffuseFactor * ( diffuseColor * texture2D(ambientOcclusionMap, texCoord[0]) ) +
reflectionFactor * ( textureCube(envMap,refDir) * texture2D(specularMap, texCoord[0]) );
final.a = diffuseColor.a * opacity;
gl_FragColor= final;
}
I am using FragmentShader and VertexShader at present, and works absolutely fine. I cannot get my geometry shader working. I am absolutely new to it, below is what I have tried.
I am using VBO, lighting and textures along with some geometry, but it works fine before using GeometryShader. the only thing I have changed is the variable names as I had to get the input in the geometry shader and give the output. So I have appended 1 at the end of those variable names those which will go out from geometry shader to the fragment shader.
Also I have added headers starting with # which were earlier not there. I am using GL_TRIANGLES to draw.
VertexShader
in vec4 position;
in vec4 color1;
in vec4 normal;
in vec2 texCoord;
uniform sampler2D Tex1;
uniform int use_texture;
out vec4 pcolor;
out vec3 N;
out vec3 L;
out vec3 R;
out vec3 V;
uniform mat4 local2clip;
uniform mat4 local2eye;
uniform mat4 normal_matrix;
uniform mat4 world2eye;
uniform vec4 light_ambient;
uniform vec4 light_diffuse;
uniform vec4 light_specular;
uniform vec4 light_pos;
#version 330 compatibility
uniform vec4 mat_ambient;
uniform vec4 mat_diffuse;
uniform vec4 mat_specular;
uniform float mat_shine;
//varying vec3 v_normal; // vertex normal
out vec4 v_color; // vertex color
out vec4 pos_in_eye; //vertex position in eye space
out vec2 FtexCoord;
void main(){
gl_Position = local2clip * position;
N = normalize(vec3(normal_matrix * normal)); //v_normal
vec4 Lpos = world2eye * light_pos; //light pos. in eye
vec4 Vpos = local2eye * position; //pos_in_eye
L = normalize(vec3(Lpos - Vpos)); //light_vector
R = normalize(reflect(-L, N));
V = normalize(vec3(-Vpos)); //eye vector
vec3 halfv = normalize(L+V);
FtexCoord = texCoord;
//pcolor = color1;
}
This is my FragemntShader
#version 330 compatibility
uniform int use_texture;
in vec4 pcolor;
in vec3 N1;
in vec3 L1;
in vec3 R1;
in vec3 V1;
uniform mat4 local2clip;
uniform mat4 local2eye;
uniform mat4 normal_matrix;
uniform mat4 world2eye;
uniform vec4 light_ambient;
uniform vec4 light_diffuse;
uniform vec4 light_specular;
uniform vec4 light_pos;
uniform vec4 mat_ambient;
uniform vec4 mat_diffuse;
uniform vec4 mat_specular;
uniform float mat_shine;
uniform sampler2D Tex1;
in vec2 FtexCoord1;
void main() {
vec4 ambient = light_ambient * mat_ambient;
float NdotL;
if (dot(N1,L1) <0.0) NdotL = 0.0;
else NdotL = dot(N1, L1);
vec4 diffuse = light_diffuse * mat_diffuse * NdotL;
float RdotV;
RdotV = dot(R1, V1);
if (NdotL == 0.0) RdotV = 0.0;
if (RdotV <0.0) RdotV = 0.0;
vec4 specular = light_specular * mat_specular * pow(RdotV,mat_shine);
vec4 texcolor;
if( use_texture == 1 ) {
texcolor = texture2D(Tex1, FtexCoord1);
gl_FragColor = texcolor;
}
else
gl_FragColor = (diffuse + ambient + specular);
}
This is my GeometryShader
#version 330
layout (triangles) in;
layout (triangles) out;
layout (max_vertices = 3) out;
out vec3 N1;
out vec3 L1;
out vec3 R1;
out vec3 V1;
in vec3 N;
in vec3 L;
in vec3 R;
in vec3 V;
uniform mat4 local2clip;
uniform mat4 local2eye;
uniform mat4 normal_matrix;
uniform mat4 world2eye;
uniform vec4 light_ambient;
uniform vec4 light_diffuse;
uniform vec4 light_specular;
uniform vec4 light_pos;
uniform vec4 mat_ambient;
uniform vec4 mat_diffuse;
uniform vec4 mat_specular;
uniform float mat_shine;
//varying vec3 v_normal; // vertex normal
out vec4 v_color1; // vertex color
out vec4 pos_in_eye1; //vertex position in eye space
out vec2 FtexCoord1;
in vec4 v_color; // vertex color
in vec4 pos_in_eye; //vertex position in eye space
in vec2 FtexCoord;
void main(void)
{
int i;
N1=N;
L1=L;
R1=R;
V1=R;
FtexCoord1=FtexCoord;
v_color1=v_color;
pos_in_eye1=pos_in_eye;
for (i = 0; i < gl_in.length(); i++)
{
gl_Position = gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}
I just want that what ever was there earlier is passed from vertex shader to fragment shader via geometry shader, so that I can manipulate the shader later. Currently the screen is just black
The core of your problem is that you didn't bother to check for compilation errors when you built your Geometry Shader. I know that because I see several syntax errors for it. In particular:
in vec3 N;
in vec3 L;
in vec3 R;
in vec3 V;
in vec4 v_color; // vertex color
in vec4 pos_in_eye; //vertex position in eye space
in vec2 FtexCoord;
Geometry Shader inputs are always aggregated into arrays. Remember: a geometry shader operates on primitives, which are defined as a collection of one or more vertices. Each GS invocation therefore gets a set of per-vertex input values, one for each vertex in the primitive type defined by your layout in qualifier.
Notice how you loop over the number of vertices in a primitive and use gl_in[i] to get the input value for each vertex in the primitive. That's how you need to access all of your Geometry Shader inputs. And you need to write each one to its corresponding output variable, then call EmitVertex. All in that loop.
Hi i'm new to GLSL and i'm having a few problems.
I'm trying to create a pair of GLSL Shaders to either use color or texture but i must be doing something wrong.
The problem is that if set uUseTexture to 0 (which should indicate color) it doesn't work (object is not colored). I know the coloring code works separately, any hints why it does not work using the if statement?
Here is the code:
// Fragment
precision mediump float;
uniform int uUseTexture;
uniform sampler2D uSampler;
varying vec4 vColor;
varying vec2 vTextureCoord;
void main(void) {
if(uUseTexture == 1) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
} else {
gl_FragColor = vColor;
}
}
// Vertex
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
attribute vec2 aTextureCoord;
uniform int uUseTexture;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec4 vColor;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
if(uUseTexture == 1) {
vTextureCoord = aTextureCoord;
} else {
vColor = aVertexColor;
}
Nothing springs to mind immediately glancing over your code, but I'd like to take a moment and point out that this use case can be covered without needing an if statement. For example, let's treat uUseTexture as a float instead of an int (you could cast it in the shader but this is more interesting):
// Vertex
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec4 vColor;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
// It may actually be faster to just assign both of these anyway
vTextureCoord = aTextureCoord;
vColor = aVertexColor;
}
// Fragment
uniform float uUseTexture;
uniform sampler2D uSampler;
varying vec4 vColor;
varying vec2 vTextureCoord;
void main(void) {
// vTextureCoord is already a vec2, BTW
vec4 texColor = texture2D(uSampler, vTextureCoord) * uUseTexture;
vec4 vertColor = vColor * (1.0 - uUseTexture);
gl_FragColor = texColor + vertColor;
}
Now uUseTexture simply acts as a modulator for how much of each color source you want to use. And it's more flexible in that you could set it to 0.5 and get half texture/half vertex color too!
The thing that may surprise you is that there's a good likelihood that this is what the shader compiler is doing behind the scenes anyway when you use an if statement like that. It's typically more efficient for the hardware that way.