I'd like to render object to see the inside of the box.
I used Phong Shading.
When I draw object with glPolygonMode(GL_FRONT_AND_BACK, GL_LINE), an image looks like this:
But When I used glPolygonMode(GL_FRONT_AND_BACK, GL_FILL), the image looks like this:
I'd like to shade only rectangle part. So I want to see the objects inside the box. This is fragment shade code, and I think it works well. But I don't know why i can't see inside.
#version 400
struct LIGHT {
vec4 position; // assume point or direction in EC in this example shader
vec4 ambient_color, diffuse_color, specular_color;
vec4 light_attenuation_factors; // compute this effect only if .w != 0.0f
vec3 spot_direction;
float spot_exponent;
float spot_cutoff_angle;
bool light_on;
};
struct MATERIAL {
vec4 ambient_color;
vec4 diffuse_color;
vec4 specular_color;
vec4 emissive_color;
float specular_exponent;
};
uniform vec4 u_global_ambient_color;
#define NUMBER_OF_LIGHTS_SUPPORTED 4
uniform LIGHT u_light[NUMBER_OF_LIGHTS_SUPPORTED];
uniform MATERIAL u_material;
const float zero_f = 0.0f;
const float one_f = 1.0f;
in vec3 v_position_EC;
in vec3 v_normal_EC;
layout (location = 0) out vec4 final_color;
vec4 lighting_equation(in vec3 P_EC, in vec3 N_EC) {
vec4 color_sum;
float local_scale_factor, tmp_float;
vec3 L_EC;
color_sum = u_material.emissive_color + u_global_ambient_color * u_material.ambient_color;
for (int i = 0; i < NUMBER_OF_LIGHTS_SUPPORTED; i++) {
if (!u_light[i].light_on) continue;
local_scale_factor = one_f;
if (u_light[i].position.w != zero_f) { // point light source
L_EC = u_light[i].position.xyz - P_EC.xyz;
if (u_light[i].light_attenuation_factors.w != zero_f) {
vec4 tmp_vec4;
tmp_vec4.x = one_f;
tmp_vec4.z = dot(L_EC, L_EC);
tmp_vec4.y = sqrt(tmp_vec4.z);
tmp_vec4.w = zero_f;
local_scale_factor = one_f/dot(tmp_vec4, u_light[i].light_attenuation_factors);
}
L_EC = normalize(L_EC);
if (u_light[i].spot_cutoff_angle < 180.0f) { // [0.0f, 90.0f] or 180.0f
float spot_cutoff_angle = clamp(u_light[i].spot_cutoff_angle, zero_f, 90.0f);
vec3 spot_dir = normalize(u_light[i].spot_direction);
tmp_float = dot(-L_EC, spot_dir);
if (tmp_float >= cos(radians(spot_cutoff_angle))) {
tmp_float = pow(tmp_float, u_light[i].spot_exponent);
}
else
tmp_float = zero_f;
local_scale_factor *= tmp_float;
}
}
else { // directional light source
L_EC = normalize(u_light[i].position.xyz);
}
if (local_scale_factor > zero_f) {
vec4 local_color_sum = u_light[i].ambient_color * u_material.ambient_color;
tmp_float = dot(N_EC, L_EC);
if (tmp_float > zero_f) {
local_color_sum += u_light[i].diffuse_color*u_material.diffuse_color*tmp_float;
vec3 H_EC = normalize(L_EC - normalize(P_EC));
tmp_float = dot(N_EC, H_EC);
if (tmp_float > zero_f) {
local_color_sum += u_light[i].specular_color
*u_material.specular_color*pow(tmp_float, u_material.specular_exponent);
}
}
color_sum += local_scale_factor*local_color_sum;
}
}
return color_sum;
}
void main(void) {
final_color = lighting_equation(v_position_EC, normalize(v_normal_EC)); // for normal rendering
}
Related
Does anyone know why I keep getting the error that says:
The ♦ shader uses varying _I;DATA;g_mapCoord, but previous shader does not write to it.
The ♦ shader uses varying _I;DATA;worldPosition, but previous shader does not write to it.
Take a look at my shaders here.
Vertex
#version 430
layout (location = 0) in vec2 position0;
out DATA {
vec2 v_mapCoord;
vec3 worldPosition;
} Out;
uniform vec3 u_cameraPosition;
uniform mat4 u_localMatrix;
uniform mat4 u_worldMatrix;
uniform float u_scaleY;
uniform int u_lod;
uniform vec2 u_index;
uniform float u_gap;
uniform vec2 u_location;
uniform sampler2D s_heightmap;
uniform int u_lodMorphArea[8];
float morphLatitude(vec2 position)
{
//not important code
return 0;
}
float morphLongitude(vec2 position)
{
//not important code
return 0;
}
vec2 morph(vec2 localPosition, int morph_area){
//not important code
return vec2(0);
}
void main()
{
vec2 localPosition = (u_localMatrix * vec4(position0.x,0,position0.y,1)).xz;
if (u_lod > 0) {
localPosition += morph(localPosition, u_lodMorphArea[u_lod-1]); // Translate position by morphing vector
}
float height = texture(s_heightmap, localPosition).r;
Out.v_mapCoord = localPosition;
vec4 _worldPosition = u_worldMatrix * vec4(localPosition.x, height, localPosition.y,1);
Out.worldPosition = _worldPosition.xyz;
gl_Position = u_worldMatrix * vec4(localPosition.x, height, localPosition.y,1);
}
Fragment
#version 430
layout (location = 0) out vec4 outputColor;
in DATA {
vec2 g_mapCoord;
vec3 worldPosition;
} In;
const vec3 lightDirection = vec3(-0.2, -1.0, -0.2);
const float intensity = 1.2;
uniform sampler2D s_textureNormal;
uniform sampler2D s_textureWater;
uniform sampler2D s_textureLand;
float diffuse(vec3 direction, vec3 normal, float intensity)
{
return max(0.01, dot(normal, -direction) * intensity);
}
void main()
{
vec3 normal = texture(s_textureNormal, In.g_mapCoord).rgb;
float diff = diffuse(lightDirection, normal, intensity);
outputColor = vec4(1,0,0,1);
}
Geom
#version 430
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vec2 te_mapCoord[];
out vec2 g_mapCoord;
uniform mat4 u_viewProjection;
void main() {
for (int i = 0; i < gl_in.length(); ++i)
{
vec4 position = gl_in[i].gl_Position;
gl_Position = u_viewProjection * position;
g_mapCoord = te_mapCoord[i];
EmitVertex();
}
EndPrimitive();
}
TCS
#version 430
layout(vertices = 16) out;
in DATA {
vec2 v_mapCoord;
vec3 worldPosition;
} In[];
out vec2 tc_mapCoord[];
const int AB = 2;
const int BC = 3;
const int CD = 0;
const int DA = 1;
uniform int u_tessellationFactor;
uniform float u_tessellationSlope;
uniform float u_tessellationShift;
uniform vec3 u_cameraPosition;
// Calculate tessellation levels
float lodFactor(float dist)
{
float tessellationLevel = max(0.0, u_tessellationFactor/pow(dist, u_tessellationSlope) + u_tessellationShift);
return tessellationLevel;
}
void main()
{
if (gl_InvocationID == 0){
// Calculate mid points of the edges of the quad
vec3 abMid = vec3(gl_in[0].gl_Position + gl_in[3].gl_Position)/2.0; //Bottom left, Bottom right
vec3 bcMid = vec3(gl_in[3].gl_Position + gl_in[15].gl_Position)/2.0; //Bottom right Top right
vec3 cdMid = vec3(gl_in[15].gl_Position + gl_in[12].gl_Position)/2.0; //Top right, Top left
vec3 daMid = vec3(gl_in[12].gl_Position + gl_in[0].gl_Position)/2.0; //Top left, Bottom left
// Calculate distance between camera and mid points of the edges of the quad
float distanceAB = distance(abMid, u_cameraPosition);
float distanceBC = distance(bcMid, u_cameraPosition);
float distanceCD = distance(cdMid, u_cameraPosition);
float distanceDA = distance(daMid, u_cameraPosition);
// Tesselation levels used by tessellation primitive generator (define how much tessellation to apply to the patch). Value between 1 and gl_MaxTessGenLevel, depending on lodFactor.
gl_TessLevelOuter[AB] = mix(1, gl_MaxTessGenLevel, lodFactor(distanceAB));
gl_TessLevelOuter[BC] = mix(1, gl_MaxTessGenLevel, lodFactor(distanceBC));
gl_TessLevelOuter[CD] = mix(1, gl_MaxTessGenLevel, lodFactor(distanceCD));
gl_TessLevelOuter[DA] = mix(1, gl_MaxTessGenLevel, lodFactor(distanceDA));
gl_TessLevelInner[0] = (gl_TessLevelOuter[BC] + gl_TessLevelOuter[DA])/4;
gl_TessLevelInner[1] = (gl_TessLevelOuter[AB] + gl_TessLevelOuter[CD])/4;
}
tc_mapCoord[gl_InvocationID] = In[gl_InvocationID].v_mapCoord; // Just pass to the next stage
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
TES
#version 430
layout(quads, fractional_odd_spacing, cw) in;
in vec2 tc_mapCoord[];
out vec2 te_mapCoord;
uniform sampler2D s_heightmap;
uniform float u_scaleY;
void main(){
float u = gl_TessCoord.x;
float v = gl_TessCoord.y;
// Compute new position for each tessellated vertex within the patch. gl_in with index 12, 0, 3, 15 are corners of the patch.
vec4 position = ((1 - u) * (1 - v) * gl_in[12].gl_Position + u * (1 - v) * gl_in[0].gl_Position + u * v * gl_in[3].gl_Position +(1 - u) * v * gl_in[15].gl_Position);
vec2 mapCoord = ((1 - u) * (1 - v) * tc_mapCoord[12] + u * (1 - v) * tc_mapCoord[0] + u * v * tc_mapCoord[3] +(1 - u) * v * tc_mapCoord[15]);
float height = texture(s_heightmap, mapCoord).r;
height *= u_scaleY;
position.y = height;
te_mapCoord = mapCoord;
gl_Position = position;
}
Can anyone help me find the error here which is why I'm getting that error message?
When you introduce a geometry shader you need to pass the varyings for the fragment shader from the geometry shader, not the vertex shader.
You can see how your geometry shader doing this:
out vec2 g_mapCoord;
is incompatible with your fragment shader expecting this:
in DATA {
vec2 g_mapCoord;
vec3 worldPosition;
} In;
Related question and subsequent answers here.
I'm creating a few glowing particles in raylib using shaders and the particles are supposed to move along with the mouse but when compiling it gets stuck to the bottom left corner and the particles dont move.
How it Looks
The c++ code
#include <raylib.h>
#include <vector>
const int W = 400;
const int H = 400;
std::vector<Vector2> particle;
float remap(float value, float low1, float high1, float low2, float high2) {
return low2 + (value - low1) * (high2 - low2) / (high1 - low1);
}
int main() {
SetConfigFlags( FLAG_WINDOW_RESIZABLE );
InitWindow(W, H, "FireWorks");
Shader shader = LoadShader("../assets/vert.glsl", "../assets/frag.glsl");
Texture2D texture = LoadTextureFromImage(GenImageColor(W, H, BLUE));
int resolLoc = GetShaderLocation(shader, "resolution");
int particleLoc = GetShaderLocation(shader, "particle");
int particleCountLoc = GetShaderLocation(shader, "particleCount");
float res[2] = {(float)W, (float)H};
SetShaderValue(shader, resolLoc, res, SHADER_UNIFORM_VEC2);
SetTargetFPS(60);
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(BLACK);
particle.push_back(Vector2{(float)GetMouseX(), (float)GetMouseY()});
int removeCount = 1;
for (int i = 0; i < removeCount; i++) {
if (particle.size() == 0) break;
if (particle.size() > 30) {
particle.erase(particle.begin() + i);
}
}
BeginShaderMode(shader);
float particles[30][2];
for ( int i = 0; i < particle.size(); i++) {
particles[i][0] = remap(particle[i].x, 0, W, 0.0, 1.0);
particles[i][1] = remap(particle[i].y, 0, H, 1.0, 0.0);
}
int pSize = particle.size();
SetShaderValue(shader, particleCountLoc, &pSize, SHADER_UNIFORM_INT);
SetShaderValue(shader, particleLoc, particles, SHADER_UNIFORM_VEC2);
DrawTextureRec(texture, (Rectangle) { 0, 0, (float)texture.width, (float) -texture.height }, (Vector2) { 0, 0}, RAYWHITE);
DrawRectangle(0, 0, W, H, BLACK);
EndShaderMode();
EndDrawing();
}
UnloadTexture(texture);
UnloadShader(shader);
CloseWindow();
return 0;
}
The Vertex Shader
#version 330
// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexColor;
// Input uniform values
uniform mat4 mvp;
// Output vertex attributes (to fragment shader)
out vec2 fragTexCoord;
out vec4 fragColor;
// NOTE: Add here your custom variables
void main()
{
// Send vertex attributes to fragment shader
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
// Calculate final vertex position
gl_Position = mvp * vec4(vertexPosition, 1.0);
}
The Fragment Shader
#version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables
uniform vec2 resolution;
uniform int particleCount;
uniform vec2 particle[30];
void main() {
// Texel color fetching from texture sampler
vec4 texelColor = texture(texture0, fragTexCoord);
vec2 st = gl_FragCoord.xy / resolution.xy;
float r = 0.0;
float g = 0.0;
float b = 0.0;
for (int i = 0; i < 30; i++) {
if (i < particleCount) {
vec2 particlePos = particle[i];
float value = float(i) / distance(st, particlePos.xy) * 0.00015;
g += value * 0.5;
b += value;
}
}
finalColor = vec4(r, g, b, 1.0) * texelColor * colDiffuse;
}
The JS version of the code (which works) is here.
If you could point me in the right direction it'd be great.
The uniform particle is of type vec2[30]. An uniform array can needs to be set with SetShaderValueV instead of SetShaderValue:
SetShaderValue(shader, particleLoc, particles, SHADER_UNIFORM_VEC2);
SetShaderValueV(shader, particleLoc, particles[0], SHADER_UNIFORM_VEC2, 30);
When I implemented SSR I encountered the problem of artifacts. Below I present the code and screenshots.
Fragment SSR shader:
#version 330 core
uniform sampler2D normalMap; // in view space
uniform sampler2D colorMap;
uniform sampler2D reflectionStrengthMap;
uniform sampler2D positionMap; // in view space
uniform mat4 projection;
uniform vec3 skyColor = vec3(0.1, 0, 0.5);
in vec2 texCoord;
layout (location = 0) out vec4 fragColor;
const int binarySearchCount = 10;
const int rayMarchCount = 30;
const float step = 0.05;
const float LLimiter = 0.2;
const float minRayStep = 0.2;
vec3 getPosition(in vec2 texCoord) {
return texture(positionMap, texCoord).xyz;
}
vec2 binarySearch(inout vec3 dir, inout vec3 hitCoord, inout float dDepth) {
float depth;
vec4 projectedCoord;
for(int i = 0; i < binarySearchCount; i++) {
projectedCoord = projection * vec4(hitCoord, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
depth = getPosition(projectedCoord.xy).z;
dDepth = hitCoord.z - depth;
dir *= 0.5;
if(dDepth > 0.0)
hitCoord += dir;
else
hitCoord -= dir;
}
projectedCoord = projection * vec4(hitCoord, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
return vec2(projectedCoord.xy);
}
vec2 rayCast(vec3 dir, inout vec3 hitCoord, out float dDepth) {
dir *= step;
for (int i = 0; i < rayMarchCount; i++) {
hitCoord += dir;
vec4 projectedCoord = projection * vec4(hitCoord, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
float depth = getPosition(projectedCoord.xy).z;
dDepth = hitCoord.z - depth;
if((dir.z - dDepth) < 1.2 && dDepth <= 0.0) return binarySearch(dir, hitCoord, dDepth);
}
return vec2(-1.0);
}
void main() {
float reflectionStrength = texture(reflectionStrengthMap, texCoord).r;
if (reflectionStrength == 0) {
fragColor = texture(colorMap, texCoord);
return;
}
vec3 normal = texture(normalMap, texCoord).xyz;
vec3 viewPos = getPosition(texCoord);
// Reflection vector
vec3 reflected = normalize(reflect(normalize(viewPos), normalize(normal)));
// Ray cast
vec3 hitPos = viewPos;
float dDepth;
vec2 coords = rayCast(reflected * max(-viewPos.z, minRayStep), hitPos, dDepth);
float L = length(getPosition(coords) - viewPos);
L = clamp(L * LLimiter, 0, 1);
float error = 1 - L;
vec3 color = texture(colorMap, coords.xy).rgb * error;
if (coords.xy != vec2(-1.0)) {
fragColor = mix(texture(colorMap, texCoord), vec4(color, 1.0), reflectionStrength);
return;
}
fragColor = mix(texture(colorMap, texCoord), vec4(skyColor, 1.0), reflectionStrength);
}
Result without blackout (without * error):
Result with blackout:
Note: blue is filled specifically to see artifacts
And one more question, what is the best way to add fresnel without harming scene?
tl;dr:
What is the best method for accessing data from each individual vertex whilst in the fragment shader?
e.g.
The triangle in this fragment is made up from vertices v0,v1 and v2 and I want to give each vertex a specific integer which I can use to pick a texture and then fade between the 3 in the fragment shader; I don't want these ids to be interpolated and it is important that I can access each vertex's id.
Current Situation:
I am currently writing a shader for rendering terrain; I have a function in my fragment shader which will return the appropriate texture colour from uvs for a given ID (By means of a texture atlas). I can then fade between the 3 textures to give the give smoothly textured terrain
Current Code
Vertex Shader:
#version 330 core
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec2 in_uv_coords;
layout(location = 2) in vec3 in_normal;
layout(location = 3) in float in_texture_id;
uniform mat4 view_matrix;
uniform mat4 projection_matrix;
out vec2 pass_uv_coords;
out vec3 pass_normal;
out vec3 texture_ratio;
out float pass_fake_brightness;
out float pass_id0;
out float pass_id1;
out float pass_id2;
void CalculateFakeLighting()
{
const vec3 light_direction = normalize(vec3(1,-1,1));
vec3 unit_normal = normalize(in_normal);
float normal_dot_light = dot(unit_normal, -light_direction);
pass_fake_brightness = max(0.2, normal_dot_light);
}
void main()
{
pass_uv_coords = in_uv_coords;
pass_normal = in_normal;
gl_Position = projection_matrix * view_matrix * vec4(in_position, 1.0);
int tile_track = int(mod(gl_VertexID, 3));
switch(tile_track)
{
case 0:
texture_ratio = vec3(1,0,0);
pass_id0 = in_texture_id;
break;
case 1:
texture_ratio = vec3(0,1,0);
pass_id1 = in_texture_id;
break;
case 2:
texture_ratio = vec3(0,0,1);
pass_id0 = in_texture_id;
break;
};
CalculateFakeLighting();
}
Fragment Shader:
#version 330 core
in vec2 pass_uv_coords;
in vec3 pass_normal;
in vec3 texture_ratio;
in float pass_fake_brightness;
in float pass_id0;
in float pass_id1;
in float pass_id2;
const int HORIZONTAL_IDS = 8;
const int VERTICAL_IDS = 8;
uniform sampler2D texture0_sampler;
out vec4 colour;
void UseFakeLighting()
{
colour *= pass_fake_brightness;
}
vec2 CorrectUVs(vec2 uvs)
{
vec2 corrected_uvs = uvs;
const float cushion = 0.001;
//Correct UV scale
while(corrected_uvs.x >= 1)
corrected_uvs.x--;
while(corrected_uvs.y >= 1)
corrected_uvs.y--;
if(corrected_uvs.x < cushion)
corrected_uvs.x = cushion;
if(corrected_uvs.x > 1 - cushion)
corrected_uvs.x = 1 - cushion;
if(corrected_uvs.y < cushion)
corrected_uvs.y = cushion;
if(corrected_uvs.y > 1 - cushion)
corrected_uvs.y = 1 - cushion;
return corrected_uvs;
}
vec4 GetTexture(float id, vec2 uv_coords)
{
vec2 step = vec2(
1.0/HORIZONTAL_IDS,
1.0/VERTICAL_IDS
);
uv_coords.x/=HORIZONTAL_IDS;
uv_coords.y/=VERTICAL_IDS;
uv_coords.x += step.x * mod(id, HORIZONTAL_IDS);
uv_coords.y += step.y * floor(id/VERTICAL_IDS);
//Texture is upsidedown
uv_coords.y = 1.0 - uv_coords.y;
return texture(texture0_sampler, uv_coords);
}
void main()
{
vec2 corrected_uvs = CorrectUVs(pass_uv_coords);
vec3 correct_ratio = normalize(texture_ratio);
colour = GetTexture(pass_id0, corrected_uvs) * correct_ratio.x +
GetTexture(pass_id1, corrected_uvs) * correct_ratio.y +
GetTexture(pass_id2, corrected_uvs) * correct_ratio.z;
if(colour.a == 0)
discard;
UseFakeLighting();
}
By default the output variables from the vertex shader to the fragment shader use perspective-correct interpolation. If you want no interpolation done then qualify your variables with flat:
flat out vec3 pass_id0;
For more info see GLSL Type Qualifiers. Also see this question “flat” qualifier in glsl?
As recommended by #aslg and #AndonM.Coleman, geometry is a good solution to this issue. A flat vec3 is passed out of the geometry stage, which stores the id of each vertex which is then accessible in the fragment shader.
The key lines are in the geometry shader; one part of the output is
flat vec3 texture_ids;
Which is then set as such:
vertex_out.texture_ids.x = vertex_in[0].texture_id;
vertex_out.texture_ids.y = vertex_in[1].texture_id;
vertex_out.texture_ids.z = vertex_in[2].texture_id;
Full Shader Sources:
Vertex
#version 330 core
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec2 in_uv_coords;
layout(location = 2) in vec3 in_normal;
layout(location = 3) in float in_texture_id;
out VertexData
{
vec2 uv_coord;
vec3 normal;
uint texture_id;
} vertex_out;
void main()
{
vertex_out.uv_coord = in_uv_coords;
vertex_out.normal = in_normal;
vertex_out.texture_id = uint(round(in_texture_id));
gl_Position = vec4(in_position, 1.0);
}
Geometry
#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
uniform mat4 view_matrix;
uniform mat4 projection_matrix;
mat4 vp_matrix = projection_matrix * view_matrix;
in VertexData
{
vec2 uv_coord;
vec3 normal;
uint texture_id;
} vertex_in[];
out VertexDataPass
{
vec2 uv_coord;
vec3 normal;
vec3 texture_ratio;
float brightness;
flat vec3 texture_ids;
} vertex_out;
void CalculateFakeBrightness(int index)
{
const vec3 light_direction = normalize(vec3(1,-1,1));
vec3 unit_normal = normalize(vertex_in[index].normal);
float normal_dot_light = dot(unit_normal, -light_direction);
vertex_out.brightness = max(0.2, normal_dot_light);
}
void main()
{
for(int i = 0; i < gl_in.length(); i++)
{
gl_Position = vp_matrix * gl_in[i].gl_Position;
vertex_out.uv_coord = vertex_in[i].uv_coord;
vertex_out.normal = vertex_in[i].normal;
vertex_out.texture_ids.x = vertex_in[0].texture_id;
vertex_out.texture_ids.y = vertex_in[1].texture_id;
vertex_out.texture_ids.z = vertex_in[2].texture_id;
CalculateFakeBrightness(i);
switch(int(mod(i,3)))
{
case 0:
vertex_out.texture_ratio = vec3(1,0,0);
break;
case 1:
vertex_out.texture_ratio = vec3(0,1,0);
break;
case 2:
vertex_out.texture_ratio = vec3(0,0,1);
break;
};
EmitVertex();
}
EndPrimitive();
}
Fragment
#version 330 core
in VertexDataPass
{
vec2 uv_coord;
vec3 normal;
vec3 texture_ratio;
float brightness;
flat vec3 texture_ids;
} vertex_data;
const int HORIZONTAL_IDS = 8;
const int VERTICAL_IDS = 8;
uniform sampler2D texture0_sampler;
out vec4 colour;
vec2 CorrectUVs(vec2 uvs)
{
vec2 corrected_uvs = uvs;
const float cushion = 0.001;
//Correct UV scale
while(corrected_uvs.x >= 1)
corrected_uvs.x--;
while(corrected_uvs.y >= 1)
corrected_uvs.y--;
if(corrected_uvs.x < cushion)
corrected_uvs.x = cushion;
if(corrected_uvs.x > 1 - cushion)
corrected_uvs.x = 1 - cushion;
if(corrected_uvs.y < cushion)
corrected_uvs.y = cushion;
if(corrected_uvs.y > 1 - cushion)
corrected_uvs.y = 1 - cushion;
return corrected_uvs;
}
vec4 GetTexture(uint id, vec2 uv_coords)
{
vec2 step = vec2(
1.0/HORIZONTAL_IDS,
1.0/VERTICAL_IDS
);
uv_coords.x/=HORIZONTAL_IDS;
uv_coords.y/=VERTICAL_IDS;
uv_coords.x += step.x * mod(id, HORIZONTAL_IDS);
uv_coords.y += step.y * floor(float(id)/VERTICAL_IDS);
//Texture is upsidedown
uv_coords.y = 1.0 - uv_coords.y;
return texture(texture0_sampler, uv_coords);
}
void main()
{
vec2 uvs = CorrectUVs(vertex_data.uv_coord);
colour =
GetTexture(uint(vertex_data.texture_ids.x), uvs) * vertex_data.texture_ratio.x +
GetTexture(uint(vertex_data.texture_ids.y), uvs) * vertex_data.texture_ratio.y +
GetTexture(uint(vertex_data.texture_ids.z), uvs) * vertex_data.texture_ratio.z;
if(colour.a == 0)
discard;
colour.xyz *= vertex_data.brightness;
}
I'm learning GLSL and trying to implement some lighting and mapping tricks. I'm working with ShaderDesigner tool. After coding normal mapping I recognized that my model illumination looks not real. Here is my code and some pictures. If it possible tell me what is my problem.
Vertex Shader
#define MAX_LIGHTS 1
struct LightProps
{
vec3 direction[MAX_LIGHTS];
};
attribute vec3 tangent;
attribute vec3 bitangent;
varying LightProps lights;
void main()
{
vec3 N = normalize(gl_NormalMatrix*gl_Normal);
vec3 T = normalize(gl_NormalMatrix*tangent);
vec3 B = normalize(gl_NormalMatrix*bitangent);
mat3 TBNMatrix = mat3(T,B,N);
vec4 vertex = gl_ModelViewMatrix*gl_Vertex;
for(int i = 0; i < MAX_LIGHTS; i++)
{
vec4 lightPos = gl_LightSource[i].position;
lights.direction[i] = vec3(lightPos.w > 0 ? lightPos-vertex : lightPos);
lights.direction[i] *= TBNMatrix;
}
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
}
Fragment Shader
#define MAX_LIGHTS 1
struct LightProps
{
vec3 direction[MAX_LIGHTS];
};
uniform sampler2D textureUnit;
uniform sampler2D normalTextureUnit;
uniform vec4 TexColor;
varying LightProps lights;
void main()
{
vec3 N = normalize(texture2D(normalTextureUnit,gl_TexCoord[0].st).rgb*2.0-1.0);
vec4 color = vec4(0,0,0,0);
for(int i = 0; i < MAX_LIGHTS; i++)
{
vec3 L = lights.direction[i];
float dist = length(L);
L = normalize(L);
float NdotL = max(dot(N,L),0.0);
if(NdotL > 0)
{
float att = 1.0;
if(gl_LightSource[i].position.w > 0)
{
att = 1.0/ (gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * dist +
gl_LightSource[i].quadraticAttenuation * dist * dist);
}
vec4 ambient = gl_FrontLightProduct[i].ambient;
vec4 diffuse = clamp(att*NdotL*gl_FrontLightProduct[i].diffuse,0,1);
color += att*(ambient+diffuse);
}
}
vec4 textureColor = texture2D(textureUnit, vec2(gl_TexCoord[0]));
gl_FragColor = TexColor*textureColor + gl_FrontLightModelProduct.sceneColor + color;
}
I set TexColor to (0.3,0.3,0.3,1.0) and take screenshots:
Screenshot
There is little bit lighting when I rotate camera and light to left,
but when I rotate to right the plane got fully illuminated.I think there is something wrong because without normal mapping plane looks same from to sides. Here is normal texture. Thanks in advance.
Normal Map:
That normal map is in tangent-space, but you are treating it as object-space.
You need a bitangent and/or tangent vector per-vertex in addition to your normal in order to form the basis to perform transformation into and out of tangent-space. This matrix is often referred to as simply TBN.
You have two options here:
Transform all of your lighting direction vectors into tangent-space
Useful for forward-shading, can be done in a vertex shader
Transform your normal map from tangent-space back to view-space
Required by deferred-shading, must be done in fragment shader
Both options require the construction of a TBN matrix, and if your tangent-space basis is orthogonal (modeling software like Assimp can be configured to do this for you) you can transpose the TBN matrix to do either one.
You are implementing forward-shading, so solution #1 is the approach you should take.
Below is a rough overview of the necessary steps for solution #1. Ordinarily you would do the calculation of the lighting direction vector in the vertex shader for better performance.
Vertex Shader to Transform of Lighting Vectors into Tangent-space:
attribute vec3 tangent;
attribute vec3 bitangent;
varying vec3 N;
varying vec3 V;
varying vec3 E;
varying vec3 T;
varying vec3 B;
void main()
{
N = normalize(gl_NormalMatrix*gl_Normal);
V = vec3(gl_ModelViewMatrix*gl_Vertex);
E = normalize(-V);
T = normalize(gl_NormalMatrix*tangent);
B = normalize(gl_NormalMatrix*bitangent);
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
}
Fragment Shader to Transform Lighting Vectors into Tangent-space:
varying vec3 N;
varying vec3 V;
varying vec3 E;
varying vec3 B;
varying vec3 T;
uniform sampler2D textureUnit;
uniform sampler2D normalTextureUnit;
uniform vec4 TexColor;
#define MAX_LIGHTS 1
void main()
{
// Construct Tangent Space Basis
mat3 TBN = mat3 (T, B, N);
vec3 normal = normalize (texture2D(normalTextureUnit,gl_TexCoord[0].st).xyz*2.0 - 1.0);
vec4 color = vec4(0,0,0,0);
for(int i = 0; i < MAX_LIGHTS; i++)
{
vec4 lightPos = gl_LightSource[i].position;
vec3 L = lightPos.w > 0 ? lightPos.xyz - V : lightPos;
L *= TBN; // Transform into tangent-space
float dist = length(L);
L = normalize(L);
float NdotL = max(dot(L,N),0.0);
if(NdotL > 0)
{
float att = 1.0;
if(lightPos.w > 0)
{
att = 1.0/ (gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * dist +
gl_LightSource[i].quadraticAttenuation * dist * dist);
}
vec4 diffuse = clamp(att*NdotL*gl_FrontLightProduct[i].diffuse,0,1);
color += att*gl_FrontLightProduct[i].ambient + diffuse;
}
}
vec4 textureColor = texture2D(textureUnit, vec2(gl_TexCoord[0]));
gl_FragColor = TexColor*textureColor + gl_FrontLightModelProduct.sceneColor + color;
}
There is a tutorial here that should fill in the gaps and explain how to compute tangent and bitangent.