oversaturation in BRDF calculation - glsl

Edit:
In hindsight those images may be correct since it's just showing the vector differences, so assuming it's correct the issue is actually somewhere in the code regarding BRDF . I've added the full shader code and I'm attaching a new screenshot showing the artifacts I'm seeing. It seems to be over saturated in certain angles..
The issue is potentially in the distribution.. I tried a beckmann distribution model also and it showed the same type of issue..
See here as the light source moves down over the terrain from .. It's over saturating on the right hand side..
light at horizon
light just above horizon
I'm having some issues calculating directions in the vertex shader, the direction is skewed to one corner (the origin)
I create the terrain using instancing however the same issue happens if I just use a static plane.
my vertex shader looks like this (using ogre3d)
# version 330 compatibility
# define MAP_HEIGHT_FACTOR 50000
# define MAP_SCALE_FACTOR 100
#
// attributes
in vec4 blendIndices;
in vec4 uv0;
in vec4 uv1;
in vec4 uv2;
in vec4 position;
in vec2 vtx_texcoord0;
uniform mat4 viewProjMatrix;
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 worldMatrix;
uniform vec3 cameraPosition;
uniform vec3 sunPosition;
out vec4 vtxPosWorld;
out vec3 lightDirection;
out vec3 viewVector;
uniform sampler2D heightmap;
uniform mat4 worldViewProjMatrix;
void main()
{
vec4 vtxPosWorld = vec4((gl_Vertex.x * MAP_SCALE_FACTOR) + uv0.w,
(gl_Vertex.y * MAP_SCALE_FACTOR) + uv1.w,
(gl_Vertex.z * MAP_SCALE_FACTOR) + uv2.w,
1.0 ) * worldMatrix;
l_texcoord0 = vec2((vtxPosWorld.x)/(8192*MAP_SCALE_FACTOR), (vtxPosWorld.z)/(8192*MAP_SCALE_FACTOR));
vec4 hmt = texture(heightmap, l_texcoord0);
height = (hmt.x * MAP_HEIGHT_FACTOR);
// take the height from the heightmap
vtxPosWorld = vec4(vtxPosWorld.x, height, vtxPosWorld.z, vtxPosWorld.w);
lightDirection = vec4(normalize(vec4(sunPosition,1.0)) * viewMatrix).xyz;
viewVector = normalize((vec4(cameraPosition,1.0)*viewMatrix).xyz-(vtxPosWorld*viewMatrix).xyz);
l_Position = worldViewProjMatrix * vtxPosWorld;
}
fragment shader .
#version 330 compatibility
#define TERRAIN_SIZE 8192.0
#define HEIGHT_SCALE_FACTOR 50000
#define MAP_SCALE_FACTOR 100
#define M_PI 3.1415926535897932384626433832795
in vec2 l_texcoord0;
in vec4 vtxPosWorld;
in vec3 viewVector;
uniform vec3 sunPosition;
uniform vec3 cameraPosition;
uniform sampler2D heightmap;
float G1V(float dotP, float k)
{
return 1.0f/(dotP*(1.0f-k)+k);
}
float calcBRDF(vec3 normal, float fresnel, float MFD, vec3 sunColor) {
float F = fresnel;
vec3 Nn = normalize(normal.xyz);
vec3 Vn = viewVector;
vec3 Ln = lightDirection;
vec3 Hn = normalize(viewVector + lightDirection);
float NdotV = max(dot(Nn,Vn),0.0);
float NdotL = max(dot(Nn,Ln),0.0);
float NdotH = max(dot(Nn,Hn),0.1);
float VdotH = max(dot(Vn,Hn),0.0);
float LdotH = max(dot(Ln,Hn),0.0);
// Microfacet Distribution
float denom, alpha, beckmannD, GGXD;
float NdotHSqr = NdotH * NdotH;
float alphaSqr = MFD*MFD;
// GGX distribution (better performance)
denom = NdotHSqr * ( alphaSqr-1.0 ) + 1.0f;
GGXD = alphaSqr/(M_PI * pow(denom,2));
float k = MFD/2.0f;
float GGX = G1V(NdotL,k) * G1V(NdotV,k);
return GGXSpecular = F * GGXD * GGX;
}
float calcFresnel(float R) {
vec3 Hn = normalize(viewVector + lightDirection);
vec3 Vn = viewVector;
vec3 Ln = lightDirection;
float VdotH = dot(Vn,Hn);
float NdotL = dot(Hn,Vn);
float fresnel = R + (1-R)*pow((1-NdotL),5);
return fresnel;
}
vec3 calcNormal(sampler2D heightmap, vec2 texcoord) {
const vec2 size = vec2(MAP_SCALE_FACTOR,0.0);
vec3 off = ivec3(1,0,1)/TERRAIN_SIZE;
float hL = texture2D(heightmap, texcoord - off.xy).x*HEIGHT_SCALE_FACTOR;
float hR = texture2D(heightmap, texcoord + off.xy).x*HEIGHT_SCALE_FACTOR;
float hD = texture2D(heightmap, texcoord - off.yz).x*HEIGHT_SCALE_FACTOR;
float hU = texture2D(heightmap, texcoord + off.yz).x*HEIGHT_SCALE_FACTOR;
vec3 va = normalize(vec3(size.xy,(hL-hR)));
vec3 vb = normalize(vec3(size.yx,(hD-hU)));
return vec3(1.0,1.0,1.0);
return normalize(cross(va,vb)/2 + 0.5);
}
void main()
{
vec3 normal = calcNormal(heightmap, l_texcoord0);
float N = 1.69;
float microFacetDistribution = 1.5;
vec3 sunColor = vec3(1.0,1.0,1.0);
float Rfactor = calcFresnelReflectance(N);
float fresnel = calcFresnel(Rfactor);
float brdf = calcBRDF(normal,fresnel,microFacetDistribution,sunColor);
float conservedBrdf = clamp(brdf,0.0,fresnel);
gl_FragColor.rgb = vec4(0.5,0.5,0.5,1.0)*conservedBrdf;
}
I've tried using viewspace, worldspace etc.. It seems like a simple/silly problem, but I can't figure it out :|
Any suggestions appreciated..

Of course the answer was something silly.
First of all the normals were incorrect. That caused a skew in the light direction which made the light appear to be hitting on one direction only.
Secondly the light direction itself needed to be negated.

Related

How to fix improperly distributed lighting projected onto a model in OpenGL?

I've been trying to implement the Blinn-Phong lighting model to project lighting onto an imported Wavefront OBJ model through Assimp(github link).
The model seems to be loaded correctly, however, there seems to be a point where the lighting appears to be "cut off" near the middle of the model.
Image of the imported model with and without lighting enabled.
As you can see on the left of the image above, there is a region in the middle of the model where the light effectively gets "split up" which is not what is intended. It can be seen that there is a sort of discrepancy where the side facing towards the light source appears brighter than normal and the side away from the light source appears darker than normal without any sort of easing in between the two sides.
I believe there might be something wrong with how I've implemented the lighting model in the fragment shader but I cannot say for sure as to why this is happening.
Vertex shader:
#version 330 core
layout (location = 0) in vec3 vertPos;
layout (location = 1) in vec3 vertNormal;
layout (location = 2) in vec2 vertTexCoords;
out vec3 fragPos;
out vec3 fragNormal;
out vec2 fragTexCoords;
uniform mat4 proj, view, model;
uniform mat3 normalMat;
void main() {
fragPos = vec3(model * vec4(vertPos, 1));
gl_Position = proj * view * vec4(fragPos, 1);
fragTexCoords = vertTexCoords;
fragNormal = normalMat * vertNormal;
}
Fragment shader:
#version 330 core
in vec3 fragPos;
in vec3 fragNormal;
in vec2 fragTexCoords;
out vec4 FragColor;
const int noOfDiffuseMaps = 1;
const int noOfSpecularMaps = 1;
struct Material {
sampler2D diffuseMaps[noOfDiffuseMaps], specularMaps[noOfSpecularMaps];
float shininess;
};
struct Light {
vec3 direction;
vec3 ambient, diffuse, specular;
};
uniform Material material;
uniform Light light;
uniform vec3 viewPos;
const float pi = 3.14159265;
uniform float gamma = 2.2;
float near = 0.1;
float far = 100;
float LinearizeDepth(float depth)
{
float z = depth * 2 - 1;
return (2 * near * far) / (far + near - z * (far - near));
}
void main() {
vec3 normal = normalize(fragNormal);
vec3 calculatedColor = vec3(0);
for (int i = 0; i < noOfDiffuseMaps; i++) {
vec3 diffuseTexel = texture(material.diffuseMaps[i], fragTexCoords).rgb;
// Ambient lighting
vec3 ambient = diffuseTexel * light.ambient;
// Diffuse lighting
float diff = max(dot(light.direction, normal), 0);
vec3 diffuse = diffuseTexel * light.diffuse * diff;
calculatedColor += ambient + diffuse;
}
for (int i = 0; i < noOfSpecularMaps; i++) {
vec3 specularTexel = texture(material.specularMaps[0], fragTexCoords).rgb;
vec3 viewDir = normalize(viewPos - fragPos);
vec3 halfWayDir = normalize(viewDir + light.direction);
float energyConservation = (8 + material.shininess) / (8 * pi);
// Specular lighting
float spec = pow(max(dot(halfWayDir, normal), 0), material.shininess);
vec3 specular = specularTexel * light.specular * spec * energyConservation;
calculatedColor += specular;
}
float depthColor = 1 - LinearizeDepth(gl_FragCoord.z) / far;
FragColor = vec4(pow(calculatedColor, vec3(1 / gamma)) * depthColor, 1);
}
Make sure your texture and colors are also linear(it is a simple pow 2.2) because you are doing gamma encoding at the end.
Also note, it is expected to have a harsh terminator.
http://filmicworlds.com/blog/linear-space-lighting-i-e-gamma/
Beyond that, if you expect soft falloffs, it must be coming from an area light. For that you can implement wrap lighting or area lights.

GLSL multi-texturing- blending textures

I'm trying to implement multi-texturing in OpenGL. The texture used is based on the surface normal of a given vertex- The more vertical it is, the more of the second texture is visible.
Here is what I have so far.
I want to blend the edges together now rather than having that hard edge. Is it possible to blend the textures in this way? if so how do I do that?
This is my fragment shader code:
#version 150
in vec2 pass_textureCoords;
in vec3 surfaceNormal;
in vec3 toLightVector;
in vec3 toCamera;
in vec3 playerPosition;
in vec4 vertexPosition;
in float blendPosition;
in float visibility;
out vec4 out_Color;
uniform sampler2D texture0;
uniform sampler2D texture1;
uniform vec3 skyColour;
uniform vec3 light_colour;
uniform float shineDamper;
uniform float reflectivity;
void main(void){
vec3 unitNormal = normalize(surfaceNormal);
vec3 unitLightVector = normalize(toLightVector);
float nDot1 = dot(unitNormal,unitLightVector);
float brightness = max(nDot1,0.2);
vec3 diffuse = brightness * light_colour;
vec3 unitToCamera = normalize(toCamera);
vec3 lightDirection = -unitLightVector;
vec3 reflectedLightDirection = reflect(lightDirection,unitNormal);
float specular = dot(reflectedLightDirection, unitToCamera);
specular = max(specular,0.0);
float damped = pow(specular,shineDamper);
vec3 finalSpecular = damped * reflectivity * light_colour;
out_Color = (vec4(diffuse,1.0) * texture(texture0,pass_textureCoords)) + vec4(-20,-20,0.0,0.0);
out_Color = (vec4(diffuse,1.0) * texture(texture0,pass_textureCoords));
out_Color = mix(vec4(skyColour,1.0),out_Color,visibility);
if(vertexPosition.y < -6.1 || surfaceNormal.y < 0.6){
out_Color = (vec4(diffuse,1.0) * texture(texture1,pass_textureCoords)) + vec4(-20,-20,0.0,0.0);
out_Color = (vec4(diffuse,1.0) * texture(texture1,pass_textureCoords));
out_Color = mix(vec4(diffuse,1.0) * texture(texture0,pass_textureCoords),out_Color,1);
out_Color = mix(vec4(skyColour,1.0),out_Color,visibility);
}
if(playerPosition.y < -6.1){
out_Color = mix(vec4(0.0,0.3,0.5,1.0),out_Color,0.1);
}
}
EDIT:
This is the new fragment shader code for anyone interested
Updated fragment shader code:
#version 150
in vec2 pass_textureCoords;
in vec3 surfaceNormal;
in vec3 toLightVector;
in vec3 toCamera;
in vec3 playerPosition;
in vec4 vertexPosition;
in float blendPosition;
in float visibility;
out vec4 out_Color;
uniform sampler2D texture0;
uniform sampler2D texture1;
uniform vec3 skyColour;
uniform vec3 light_colour;
uniform float shineDamper;
uniform float reflectivity;
void main(void){
vec3 unitNormal = normalize(surfaceNormal);
vec3 unitLightVector = normalize(toLightVector);
float nDot1 = dot(unitNormal,unitLightVector);
float brightness = max(nDot1,0.2);
vec3 diffuse = brightness * light_colour;
vec3 unitToCamera = normalize(toCamera);
vec3 lightDirection = -unitLightVector;
vec3 reflectedLightDirection = reflect(lightDirection,unitNormal);
float specular = dot(reflectedLightDirection, unitToCamera);
specular = max(specular,0.0);
float damped = pow(specular,shineDamper);
vec3 finalSpecular = damped * reflectivity * light_colour;
out_Color.a = 1;
vec4 fog = vec4(skyColour,1.0);
vec4 diffusion = vec4(diffuse,1.0);
float a = clamp((unitNormal.y - .6)*5 + .5, 0, 0.7);
vec3 texture0_colour = (mix(fog,diffusion * texture(texture0,pass_textureCoords),visibility)).rgb;
vec3 texture1_colour = (mix(fog,diffusion * texture(texture1,pass_textureCoords),visibility)).rgb;
out_Colour.rgb = mix(texture1_colour,texture0_colour,a);
}
To mix two texture based on a value a you do:
float a = ...;
vec3 color0 = texture(texture0, pass_textureCoords).rgb;
vec3 color1 = texture(texture1, pass_textureCoords).rgb;
out_Color.rgb = mix(color0, color1, a);
Assuming that your unitNormal = (0,1,0) is the upwards direction, as it appears from the code, then the value of
float a = clamp(unitNormal.y, 0, 1);
will result in a smooth transition between the two textures. However, you probably want a sharper transition, in which case you shift and scale the unitNormal.y value to adjust where the transition starts and ends:
float a = clamp((unitNormal.y - .6)*5 + .5, 0, 1);

Spotlight with shadows becomes square-like

I've been following a two part tutorial on shadow mapping from OGLDev (part 1, part 2) for a couple of days now, and I've nearly finished implementing it.
My problem is that when I enable shadow maps the illuminated region which shadows appear in appears as a "strip" and I'm unsure if this is intended in the tutorials or not.
Perhaps images will help explain my problem.
However shadows are functional:
My vertex shader for spotlights:
#version 330
in vec2 textureCoordinate;
in vec4 vertex;
uniform mat4 mMatrix;
uniform mat4 pMatrix;
uniform mat4 vMatrix;
uniform mat4 lightV;
uniform mat4 lightP;
uniform vec3 normal;
uniform vec3 eye;
out vec2 TexCoord0;
out vec4 LightSpacePos;
out vec3 Normal0;
out vec3 WorldPos0;
out vec3 EyePos;
void main()
{
EyePos = eye;
TexCoord0 = textureCoordinate;
WorldPos0 = (mMatrix * vertex).xyz;
Normal0 = (mMatrix * vec4(normal, 0.0)).xyz;
mat4 lightMVP = lightP * inverse(lightV) * mMatrix;
LightSpacePos = lightMVP * vertex;
mat4 worldMVP = pMatrix * vMatrix * mMatrix;
gl_Position = worldMVP * vertex;
}
and the fragment shader:
#version 330
struct BaseLight
{
vec4 color;
float intensity;
};
struct Attenuation
{
float constant;
float linear;
float exponent;
};
struct PointLight
{
BaseLight base;
Attenuation atten;
vec3 position;
float range;
};
struct SpotLight
{
struct PointLight base;
vec3 direction;
float cutoff;
};
in vec2 TexCoord0;
in vec3 WorldPos0;
in vec3 EyePos;
in vec4 LightSpacePos;
out vec4 fragColor;
uniform sampler2D sampler;
uniform sampler2D shadowMap;
in vec3 Normal0;
uniform float specularIntensity;
uniform float specularPower;
uniform SpotLight spotLight;
float CalcShadowFactor(vec4 LightSpacePos)
{
vec3 ProjCoords = LightSpacePos.xyz / LightSpacePos.w;
vec2 UVCoords;
UVCoords.x = 0.5 * ProjCoords.x + 0.5;
UVCoords.y = 0.5 * ProjCoords.y + 0.5;
float z = 0.5 * ProjCoords.z + 0.5;
float Depth = texture(shadowMap, UVCoords).x;
if (Depth < z + 0.00001)
return 0.5;
else
return 1.0;
}
vec4 CalcLightInternal(BaseLight Light, vec3 LightDirection, vec3 Normal, float ShadowFactor)
{
vec4 AmbientColor = Light.color * Light.intensity;
float DiffuseFactor = dot(Normal, -LightDirection);
vec4 DiffuseColor = vec4(0, 0, 0, 0);
vec4 SpecularColor = vec4(0, 0, 0, 0);
if (DiffuseFactor > 0) {
DiffuseColor = Light.color * Light.intensity * DiffuseFactor;
vec3 VertexToEye = normalize(EyePos - WorldPos0);
vec3 LightReflect = normalize(reflect(LightDirection, Normal));
float SpecularFactor = dot(VertexToEye, LightReflect);
SpecularFactor = pow(SpecularFactor, specularPower);
if (SpecularFactor > 0) {
SpecularColor = Light.color * specularIntensity * SpecularFactor;
}
}
return (AmbientColor + ShadowFactor * (DiffuseColor + SpecularColor));
}
vec4 CalcPointLight(PointLight l, vec3 Normal, vec4 LightSpacePos)
{
vec3 LightDirection = WorldPos0 - l.position;
float Distance = length(LightDirection);
LightDirection = normalize(LightDirection);
float ShadowFactor = CalcShadowFactor(LightSpacePos);
vec4 Color = CalcLightInternal(l.base, LightDirection, Normal, ShadowFactor);
float Attenuation = l.atten.constant +
l.atten.linear * Distance +
l.atten.exponent * Distance * Distance;
return Color / Attenuation;
}
vec4 CalcSpotLight(SpotLight l, vec3 Normal, vec4 LightSpacePos)
{
vec3 LightToPixel = normalize(WorldPos0 - l.base.position);
float SpotFactor = dot(LightToPixel, l.direction);
if (SpotFactor > l.cutoff) {
vec4 Color = CalcPointLight(l.base, Normal, LightSpacePos);
return Color * (1.0 - (1.0 - SpotFactor) * 1.0/(1.0 - l.cutoff));
}
else {
return vec4(0,0,0,0);
}
}
void main(void)
{
fragColor = texture2D(sampler, TexCoord0.xy) * CalcSpotLight(spotLight, normalize(Normal0), LightSpacePos);
}
This is intended. Since your shadowmap covers a pyramid-like region in space, your spotlight's cone can be occluded by it. This is happening because where you render something that is outside of the shadow camera's view, it will be considered unlitten. Therefore the shadow camera's view pyramid will be visible.
src
To fix this you have 2 options:
1: Make the shadowmap camera's fov bigger, so that the shadow camera's pyramid becomes wider than your spotlight's cone
2: Change the way you calculate shadows on out-of-bounds area. Currently when you sample the shadowmap, and if it's outside of the shadow texture, you apply shadow there. If you change this so that if something that is out of the shadow texture you consider it litten, this problem will disappear.
Edit:
I recommend the second option. A solution for that could be:
Insert the following line into FragmentShader::CalcShadowFactor(), just before the float Depth = ... part
if (UVCoords.x < 0.0 || UVCoords.x > 1.0 || UVCoords.y < 0.0 || UVCoords.y > 1.0) return 1.0;
Note:
There is no universal way to say which is better. In a terrain environment involving sunlight, you may want to consider out-of-bounds regions as litten. However when you use a flashlight for example, that is in the user's hand, you have to consider out-of-bounds regions as unlitten.

Normal mapping GLSL using LibGDX

I try to implement normal mapping using LibGDX. So I got some positive results when I calculate diffuse and specular color in vertex shader (at least I think so).
Vertex shader:
attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec3 a_normal;
varying vec2 v_texCoord;
varying float v_diffuse;
varying vec3 v_specular;
varying vec3 v_lightVec;
uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;
uniform mat4 u_matViewInverseTranspose;
uniform mat4 u_matModelView;
const vec3 lightVector = vec3(0.0,0.0,-1.0);
void main()
{
// Output the unmodified vertex position.
gl_Position = u_projTrans * u_worldTrans * a_position;
mat3 normalMatrix = mat3(u_matViewInverseTranspose);
// compute the transformed normal
vec3 n = normalize(normalMatrix * a_normal);
// compute the light vector pointing toward the sun, in model coordinates
// x,y compose the longitude and z the (seasonal) lattitude of the nadir point.
//vec3 lightVec = normalize(vec3(u_matViewInverseTranspose * vec4(u_lightVec, 1.0)));
vec3 lightVec = normalize(normalMatrix * lightVector);
// Calculate a diffuse light intensity
//v_diffuse = dot(lightVec, n);
v_diffuse = clamp(dot(n, lightVec), 0.0, 1.0);
vec4 ecPosition = u_matModelView * a_position;
// compute the reflection vector
vec3 reflectVec = reflect(-lightVec, n);
// compute a unit vector in direction of viewing position
vec3 viewVec = normalize(vec3(-ecPosition));
// Calculate specular light intensity, scale down and apply a tint.
float specIntensity = pow(max(dot(reflectVec, viewVec), 0.0), 8.0);
v_specular = specIntensity *
//gloss color
vec3(1.,.7,.3) *
//gloss intensity
.7;
v_texCoord.y = 1.-a_texCoord0.y;
v_texCoord.x = a_texCoord0.x;
vec3 lightDir = normalize(lightVector - u_matModelView * a_position);
vec3 tangent=a_tangent;
vec3 t = normalize(normalMatrix * tangent);
vec3 b = cross (n, t);
vec3 v;
v.x = dot (lightDir, t);
v.y = dot (lightDir, b);
v.z = dot (lightDir, n);
v_lightVec = normalize (v);
}
Fragment shader:
precision mediump float;
varying vec2 v_texCoord;
varying float v_diffuse;
varying vec3 v_specular;
varying vec3 v_lightVec;
uniform sampler2D u_texture;
uniform sampler2D u_normalMap;
void main()
{
vec3 ground = texture2D(u_texture, v_texCoord).rgb;
vec3 normal = normalize(2.0 * texture2D (u_normalMap, v_texCoord).rgb - 1.0);
float lamberFactor = max (dot (normal, v_lightVec), 0.0);
vec3 color = ( ground.rgb * v_diffuse * lamberFactor + v_specular);
gl_FragColor = vec4 (color, 1.0);
}
Result:
As you can see the result is rendered correctly. Specular spot behaves like from many examples. But I need to implement specular color in fragment shader to get more impressive picture. So I found example from here and now I'm trying to make it works.
Vertex shader:
attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec3 a_normal;
attribute vec3 a_tangent;
varying vec2 v_texCoord;
varying vec3 v_lightVec;
varying vec3 v_eyeVec; //Added
uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;
uniform mat4 u_matViewInverseTranspose;
uniform mat4 u_matModelView;
const vec3 lightVector = vec3(0.0,0.0,-1.0);
void main()
{
// Output the unmodified vertex position.
gl_Position = u_projTrans * u_worldTrans * a_position;
mat3 normalMatrix = mat3(u_matViewInverseTranspose);
// compute the transformed normal
vec3 n = normalize(normalMatrix * a_normal);
v_texCoord.y = 1.-a_texCoord0.y;
v_texCoord.x = a_texCoord0.x;
vec3 lightDir = normalize(lightVector - u_matModelView * a_position);
vec3 tangent=a_tangent;
vec3 t = normalize(normalMatrix * tangent);
vec3 b = cross (n, t);
vec3 v;
v.x = dot (lightDir, t);
v.y = dot (lightDir, b);
v.z = dot (lightDir, n);
v_lightVec = normalize (v);
//Added
vec3 ecPosition = u_matModelView * a_position;
vec3 tmp = vec3(-ecPosition);
v_eyeVec.x = dot(tmp, t);
v_eyeVec.y = dot(tmp, b);
v_eyeVec.z = dot(tmp, n);
v_eyeVec = normalize (v_eyeVec);
}
Fragment shader:
precision mediump float;
varying vec2 v_texCoord;
varying vec3 v_lightVec;
varying vec3 v_eyeVec;
uniform sampler2D u_texture;
uniform sampler2D u_normalMap;
void main()
{
vec3 ground = texture2D(u_texture, v_texCoord).rgb;
vec3 normal = normalize(2.0 * texture2D (u_normalMap, v_texCoord).rgb - 1.0);
//Added
float distSqr = dot(v_lightVec, v_lightVec);
float att = clamp(1.0 - .25 * sqrt(distSqr), 0.0, 1.0);
vec3 lVec = v_lightVec * inversesqrt(distSqr);
vec3 vVec = normalize(v_eyeVec);
vec3 bump = normalize( texture2D(u_normalMap, v_texCoord).xyz * 2.0 - 1.0);
float diffuse = max( dot(lVec, bump), 0.0 );
vec3 specular = pow(clamp(dot(reflect(-lVec, bump), v_eyeVec), 0.0, 1.0), 8.0 ) *
//gloss color
vec3(1.,.7,.3) *
//gloss intensity
.7;
vec3 color = ( ground.rgb * diffuse + specular) * att;
gl_FragColor = vec4 (color, 1.0);
}
Result:
Specular spot is wrong. I thought it happens because of wrong matrix calculation. If it's true why do first couple of shaders work correctly?
How do I get model-view matrix, normal matrix and others in LibGDX?
viewInvTraMatrix.set(camera.view);
viewInvTraMatrix.mul(renderable.worldTransform);
//model-view matrix
program.setUniformMatrix("u_matModelView", viewInvTraMatrix);
viewInvTraMatrix.inv(); //inverse
viewInvTraMatrix.tra(); //transpose
//normal matrix
program.setUniformMatrix("u_matViewInverseTranspose", viewInvTraMatrix);
//other matrix
program.setUniformMatrix("u_worldTrans", renderable.worldTransform);
program.setUniformMatrix("u_projTrans", camera.combined);
So, my question is what is wrong in the last couple of shaders?
The problem was in my model(mesh). After some time of digging I found out that my mesh doesn't have tangents and binormals. It happend because I used Blender 2.58 which cannot export model to FBX with tangent space. Fortunately, they fixed this bug in Blender 2.71 and later. So, when you export your model, you should tick Tangent Space parameter and choose version FBX 7.4 binary. To ensure that your mesh contains tangents and binormals, you can use fbx-converter tool to convert your fbx file to g3dj format instead of default g3db by using additional option like below:
fbx-converter.exe -o g3dj yourModel.fbx yourConvertedModel.g3dj
Then open it in some program like Notepad and check that attributes contain TANGENT and BINORMAL
"version": [ 0, 1],
"id": "",
"meshes": [
{
"attributes": ["POSITION", "NORMAL", "TANGENT", "BINORMAL", "TEXCOORD0"],
"vertices": [
0.257400, 58.707802, -0.257400, 0.000000, 1.000000, -0.000000, 0.941742,
Only one thing I don't understand, why does lamberFactor work with wrong tangent attribute(actually, without it)? Most likely, diffuse color is wrong calculated, but in my example(on sphere) it looks pretty satisfactorily. I hope it will help somebody else.
EDIT
By the way, to get a normal & a model-view matrices, I use the following code:
myMatrix.set(camera.view);
myMatrix.mul(renderable.worldTransform);
program.setUniformMatrix(u_matModelView, myMatrix); //pass model-view matrix
myMatrix.inv();
myMatrix.tra();
program.setUniformMatrix(u_matNormal, myMatrix); //pass normal matrix

Syntax error in GLSL - unexpected NEW_IDENTIFIER

I have been writing a shading language that is meant to simplify writing GLSL. Because of this, I can't really rely on line numbers given by the GLSL compiler. I therefore can't find what this error is trying to say. What does it mean first of all, and then how can I fix it?
Error code:
0:8(18): error: syntax error, unexpected NEW_IDENTIFIER, expecting '{'
I believe that this just means there is a syntax error with the generated GLSL, but I can't find one. What does this error message actually mean?
-- EDIT --
Sorry for not providing code, I wanted to know what the error meant so I could provide the relevant areas of code.
Generated vertex shader:
#version 120
attribute vec3 position;
attribute vec2 texCoord;
attribute vec3 normal;
attribute vec3 tangent;
varying vec2 fragTexCoords;
varying vec3 worldPos;
varying vec4 shadowMapCoords;
varying mat3 tbnMatrix;
uniform mat4 modelMatrix;
uniform mat4 MVPMatrix;
uniform mat4 lightMatrix;
void main() {
gl_Position = MVPMatrix * vec4(position, 1);
fragTexCoords = texCoord;
shadowMapCoords = lightMatrix * vec4(position, 1);
worldPos = (modelMatrix * vec4(position, 1)).xyz;
vec3 n = normalize((modelMatrix * vec4(normal, 0)).xyz);
vec3 t = normalize((modelMatrix * vec4(tangent, 0)).xyz);
t = normalize(t - dot(t, n) * n);
vec3 biTangent = cross(t, n);
tbnMatrix = mat3(t, biTangent, n);
}
And the generated fragment shader:
#version 120
varying vec2 fragTexCoords;
varying vec3 worldPos;
varying vec4 shadowMapCoords;
varying mat3 tbnMatrix;
uniform Material material;
uniform Light light;
uniform vec3 eyePos;
uniform sampler2D shadowMap;
uniform float shadowVarianceMin;
uniform float shadowLightBleedReduction;
bool inRange(float value) {
return value >= 0 && value <= 1;
}
float linStep(float low, float high, float v) {
return clamp((v - low) / (high - low), 0, 1);
}
vec2 calcParallaxTexCoords(sampler2D dispMap, mat3 tbnMatrix, vec3 directionToEye, vec2 texCoords, float scale, float bias) {
return texCoords.xy + (directionToEye * tbnMatrix).xy * (texture2D(dispMap, texCoords.xy).r * scale + bias);
}
float sampleShadowMap(sampler2D shadowMap, vec2 coords, float compare) {
return step(compare, texture2D(shadowMap, coords.xy).r);
}
float sampleVarianceShadowMap(sampler2D shadowMap, vec2 coords, float compare, float varianceMin, float lightBleedReduction) {
vec2 moments = texture2D(shadowMap, coords.xy).xy;
float p = step(compare, moments.x);
float variance = max(moments.y - moments.x * moments.x, varianceMin);
float d = compare - moments.x;
float pMax = linStep(lightBleedReduction, 1, variance / (variance + d * d));
return min(max(p, pMax), 1);
}
struct Light {
vec3 color;
float intensity;
vec3 direction;
};
struct Material {
float roughness;
float fresnelReflectance;
sampler2D diffuseTexture;
sampler2D normalMap;
sampler2D dispMap;
float dispMapScale;
float dispMapBias;
};
vec3 calcLight(Light light, Material material, vec3 surfaceNormal, vec3 eyePos, vec3 diffuseColor, vec3 specularColor) {
vec3 halfVector = normalize(light.direction + eyePos);
float NdotL = clamp(dot(surfaceNormal, light.direction), 0.0, 1.0);
float NdotH = clamp(dot(surfaceNormal, halfVector), 0.0, 1.0);
float NdotV = clamp(dot(surfaceNormal, eyePos), 0.0, 1.0);
float VdotH = clamp(dot(eyePos, halfVector), 0.0, 1.0);
float rSq = material.roughness * material.roughness;
// ----- Fresnel term -----
float fresnel = pow(1 - VdotH, 5.0);
fresnel *= 1 - material.fresnelReflectance;
fresnel += material.fresnelReflectance;
// ----- Geometric attenuation term -----
float geoNum = 2.0 * NdotV;
float geoB = (geoNum * NdotV) / VdotH;
float geoC = (geoNum * NdotL) / VdotH;
float geo = min(1.0, min(geoB, geoC));
// ----- Roughness term -----
float roughnessA = rSq * pow(NdotH, 4.0);
float roughnessB = (NdotH * NdotH - 1.0) / (rSq * NdotH * NdotH);
float roughness = 1.0 / roughnessA * exp(roughnessB);
// ----- Cook-Torrance calculation -----
vec3 specular = vec3(fresnel * roughness * geo) / (NdotV * NdotL);
return max(0.0, NdotL) * (specularColor * specular + diffuseColor);
}
float calcShadowAmount(sampler2D shadowMap, vec4 initialShadowMapCoords) {
vec3 shadowMapCoords = (initialShadowMapCoords.xyz / initialShadowMapCoords.w);
if (inRange(shadowMapCoords.x) && inRange(shadowMapCoords.y) && inRange(shadowMapCoords.z)) {
return sampleVarianceShadowMap(shadowMap, shadowMapCoords.xy, shadowMapCoords.z, shadowVarianceMin, shadowLightBleedReduction);
} else {
return 1.0;
}
}
float calcBasicShadowAmount(sampler2D shadowMap, vec4 initialShadowMapCoords) {
vec3 shadowMapCoords = (initialShadowMapCoords.xyz / initialShadowMapCoords.w);
return sampleShadowMap(shadowMap, shadowMapCoords.xy, shadowMapCoords.z);
}
void main() {
vec3 directionToEye = normalize(eyePos - worldPos);
vec2 texCoords = calcParallaxTexCoords(dispMap, tbnMatrix, directionToEye, fragTexCoords, dispMapScale, dispMapBias);
vec3 normal = normalize(tbnMatrix * (255.0 / 128.0 * texture2D(normalMap, texCoords).xyz - 1));
gl_FragColor = calcLight(light, material, normal, eyePos, texture2D(diffuse, texCoords), vec3(1, 1, 1));
}
GLSL error reporting conventions are vendor-specific and thus difficult to parse. However, in this case 0:8(18): error: syntax error, unexpected NEW_IDENTIFIER, expecting '{' refers to line 8, character 18.
If you look at your fragment shader, on line 8 you have the following:
uniform Material material;
^ char. 18
The problem here is that you have not yet defined the structure of Material.
You will need to move these structs to precede your uniforms:
struct Light {
vec3 color;
float intensity;
vec3 direction;
};
struct Material {
float roughness;
float fresnelReflectance;
sampler2D diffuseTexture;
sampler2D normalMap;
sampler2D dispMap;
float dispMapScale;
float dispMapBias;
};