I'm having a problem building this on my raspberry. This same shader code works on several other computers, even if I force usage of OpenGL ES, and force the GLSL version to 1.0 es.
The #version string is added programatically to each of the shaders.
Vertex shader:
#version 100
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#if (__VERSION__ > 120)
#define IN in
#define OUT out
#else
#define IN attribute
#define OUT varying
#endif // __VERSION
#define MAX_LIGHTS 8
struct SLight
{
vec3 Position;
vec3 DiffuseColor;
float Intensity;
float ConstantAttenuation;
float LinearAttenuation;
float ExponentialAttenuation;
float CutoffDistance;
float CutoffIntensity;
};
struct SMaterial
{
vec3 Specular, Diffuse, Ambient;
float Shininess;
};
uniform SLight Lights[MAX_LIGHTS];
uniform int LightCount;
uniform SMaterial Material;
struct SAmbientLight
{
vec3 Color;
float Intensity;
};
uniform mat4 ModelMatrix, ViewMatrix, MVPMatrix;
uniform SAmbientLight AmbientLight;
IN vec3 VertexPosition, VertexNormal;
IN vec2 VertexTexCoord;
IN vec4 VertexColor;
OUT vec2 PerVertex_TexCoord;
OUT vec4 PerVertex_Color;
OUT vec3 PerVertex_ViewSpaceNormal, PerVertex_ViewVector;
OUT vec4 PerVertex_LightVectors[MAX_LIGHTS];
uniform bool ColoringEnabled, TexturingEnabled, LightingEnabled;
vec4 ViewSpaceLightPositions[MAX_LIGHTS];
void main()
{
mat4 ObjectToViewMatrix = ViewMatrix * ModelMatrix;
vec4 ViewSpaceCoordinate = ObjectToViewMatrix * vec4 ( VertexPosition, 1.0f );
// Calculate normal in view-space
PerVertex_ViewSpaceNormal = mat3 ( ObjectToViewMatrix ) * VertexNormal;
// Calculate light position in view-space
for ( int cont = 0; cont < LightCount; ++cont )
ViewSpaceLightPositions[cont] = ( ViewMatrix * vec4 ( Lights[cont].Position, 1.0f ) );
// Calculate vectors from the lights to this vertex
for ( int cont = 0; cont < LightCount; ++cont )
PerVertex_LightVectors[cont] = ViewSpaceLightPositions[cont] - ViewSpaceCoordinate;
// Calculate view vector
PerVertex_ViewVector = -ViewSpaceCoordinate.xyz;
gl_Position = MVPMatrix * vec4 ( VertexPosition, 1.0f );
PerVertex_TexCoord = VertexTexCoord;
if ( ColoringEnabled )
PerVertex_Color = VertexColor;
}
fragment shader:
#version 100
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#if (__VERSION__ > 120)
#define IN in
#else
#define IN varying
#endif // __VERSION __
#if ( __VERSION__ > 330 )
#define texture2D texture
#endif
#if ( __VERSION__ >= 300 )
#define FRAG_OUTPUT FragOutput
out vec4 FragOutput;
#else
#define FRAG_OUTPUT gl_FragColor
#endif
#define MAX_LIGHTS 8
struct SLight
{
vec3 Position;
vec3 DiffuseColor;
float Intensity;
float ConstantAttenuation;
float LinearAttenuation;
float ExponentialAttenuation;
float CutoffDistance;
float CutoffIntensity;
};
struct SMaterial
{
vec3 Specular, Diffuse, Ambient;
float Shininess;
};
uniform SLight Lights[MAX_LIGHTS];
uniform int LightCount;
uniform SMaterial Material;
struct SAmbientLight
{
vec3 Color;
float Intensity;
};
uniform mat4 ModelMatrix, ViewMatrix, MVPMatrix;
uniform SAmbientLight AmbientLight;
IN vec2 PerVertex_TexCoord;
IN vec4 PerVertex_Color;
IN vec3 PerVertex_ViewSpaceNormal, PerVertex_ViewVector;
IN vec4 PerVertex_LightVectors[MAX_LIGHTS];
uniform bool ColoringEnabled, TexturingEnabled, LightingEnabled;
uniform sampler2D TextureSampler;
vec4 CalculateLights ( void )
{
vec4 LightResult;
LightResult = vec4 ( 0.0f, 0.0f, 0.0f, 1.0f );
vec3 N = normalize ( PerVertex_ViewSpaceNormal );
vec3 V = normalize ( PerVertex_ViewVector );
for ( int cont = 0; cont < LightCount; ++cont )
{
float Distance = length ( PerVertex_LightVectors[cont] );
if ( Distance > Lights[cont].CutoffDistance )
continue;
// Normalize the incoming N, L and V vectors
vec3 L = normalize ( PerVertex_LightVectors[cont] ).xyz;
vec3 H = normalize ( L + V );
// Compute the diffuse and specular components for each fragment
vec3 diffuse = max ( dot ( N, L ), 0.0f ) * Material.Diffuse * Lights[cont].DiffuseColor /** Lights[cont].Intensity*/;
vec3 specular = pow ( max ( dot ( N, H ), 0.0f ), Material.Shininess ) * Material.Specular;
// Compute attenuation
float Attenuation = Lights[cont].ConstantAttenuation + Lights[cont].LinearAttenuation * Distance + Lights[cont].ExponentialAttenuation * pow ( Distance, 2.0f );
// Final color contribution from this light
vec3 LightContribution = vec3 ( diffuse + specular ) / Attenuation;
if ( length ( LightContribution ) < Lights[cont].CutoffIntensity )
continue;
LightResult += vec4 ( LightContribution, 1.0f );
// LightResult += vec4 ( diffuse + specular, 1.0f );
}
LightResult += vec4 ( AmbientLight.Color * AmbientLight.Intensity * Material.Ambient, 1.0f );
return LightResult;
}
void main()
{
vec4 FragmentOriginalColor;
if ( TexturingEnabled )
FragmentOriginalColor = texture2D ( TextureSampler, PerVertex_TexCoord );
else if ( ColoringEnabled )
FragmentOriginalColor = PerVertex_Color;
else
FragmentOriginalColor = vec4 ( Material.Diffuse, 1.0f );
if ( LightingEnabled )
FragmentOriginalColor *= CalculateLights();
if ( FragmentOriginalColor.a == 0.0 )
discard;
FRAG_OUTPUT = FragmentOriginalColor;
}
This is the output from my app:
DEBUG: Video driver 1: RPI
DEBUG: Video driver 2: dummy
DEBUG: Current video driver: RPI
INFO: Initializing OpenGLES2
INFO: Initializing OpenGLES2
DEBUG: Reported GL version string : OpenGL ES 2.0
DEBUG: Reported GLSL version string : OpenGL ES GLSL ES 1.00
DEBUG: Parsed GLSL version 1.0 es
glGetError 0x500
glGetError 0x500
DEBUG: OpenGL version 2.0 es
DEBUG: GLSL version 1.0 es
DEBUG: Created window 0x160a960
DEBUG: GL program info log length 9
DEBUG: vertex shader ID 1 successfully compiled
DEBUG: GL program info log length 9
DEBUG: fragment shader ID 2 successfully compiled
DEBUG: Created shader program 3
DEBUG: GL program info log length 56
ERROR: Shader program 3 link error. ERROR:LEX/PARSE-1 (vertex shader, line 61) Syntax error
Line 61 appears to be the first line inside main, where the two matrices are multiplied. What am I doing wrong?
I tried to compile the vertex shader for GLES with PVRShaderEditor (from the Power VR SDK, usefull tool to check for GLES related errors, it allows compiling shader like if you were on an iPhone).
It reports three errors:
ERROR: 0:62: 'f' : suffix for floats requires language version 300
ERROR: 0:69: 'f' : suffix for floats requires language version 300
ERROR: 0:78: 'f' : suffix for floats requires language version 300
So you just need to replace all 1.0f with 1.0 in vertex AND fragment shaders and the problem should be solved, seems like the f suffix is not supported in GLES2.0.
Note that it seems there is a bug on Pi which causes compilation errors to be shown at program linking time while they should be shown at shader compilation time... No idea why the error message you get is not more detailled ...
Related
I'm porting an openGL application to webassembly using Emscripten. I've written a bunch of shaders in GLSL (330) for the native version. However for the webversion I need shaders written in GLSL ES (300 es). How would I go about converting my shaders from GLSL to GLSL ES?
Possibilities I have considered so far:
GLSL -> SPIR-V -> GLSL ES,
having a bunch of #ifdef statements in the GLSL code in order to make blocks of code only execute for GLSL ES or GLSL,
writing custom C++ code that dynamically creates GLSL / GLSL ES code depending on what you need
simply having two nearly identical copies of all the shaders, one in GLSL and the other in GLSL ES
Example of GLSL vertex shader:
#version 330 core
#define NR_LIGHTS 10
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
out vec3 normalViewSpace;
out vec3 posViewSpace;
out vec2 textureCoords;
out vec4 positionsLightSpace[NR_LIGHTS];
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
uniform mat4 lightMatrices[NR_LIGHTS];
void main()
{
vec4 posViewSpaceV4;
posViewSpaceV4 = viewMatrix * modelMatrix * vec4(position, 1.0);
posViewSpace = posViewSpaceV4.xyz;
gl_Position = projectionMatrix * posViewSpaceV4;
normalViewSpace = mat3(viewMatrix) * normalMatrix * normal;
for( int i = 0; i
Example of GLSL fragment shader:
#version 330 core
#define NR_LIGHTS 10
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
float alpha;
};
struct Light {
vec3 posViewSpace;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
vec3 directionViewSpace;
float cutOff;
float outerCutOff;
sampler2D shadowMap;
};
out vec4 FragColor;
in vec3 normalViewSpace;
in vec3 posViewSpace;
in vec4 positionsLightSpace[NR_LIGHTS];
uniform Material material;
uniform Light lights[NR_LIGHTS];
float shadowCalculation(vec4 posLightSpace, sampler2D shadowMap, Light light)
{
// perform perspective divide
vec3 projCoords = posLightSpace.xyz / posLightSpace.w; // range [-1, 1]
// transform range [0, 1]
projCoords = projCoords * 0.5 + 0.5;
float closestDepth = texture(shadowMap, projCoords.xy).r;
float currentDepth = projCoords.z;
vec3 lightDir = normalize(light.posViewSpace - posViewSpace);
float bias = max(0.00005 * (1.0 - dot(normalViewSpace, lightDir)), 0.000005); // solves shadow acne
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
return shadow;
}
vec3 calcSpotLight( Light light, vec3 normal, vec3 position, float shadow) // normal and position in view space, although this function should not care about which space it's in
{
vec3 result = vec3(0.0, 0.0, 0.0);
vec3 lightDir = normalize(light.posViewSpace - position);
float theta = dot(lightDir, normalize(-light.directionViewSpace));
float epsilon = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); // interpolate between inner and outer cutOff and clamp to 0 and 1
if( intensity > 0 ) // if inside spot radius
{
// attenuation
float distance = length(light.posViewSpace - position);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
if( attenuation > 0.001 )
{
// ambient
vec3 ambient = material.ambient * light.ambient;
// diffuse
vec3 norm = normalize(normalViewSpace);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * material.diffuse * light.diffuse;
// specular
vec3 viewDir = normalize(-position); // in view space the camera is at (0, 0, 0)
vec3 reflectDir = reflect(-lightDir, norm); // reflect function expect vector FROM light source TO position
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = material.specular * spec * light.specular;
// result
result = intensity * attenuation * (ambient + (1.0 - shadow) * (diffuse + specular));
}
}
return result;
}
void main()
{
vec3 result = material.ambient * 0.08;
for( int i = 0; i
I don't have much experience with Shader or GLSL. I am trying to practice with them. To this end I'm trying to port this shader.
https://www.shadertoy.com/view/XsXGR7
Into a project to use with SFML. I am having issue doing this and I'm not sure what to do to start fixing the issues.
I messed around with the uniforms and a few varaiable but the shader itself keeps giving the same error message. That it won't compile. Not sure why, I assume it's because without converting it to work with SFML it's asking for input from OpenGL.
Shader file
uniform vec3 iResolution; // viewport resolution (in pixels)
uniform float iTime; // shader playback time (in seconds)
uniform float iTimeDelta; // render time (in seconds)
uniform int iFrame; // shader playback frame
uniform float iChannelTime[4]; // channel playback time (in seconds)
uniform vec3 iChannelResolution[4]; // channel resolution (in pixels)
uniform vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click
uniform samplerXX iChannel0..3; // input channel. XX = 2D/Cube
uniform vec4 iDate; // (year, month, day, time in seconds)
uniform float iSampleRate; // sound sample rate (i.e., 44100)
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec3 waveParams = vec3( 10.0, 0.8, 0.1 );
vec2 tmp = vec2( iMouse.xy / iResolution.xy );
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 texCoord = uv;
float distance = distance(uv, tmp);
if ( (distance <= ((iTime ) + waveParams.z )) && ( distance >= ((iTime ) - waveParams.z)) )
{
float diff = (distance - (iTime));
float powDiff = 1.0 - pow(abs(diff*waveParams.x), waveParams.y);
float diffTime = diff * powDiff;
vec2 diffUV = normalize(uv - tmp);
texCoord = uv + (diffUV * diffTime);
}
vec4 original = texture( iChannel0, texCoord);
fragColor = original;
}
Currently all the shader does is get loaded in.
shader.loadFromFile("ASSETS/SHADERS/Shockwave1.txt",sf::Shader::Fragment);
//load the shader
if (!shader.isAvailable()) {
std::cout << "The shader is not available\n";
}
Error message trying to load the above shader. No uniforms set, nothing is done with the shader aside from loading it.
Failed to compile fragment shader:
WARNING: 0:1 '' : #version directive missing
ERROR: 0:8 'iChannel0 : syntax error syntax error
Edit:
Having replaced "samplerXX" with "sampler2D" and inserted a void main() function the shader loads properly. Getting the code to work is now the issue.
The Main()
void main(out vec4 fragColor, in vec2 fragCoord )
{
vec3 waveParams = vec3( 10.0, 0.8, 0.1 );
vec2 tmp = vec2( iMouse.xy / iResolution.xy );
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 texCoord = uv;
float distance = distance(uv, tmp);
if ( (distance <= ((iTime ) + waveParams.z )) && ( distance >= ((iTime ) - waveParams.z)) )
{
float diff = (distance - (iTime));
float powDiff = 1.0 - pow(abs(diff*waveParams.x), waveParams.y);
float diffTime = diff * powDiff;
vec2 diffUV = normalize(uv - tmp);
texCoord = uv + (diffUV * diffTime);
}
vec4 original = texture( iChannel0, texCoord);
fragColor = original;
}
This produces these errors
Failed to compile fragment shader:
WARNING: 0:1: '' : #version directive missing
WARNING: 0:32: 'function' : is not available in current GLSL version texture
ERROR: 0:34: 'main' : function cannot take any parameter(s)
WARNING: 0:53: 'function' : is not available in current GLSL version texture
While the main not taking parameters is straightforward I would like to know would values be passed in strictly using uniforms? I am not sure what the 'function' errors relate to.
Edit:
Main()
void main( )
{
vec2 fragCoord = vec2(20,20);
vec3 waveParams = vec3( 10.0, 0.8, 0.1 );
vec2 tmp = vec2( iMouse.xy / iResolution.xy );
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 texCoord = uv;
float distance = distance(uv, tmp);
if ( (distance <= ((iTime ) + waveParams.z )) && ( distance >= ((iTime ) - waveParams.z)) )
{
float diff = (distance - (iTime));
float powDiff = 1.0 - pow(abs(diff*waveParams.x), waveParams.y);
float diffTime = diff * powDiff;
vec2 diffUV = normalize(uv - tmp);
texCoord = uv + (diffUV * diffTime);
}
vec4 original = texture( iChannel0, texCoord);
gl_FragColor = original;
}
Removing the main parameters, hardcode defining vec2 fragCoord as vec2(20,20) made the shader run without issue. My question now is this enough to output the shader effect? (Little experience with glsl, sorry if this is a dumb question)
gl_FragColor = original;
And if it is this seems to be the position of the pixel to be shaded. Is there a way to pass this in automatically?
vec2 fragCoord
I've been following along with the OpenGL 4 Shading Language cookbook and have gotten a teapot rendering with bezier surfaces. The next step I'm attempting is to draw a wireframe over the surfaces using a geometry shader. The directions can be found here on pages 228-230. Following the code that is given, I've gotten the wireframe to display, however, I also have multiple fragments that flicker different shades of my material color.
An image of this can be seen
I have narrowed down the possible issues and have discovered that for some reason, when I perform my triangle height calculations, I am getting variable side lengths for my calculations, as if I hard code the values in the edge distance for each vertex of the triangle within the geometry shader, the teapot no longer flickers, but neither does a wireframe display. (variables ha, hb, hc in the geo shader below)
I was wondering if anyone has run into this issue before or are aware of a workaround.
Below are some sections of my code:
Geometry Shader:
/*
* Geometry Shader
*
* CSCI 499, Computer Graphics, Colorado School of Mines
*/
#version 410 core
layout( triangles ) in;
layout( triangle_strip, max_vertices = 3 ) out;
out vec3 GNormal;
out vec3 GPosition;
out vec3 ghalfwayVec;
out vec3 GLight;
noperspective out vec3 GEdgeDistance;
in vec4 TENormal[];
in vec4 TEPosition[];
in vec3 halfwayVec[];
in vec3 TELight[];
uniform mat4 ViewportMatrix;
void main() {
// Transform each vertex into viewport space
vec3 p0 = vec3(ViewportMatrix * (gl_in[0].gl_Position / gl_in[0].gl_Position.w));
vec3 p1 = vec3(ViewportMatrix * (gl_in[1].gl_Position / gl_in[1].gl_Position.w));
vec3 p2 = vec3(ViewportMatrix * (gl_in[2].gl_Position / gl_in[2].gl_Position.w));
// Find the altitudes (ha, hb and hc)
float a = length(p1 - p2);
float b = length(p2 - p0);
float c = length(p1 - p0);
float alpha = acos( (b*b + c*c - a*a) / (2.0*b*c) );
float beta = acos( (a*a + c*c - b*b) / (2.0*a*c) );
float ha = abs( c * sin( beta ) );
float hb = abs( c * sin( alpha ) );
float hc = abs( b * sin( alpha ) );
// Send the triangle along with the edge distances
GEdgeDistance = vec3( ha, 0, 0 );
GNormal = vec3(TENormal[0]);
GPosition = vec3(TEPosition[0]);
gl_Position = gl_in[0].gl_Position;
EmitVertex();
GEdgeDistance = vec3( 0, hb, 0 );
GNormal = vec3(TENormal[1]);
GPosition = vec3(TEPosition[1]);
gl_Position = gl_in[1].gl_Position;
EmitVertex();
GEdgeDistance = vec3( 0, 0, hc );
GNormal = vec3(TENormal[2]);
GPosition = vec3(TEPosition[2]);
gl_Position = gl_in[2].gl_Position;
EmitVertex();
EndPrimitive();
ghalfwayVec = halfwayVec[0];
GLight = TELight[0];
}
Fragment Shader:
/*
* Fragment Shader
*
* CSCI 441, Computer Graphics, Colorado School of Mines
*/
#version 410 core
in vec3 ghalfwayVec;
in vec3 GLight;
in vec3 GNormal;
in vec3 GPosition;
noperspective in vec3 GEdgeDistance;
layout( location = 0 ) out vec4 FragColor;
uniform vec3 mDiff, mAmb, mSpec;
uniform float shininess;
uniform light {
vec3 lAmb, lDiff, lSpec, lPos;
};
// The mesh line settings
uniform struct LineInfo {
float Width;
vec4 Color;
} Line;
vec3 phongModel( vec3 pos, vec3 norm ) {
vec3 lightVec2 = normalize(GLight);
vec3 normalVec2 = -normalize(GNormal);
vec3 halfwayVec2 = normalize(ghalfwayVec);
float sDotN = max( dot(lightVec2, normalVec2), 0.0 );
vec4 diffuse = vec4(lDiff * mDiff * sDotN, 1);
vec4 specular = vec4(0.0);
if( sDotN > 0.0 ) {
specular = vec4(lSpec * mSpec * pow( max( 0.0, dot( halfwayVec2, normalVec2 ) ), shininess ),1);
}
vec4 ambient = vec4(lAmb * mAmb, 1);
vec3 fragColorOut = vec3(diffuse + specular + ambient);
// vec4 fragColorOut = vec4(0.0,0.0,0.0,0.0);
return fragColorOut;
}
void main() {
// /*****************************************/
// /******* Final Color Calculations ********/
// /*****************************************/
// The shaded surface color.
vec4 color=vec4(phongModel(GPosition, GNormal), 1.0);
// Find the smallest distance
float d = min( GEdgeDistance.x, GEdgeDistance.y );
d = min( d, GEdgeDistance.z );
// Determine the mix factor with the line color
float mixVal = smoothstep( Line.Width - 1, Line.Width + 1, d );
// float mixVal = 1;
// Mix the surface color with the line color
FragColor = vec4(mix( Line.Color, color, mixVal ));
FragColor.a = 1;
}
I ended up stumbling across the solution to my issue. In the geometry shader, I was passing the halfway vector and the light vector after ending the primitive, as such, the values of these vectors was never being correctly sent to the fragment shader. Since no data was given to the fragment shader, garbage values were used and the Phong shading model used random values to compute the fragment color. Moving the two lines after EndPrimative() to the top of the main function in the geometry shader resolved the issue.
I am developing a small OpenGL engine and currently stuck at the following GLSL problem:
I am trying to implement a shader for multiple lights and it generates the correct result but only if I put the calculation of the diffuse light inside an (completely useless) if statement. The specultar light component is always correctly rendered.
Works:
for( int i = 0; i < uNumLights; ++i ) {
//...
if( <anything> == <something> ) {
lDiffuseLight += vAmbientDiffuseMaterial * uLights[i].color * lIntensity;
}
}
Does not work:
for( int i = 0; i < uNumLights; ++i ) {
//...
lDiffuseLight += vAmbientDiffuseMaterial * uLights[i].color * lIntensity;
}
Furthermore it has no effect if I use a constant instead of an uniform for the loop condition.
Why does the code with the if work and without the if not? How can I make my shader work without silly if statements?
The full shader code:
The Vertex Shader:
#version 330
const int MAX_LIGHTS = 4;
in vec3 iVertex;
in vec3 iNormals;
uniform mat4 uModelView;
uniform mat4 uMVP;
uniform mat3 uNormal;
smooth out vec3 vPosition;
smooth out vec3 vModelView;
smooth out vec3 vNormals;
// Colors...
smooth out vec3 vAmbientDiffuseMaterial; // Make some colors...
smooth out vec3 vAmbientLight;
smooth out vec3 vLightDirection[MAX_LIGHTS];
uniform vec3 uAmbientColor;
uniform int uNumLights;
uniform struct Light {
vec3 color;
vec3 position;
} uLights[MAX_LIGHTS];
void main(void) {
vAmbientDiffuseMaterial = clamp(iVertex, 0.0, 1.0);
vAmbientLight = vAmbientDiffuseMaterial * uAmbientColor;
gl_Position = uMVP * vec4( iVertex.xyz, 1.0 );
vPosition = gl_Position.xyz;
vNormals = normalize( uNormal * iNormals );
vModelView = ( uModelView * vec4( iVertex , 1 )).xyz;
for( int i = 0; i < uNumLights; ++i ) {
vLightDirection[i] = normalize( uLights[i].position - vModelView );
}
}
The fragment shader:
#version 330
const int MAX_LIGHTS = 4;
uniform mat4 uModelView;
out vec4 oFinalColor;
smooth in vec3 vPosition;
smooth in vec3 vModelView;
smooth in vec3 vNormals;
smooth in vec3 vAmbientDiffuseMaterial;
smooth in vec3 vAmbientLight;
smooth in vec3 vLightDirection[MAX_LIGHTS];
// Light stuff
uniform int uNumLights;
uniform struct Light {
vec3 color;
vec3 position;
} uLights[MAX_LIGHTS];
const vec3 cSpecularMaterial = vec3( 0.9, 0.9, 0.9 );
const float cShininess = 30.0;
void main(void) {
vec3 lReflection, lSpecularLight = vec3( 0 ), lDiffuseLight = vec3( 0 );
float lIntensity;
// Specular Light
for( int i = 0; i < uNumLights; ++i ) {
lReflection = normalize( reflect( -vLightDirection[i], vNormals) );
lIntensity = max( 0.0, dot( -normalize(vModelView), lReflection ) );
lSpecularLight += cSpecularMaterial * uLights[i].color * pow( lIntensity, cShininess );
// Diffuse Light
lIntensity = max( 0, dot( vNormals, vLightDirection[i] ) );
// Here is the strange if part:
// Only with the if lDiffuseLight is what it is supposed to be.
if( uLights[i].color != vec3( 0, 0, 0 ) ) {
lDiffuseLight += vAmbientDiffuseMaterial * uLights[i].color * lIntensity;
}
}
oFinalColor = vec4( vAmbientLight + lDiffuseLight + lSpecularLight, 1 );
}
I have tested all uniforms and they are all correct set in the shader.
I'm trying to implement normal/steep parallax mapping, but I'm getting some weird artefacts. It looks like the view & light vectors are being distorted when they are transformed into tangent space, which is causing lighting and the uv offsetting of the parallax to be incorrect.
Vertex shader source:
// parallax.vert
#version 330
// Some drivers require the following
precision highp float;
//per vertex inputs stored on GPU memory
in vec3 in_Position;
in vec3 in_Normal;
in vec4 tangent;
//per mesh data sent at rendering time
uniform mat4 model; //object to world space transformations
uniform mat4 view; //world to eye space transformations
uniform mat4 projection; //eye space to screen space
uniform mat3 normalMat; //for transforming normals in
uniform vec4 lightPosition; //light position in world space
uniform vec3 eyePosition; //eye position in world space
//outputs to fragment shader
in vec2 in_TexCoord;
// multiply each vertex position by the MVP matrix
// and find V, L, and TBN Matrix vectors for the fragment shader
out VertexData
{
vec3 ts_L; //view vector tangent space
vec3 ts_V; //light vector tangent space
vec2 ex_TexCoord;
float dist;
} vertex;
void main(void)
{
//view space position for lighting calculations
vec3 position = ( ( view * model ) * vec4( in_Position,1.0 ) ).xyz;
//calculate view vector and light vector in view space
vec3 ex_V = -position;
vec3 ex_L = ( view * vec4( lightPosition.xyz,1.0 ) ).xyz - position;
vertex.ex_TexCoord = in_TexCoord;
//now calculate tbn matrix
//calculate biTangent, in view space
vec3 normal = normalMat*in_Normal;
vec3 tan = normalMat * tangent.xyz;
vec3 bitangent = normalize( cross( normal, tan.xyz ) * tangent.w );
//fragment stage will need this value for calculating light attenuation
vertex.dist = length( ex_L );
//calculate transpose tangent space matrix, as we are doing everything in T space in fragment stage
mat3 transTBN = transpose( mat3( tan, bitangent, normal ) );
//transform view space vertex view & light vectors into tangent space
vertex.ts_V = normalize( transTBN * ex_V );
vertex.ts_L = normalize( transTBN * ex_L );
gl_Position = projection * vec4(position,1.0);
}
fragment shader source:
// parallax.frag
#version 330
// Some drivers require the following
precision highp float;
struct lightStruct
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 position;
float radius;
};
struct materialStruct
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 emissive;
float shininess;
};
//uniforms sent at render time
uniform lightStruct light;
uniform materialStruct material;
uniform vec2 scaleBias;
//texture information
uniform sampler2D colourMap;
uniform sampler2D normalMap;
uniform sampler2D specularMap;
uniform sampler2D heightMap;
uniform sampler2D glossMap;
//inputs from vertex shader stage
in VertexData
{
vec3 ts_L; //view vector tangent space
vec3 ts_V; //light vector tangent space
vec2 ex_TexCoord;
float dist;
} vertex;
//final fragment colour
layout(location = 0) out vec4 out_Color;
void main(void) {
//calculate halfway vector for blinn phong
vec3 Half = normalize( vertex.ts_V + vertex.ts_L );
//and create some temporary types algorithm will need
vec2 texCoord;
vec3 diffuseTexel ;
vec3 specularTexel;
float gloss;
vec3 normal;
//first sample texel value from height map
float height = texture( heightMap, vertex.ex_TexCoord.st ).r;
//-----------------------------------------------
// steep parallax
float start = 1.0;
int numsteps = 50;
float step = 1.0/numsteps;
vec2 offset = vertex.ex_TexCoord;
vec2 delta = -vertex.ts_V.xy * scaleBias.r / (vertex.ts_V.z * numsteps);
for (int i = 0; i < numsteps; i++)
{
if(height < start)
{
start-=step;
offset+=delta;
height = texture(heightMap,offset).r;
}
else
{
texCoord = offset;
break;
}
}
//---------------------------------------------------
//normal maps are encoded with values between 0.0 and 0.5 being negative, so need to remove the encoding.
//sample textures
diffuseTexel = texture(colourMap,texCoord.st).rgb;
specularTexel = texture(specularMap,texCoord.st).rgb;
normal = normalize(texture(normalMap,texCoord.st).rgb * 2.0 - 1.0);
gloss = texture(glossMap,texCoord.st).r;
//--------------------------------------------------
//Lighting -- Blinn/Phong Lighting with specular, normal and gloss mapping
float lambert = max( dot (normal, vertex.ts_L ), 0.0 );
vec3 litColour = vec3(0.0,0.0,0.0);
//if light is worth calculating
if (lambert > 0.0)
{
vec3 R = normalize(-reflect(vertex.ts_L,normal));
float specularPower = pow(max(dot(R,Half),0.0),material.shininess);
litColour += light.diffuse.xyz * material.diffuse.xyz * lambert;
litColour += light.specular.xyz * material.specular.xyz * specularPower * gloss;
float attenuation = 1.0 + (0.01 * vertex.dist*vertex.dist) + (0.01 * vertex.dist);
attenuation = 1.0/attenuation;
litColour *= attenuation;
}
out_Color = vec4( litColour *diffuseTexel*(specularTexel) ,1.0);
}
The normal matrix is being calculated by taking the
transpose( inverse( modelview ) );
I've probably missed something really obvious, but I can't see it, and would be grateful for some input.
Update:
I've modified to perform the lighting & offsetting based on world space vectors, which has now produced the following results:
Lighting is now correct, and the parallax is good when viewed from close to the surface normal, but...
As the angle between view & normal increases, the parallax goes very weird.
Again, I'd be grateful for some help in this.
vec3 ex_V = -position;
Shouldn't this be:
vec3 ex_V = eyePosition - position;