Get float3 Values from specific pixels as a color value in ShaderFX? - glsl

I'm using ShaderFX and I need to fetch colors values in float3 from a texture arranged horizontally in 8x1 pixel resolution. I'm trying to make it so that I can fetch each pixel and output a color value like so:
8x1 (Red, Green, Blue, Yellow, Orange, Violet, White, Black)
Color 1: float3 for red
Color 2: float3 for green
Color 8: float3 for black
I used documentation from the Autodesk Maya website as reference to write the code below but ran into a wall when I realized I was outputting texture maps instead of color values (because the textures were still being sampled as texture maps rather than pixels). My end goal is to make my 8x1 colors function as a look up table to replace gray values from a texture. These colors will be hooked up to color stops when I create a ramp later. I'm at a loss here so any direction would be appreciated!
// You may add new struct outputs, function inputs and adjust code in the function.
// Function name and output struct should match 'Function Name' attribute on node.
// Available preprocessor definitions: SFX_HLSL_3, SFX_HLSL_5, SFX_GLSL_1_2, SFX_GLSL_4, SFX_CGFX_3, SFX_OGsFX, _MAYA_, _3DSMAX_, SFX_SWATCH
// You can use SFX_TEXTURE[n] or SFX_SAMPLER[n] to refer to texture inputs so you do not have to hardcode their names
struct PixelSamplerCode1000Output
{
float3 color1;
float3 color2;
float3 color3;
float3 color4;
float3 color5;
float3 color6;
float3 color7;
float3 color8;
};
PixelSamplerCode1000Output PixelSamplerCode1000Func(float colorSamples, float2 UV )
{
PixelSamplerCode1000Output OUT;
float3 t1 = float3(0,0,0);
float3 t2 = float3(0,0,0);
float3 t3 = float3(0,0,0);
float3 t4 = float3(0,0,0);
float3 t5 = float3(0,0,0);
float3 t6 = float3(0,0,0);
float3 t7 = float3(0,0,0);
float3 t8 = float3(0,0,0);
#if defined(SFX_CGFX_3) || defined(SFX_HLSL_3)
t1 = tex2D( SFX_SAMPLER0, float2((UV.x*0.5/colorSamples), 1-UV.y) ).xyz;
t2 = tex2D( SFX_SAMPLER0, float2((UV.x*1.5/colorSamples), 1-UV.y) ).xyz;
t3 = tex2D( SFX_SAMPLER0, float2((UV.x*2.5/colorSamples), 1-UV.y) ).xyz;
t4 = tex2D( SFX_SAMPLER0, float2((UV.x*3.5/colorSamples), 1-UV.y) ).xyz;
t5 = tex2D( SFX_SAMPLER0, float2((UV.x*4.5/colorSamples), 1-UV.y) ).xyz;
t6 = tex2D( SFX_SAMPLER0, float2((UV.x*5.5/colorSamples), 1-UV.y) ).xyz;
t7 = tex2D( SFX_SAMPLER0, float2((UV.x*6.5/colorSamples), 1-UV.y) ).xyz;
t8 = tex2D( SFX_SAMPLER0, float2((UV.x*7.5/colorSamples), 1-UV.y) ).xyz;
#endif
#ifdef SFX_HLSL_5
#if defined(SFX_SWATCH) || defined(_3DSMAX_)
t1 = SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*0.5/colorSamples), UV.y) );
t2 = SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*1.5/colorSamples), UV.y) );
t3 = SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*2.5/colorSamples), UV.y) );
t4 = SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*3.5/colorSamples), UV.y) );
t5 = SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*4.5/colorSamples), UV.y) );
t6 = SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*5.5/colorSamples), UV.y) );
t7 = SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*6.5/colorSamples), UV.y) );
t8 = SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*7.5/colorSamples), UV.y) );
#else
t1= SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*0.5/colorSamples), 1-UV.y) );
t2= SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*1.5/colorSamples), 1-UV.y) );
t3= SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*2.5/colorSamples), 1-UV.y) );
t4= SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*3.5/colorSamples), 1-UV.y) );
t5= SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*4.5/colorSamples), 1-UV.y) );
t6= SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*5.5/colorSamples), 1-UV.y) );
t7= SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*6.5/colorSamples), 1-UV.y) );
t8= SFX_TEXTURE0.Sample( SFX_SAMPLER0, float2((UV.x*7.5/colorSamples), 1-UV.y) );
#endif
#endif
#ifdef SFX_GLSL_4
t1 = texture( SFX_TEXTURE0, float2((UV.x*0.5/colorSamples), 1-UV.y) ).xyz;
t2 = texture( SFX_TEXTURE0, float2((UV.x*1.5/colorSamples), 1-UV.y) ).xyz;
t3 = texture( SFX_TEXTURE0, float2((UV.x*2.5/colorSamples), 1-UV.y) ).xyz;
t4 = texture( SFX_TEXTURE0, float2((UV.x*3.5/colorSamples), 1-UV.y) ).xyz;
t5 = texture( SFX_TEXTURE0, float2((UV.x*4.5/colorSamples), 1-UV.y) ).xyz;
t6 = texture( SFX_TEXTURE0, float2((UV.x*5.5/colorSamples), 1-UV.y) ).xyz;
t7 = texture( SFX_TEXTURE0, float2((UV.x*6.5/colorSamples), 1-UV.y) ).xyz;
t8 = texture( SFX_TEXTURE0, float2((UV.x*7.5/colorSamples), 1-UV.y) ).xyz;
#endif
#ifdef SFX_GLSL_1_2
t1 = texture2D( SFX_TEXTURE0, float2((UV.x*0.5/colorSamples), 1-UV.y) ).xyz;
t2 = texture2D( SFX_TEXTURE0, float2((UV.x*1.5/colorSamples), 1-UV.y) ).xyz;
t3 = texture2D( SFX_TEXTURE0, float2((UV.x*2.5/colorSamples), 1-UV.y) ).xyz;
t4 = texture2D( SFX_TEXTURE0, float2((UV.x*3.5/colorSamples), 1-UV.y) ).xyz;
t5 = texture2D( SFX_TEXTURE0, float2((UV.x*4.5/colorSamples), 1-UV.y) ).xyz;
t6 = texture2D( SFX_TEXTURE0, float2((UV.x*5.5/colorSamples), 1-UV.y) ).xyz;
t7 = texture2D( SFX_TEXTURE0, float2((UV.x*6.5/colorSamples), 1-UV.y) ).xyz;
t8 = texture2D( SFX_TEXTURE0, float2((UV.x*7.5/colorSamples), 1-UV.y) ).xyz;
#endif
OUT.color1 = t1;
OUT.color2 = t2;
OUT.color3 = t3;
OUT.color4 = t4;
OUT.color5 = t5;
OUT.color6 = t6;
OUT.color7 = t7;
OUT.color8 = t8;
return OUT;
}

Related

OpenGL : overlapping 2 textures without white blend

I am trying to make a fragment shader for a 2d art style im working on.
But to make that work i must make a texture able to overlap itself multiple times.
result i want and the 2 current results:
Edit1: in my art style i have 1 texture per plane. to make the illusion of each plane having thickness i need it to draw it self 2 times, with one pixel distance.
illustration:
if it was drawn a green plane then a blue plane, yes i would like to replace the green area with blue where it overlaps.
I have attempted to subtract the next texture location to nullify texture blending, but resulted in also adding negative values at empty area.
```
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform float shxx;
uniform float shyy;
void main()
{
vec2 Coord1 = v_vTexcoord + vec2(0,0);
vec2 Coord2 = v_vTexcoord + vec2(shxx,shyy);
vec2 Coord3 = v_vTexcoord + vec2(shxx+shxx,shyy+shyy);
vec2 Coord4 = v_vTexcoord + vec2(+shxx+shxx+shxx,+shyy+shyy+shyy);
gl_FragColor = v_vColour * texture2D( gm_BaseTexture, Coord1)
- v_vColour * texture2D( gm_BaseTexture, Coord2)
+ v_vColour * texture2D( gm_BaseTexture, Coord2)
- v_vColour * texture2D( gm_BaseTexture, Coord3)
+ v_vColour * texture2D( gm_BaseTexture, Coord3)
- v_vColour * texture2D( gm_BaseTexture, Coord4)
+ v_vColour * texture2D( gm_BaseTexture, Coord4);
}
```
Found a solution. every time i subtract next textures position i set all fragments with alpha value less than 0,9 to default color black. this way the next texture gets drawn on top of no existing colors. thus avoiding the textures blending into white.
Final Result = https://i.imgur.com/aexqIts.png
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform float shxx;
uniform float shyy;
void main()
{
vec2 Coord1 = v_vTexcoord + vec2(0,0);
vec2 Coord2 = v_vTexcoord + vec2(shxx,shyy);
vec2 Coord3 = v_vTexcoord + vec2(shxx+shxx,shyy+shyy);
vec2 Coord4 = v_vTexcoord + vec2(+shxx+shxx+shxx,+shyy+shyy+shyy);
vec2 Coord5 = v_vTexcoord + vec2(+shxx+shxx+shxx+shxx,+shyy+shyy+shyy+shyy);
gl_FragColor = v_vColour * texture2D( gm_BaseTexture, Coord1)
- texture2D( gm_BaseTexture, Coord2)*0.9;
if( gl_FragColor.a < 0.9 ) gl_FragColor = vec4(0.0,0.0,0.0,0.0);
gl_FragColor += v_vColour * texture2D( gm_BaseTexture, Coord2)
- texture2D( gm_BaseTexture, Coord3)*0.9;
if( gl_FragColor.a < 0.9 ) gl_FragColor = vec4(0.0,0.0,0.0,0.0);
gl_FragColor += v_vColour * texture2D( gm_BaseTexture, Coord3)
- texture2D( gm_BaseTexture, Coord4)*0.9;
if( gl_FragColor.a < 0.9 ) gl_FragColor = vec4(0.0,0.0,0.0,0.0);
gl_FragColor += v_vColour * texture2D( gm_BaseTexture, Coord4)
- texture2D( gm_BaseTexture, Coord5)*0.9;
if( gl_FragColor.a < 0.9 ) gl_FragColor = vec4(0.0,0.0,0.0,0.0);
gl_FragColor += v_vColour * texture2D( gm_BaseTexture, Coord5);
}

OpenGL ES3 Shadow map problems

I work on C++ project for Android with OpenGL ES3, so I try to implement the shadow map with directional light, I understand the theory well but I never get it successfully rendered.
first I create the framebuffer which contains the depth map:
glGenFramebuffers(1, &depthMapFBO);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glGenTextures(1, &depthMap);
glBindTexture(GL_TEXTURE_2D, depthMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
glDrawBuffers(1, GL_NONE);
glReadBuffer(GL_NONE);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
then I create a shader program that compiles the depth shader which is the following:
#version 300 es
precision mediump float;
layout (location = 0) in vec3 position;
layout (location = 4) in ivec4 BoneIDs;
layout (location = 5) in vec4 Weights;
const int MAX_BONES = 100;
uniform mat4 lightSpaceMatrix;
uniform mat4 model;
uniform bool skinned;
uniform mat4 gBones[MAX_BONES];
void main(){
vec4 nPos;
if(skinned){
mat4 BoneTransform = gBones[BoneIDs[0]] * Weights[0];
BoneTransform += gBones[BoneIDs[1]] * Weights[1];
BoneTransform += gBones[BoneIDs[2]] * Weights[2];
BoneTransform += gBones[BoneIDs[3]] * Weights[3];
nPos=BoneTransform * vec4(position, 1.0);
}
else
nPos = vec4(position, 1.0);
vec4 p=model * nPos;
gl_Position = lightSpaceMatrix * p;
}
and draw the scene using this shader program with the light space matrix using the following:
glCullFace(GL_FRONT);
double delta = GetCurrentTime() - firstFrame;
glm::mat4 camInv = glm::inverse(camera->getViewMatrix());
glm::mat4 lightSpaceProjection = glm::ortho(-40.0f, 40.0f, -40.0f, 40.0f, -1.0f, 100.0f);
glm::mat4 lightSpaceView = glm::lookAt(sun->direction, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
lightSpaceMatrix = lightSpaceProjection * (lightSpaceView*camInv) ;
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);
directDepthShader.use();
glUniformMatrix4fv(glGetUniformLocation(directDepthShader.getProgramID(), "lightSpaceMatrix"), 1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
for (mesh_it it = castShadowMeshes.begin(); it != castShadowMeshes.end(); it++) {
it->get()->renderDepth(directDepthShader, delta);
}
glCullFace(GL_BACK);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
finally I render the scene with the regular shader program and bind the depth map to the shadowMap uniform with the following code:
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
phongShader.use();
if (sun != nullptr)
if (sun->castShadow)
glUniformMatrix4fv(glGetUniformLocation(phongShader.getProgramID(), "lightSpaceMatrix"), 1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
this->setLightsUniforms(phongShader);
this->setViewUniforms(phongShader);
for (mesh_it it = phongMeshes.begin(); it != phongMeshes.end(); it++) {
if (it->get()->hasNormalMap) {
glUniform1i(glGetUniformLocation(phongShader.getProgramID(), "has_normal_map"), 1);
if (directlights.size() > 0) {
for (dlight_it it = this->directlights.begin(); it != this->directlights.end(); ++it) {
GLuint directLightPosLoc = glGetUniformLocation(phongShader.getProgramID(), (const GLchar*) ("directLightPos[" + ToString((*it)->index) + "]").c_str());
glUniform3f(directLightPosLoc, (*it)->direction.x, (*it)->direction.y, (*it)->direction.z);
}
}
if (pointlights.size() > 0) {
for (plight_it it = this->pointlights.begin(); it != this->pointlights.end(); ++it) {
GLuint pointLightPosLoc = glGetUniformLocation(phongShader.getProgramID(), (const GLchar*) ("pointLightPos[" + ToString((*it)->index) + "]").c_str());
glUniform3f(pointLightPosLoc, (*it)->position.x, (*it)->position.y, (*it)->position.z);
}
}
if (spotlights.size() > 0) {
for (slight_it it = this->spotlights.begin(); it != this->spotlights.end(); ++it) {
GLuint spotLightPosLoc = glGetUniformLocation(phongShader.getProgramID(), (const GLchar*) ("spotLightPos[" + ToString((*it)->index) + "]").c_str());
glUniform3f(spotLightPosLoc, (*it)->position.x, (*it)->position.y, (*it)->position.z);
}
}
}
double first = GetCurrentTime() - firstFrame;
it->get()->textures = 0;
if (sun != nullptr)
if (sun->castShadow) {
glUniform1i(glGetUniformLocation(phongShader.getProgramID(), "shadowMap"), it->get()->textures);
glActiveTexture(GL_TEXTURE0 + it->get()->textures);
glBindTexture(GL_TEXTURE_2D, depthMap);
it->get()->textures++;
}
it->get()->Render(phongShader, first, deltaTime);
glBindTexture(GL_TEXTURE_2D, 0);
}
finally the shader vertex and fragment are the following:
Vertex:
#version 300 es
precision mediump float;
#define NR_DIRECT_LIGHTS 0
#define NR_POINT_LIGHTS 0
#define NR_SPOT_LIGHTS 0
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoord;
layout (location = 3) in vec3 tangent;
layout (location = 4) in ivec4 BoneIDs;
layout (location = 5) in vec4 Weights;
const int MAX_BONES = 100;
out vec2 TexCoords;
out vec3 Normal;
out vec3 tDirectLightPos[NR_DIRECT_LIGHTS];
out vec3 tPointLightPos[NR_POINT_LIGHTS];
out vec3 tSpotLightPos[NR_SPOT_LIGHTS];
out vec3 tViewPos;
out vec3 tFragPos;
out vec4 FragPosLightSpace;
// conditions //
uniform bool has_normal_map;
uniform bool skinned;
//
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec3 viewPos;
uniform mat4 lightSpaceMatrix;
uniform mat4 gBones[MAX_BONES];
uniform vec3 directLightPos[NR_DIRECT_LIGHTS];
uniform vec3 pointLightPos[NR_POINT_LIGHTS];
uniform vec3 spotLightPos[NR_SPOT_LIGHTS];
void main(){
TexCoords = texCoord;
vec4 nPos;
vec3 N=transpose(inverse(mat3(model))) * normal;
if(skinned){
mat4 BoneTransform = gBones[BoneIDs[0]] * Weights[0];
BoneTransform += gBones[BoneIDs[1]] * Weights[1];
BoneTransform += gBones[BoneIDs[2]] * Weights[2];
BoneTransform += gBones[BoneIDs[3]] * Weights[3];
nPos=BoneTransform * vec4(position, 1.0);
Normal=(BoneTransform*vec4(N,0.0)).xyz;
}
else{
nPos = vec4(position, 1.0);
Normal=N;
}
gl_Position = projection*view * model * nPos;
vec3 FragPos = vec3(model * nPos);
if(has_normal_map){
mat3 normalMatrix = transpose(inverse(mat3(model)));
vec3 T = normalize(normalMatrix * tangent);
vec3 N = normalize(N);
T = normalize(T - dot(T, N) * N);
vec3 B = cross(N,T);
if (dot(cross(N, T), B) < 0.0)
T = T * -1.0;
mat3 TBN = transpose(mat3(T, B, N));
tViewPos=TBN*viewPos;
tFragPos=TBN*FragPos;
for(int i = 0; i < NR_DIRECT_LIGHTS-2; i++)
tDirectLightPos[i]=TBN*directLightPos[i];
for(int i = 0; i < NR_POINT_LIGHTS-2; i++)
tPointLightPos[i]=TBN*pointLightPos[i];
for(int i = 0; i < NR_SPOT_LIGHTS-2; i++)
tSpotLightPos[i]=TBN*spotLightPos[i];
}
else{
tViewPos=viewPos;
tFragPos=FragPos;
}
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos,1.0);
}
Fragment:
#version 300 es
precision mediump float;
#define NR_DIRECT_LIGHTS 0
#define NR_POINT_LIGHTS 0
#define NR_SPOT_LIGHTS 0
out vec4 glFragColor;
vec2 poissonDisk[4] = vec2[](
vec2( -0.94201624, -0.39906216 ),
vec2( 0.94558609, -0.76890725 ),
vec2( -0.094184101, -0.92938870 ),
vec2( 0.34495938, 0.29387760 )
);
struct SpotLight{
vec3 position;
vec3 direction;
vec3 color;
float constant;
float linear;
float quadratic;
float cutoff;
float outerCutOff;
float intensity;
int castShadow;
};
struct PointLight{
vec3 position;
vec3 color;
float constant;
float linear;
float quadratic;
float intensity;
};
struct DirectLight {
vec3 direction;
vec3 color;
float intensity;
int castShadow;
};
in vec2 TexCoords;
in vec3 Normal;
in vec4 FragPosLightSpace;
in vec3 tDirectLightPos[NR_DIRECT_LIGHTS];
in vec3 tPointLightPos[NR_POINT_LIGHTS];
in vec3 tSpotLightPos[NR_SPOT_LIGHTS];
in vec3 tViewPos;
in vec3 tFragPos;
uniform bool Has_normal_map;
uniform sampler2D mat_diffuse;
uniform sampler2D mat_specular;
uniform sampler2D mat_normal;
uniform sampler2D shadowMap;
uniform vec3 matDiffuse;
uniform vec3 matSpecular;
uniform float shininess;
uniform float far_plane;
uniform DirectLight directLights[NR_DIRECT_LIGHTS];
uniform PointLight pointLights[NR_POINT_LIGHTS];
uniform SpotLight spotLights[NR_SPOT_LIGHTS];
vec3 calcDirectLight(DirectLight,vec3,vec3,vec3,vec3);
vec3 calcPointLight(PointLight,vec3,vec3,vec3,vec3);
vec3 calcSpotLight(SpotLight,vec3,vec3,vec3,vec3);
float directShadowCalculation();
void main(){
vec3 normal;
if(Has_normal_map){
normal=texture(mat_normal, TexCoords).rgb;
normal = normalize(normal * 2.0 - 1.0); // this normal is in tangent space
}
else
normal=normalize(Normal);
vec3 diffColor= matDiffuse+vec3(texture(mat_diffuse, TexCoords));
vec3 specColor= matSpecular+vec3(texture(mat_specular,TexCoords));
vec3 result;
result=vec3(0.0);
for(int i = 0; i < NR_DIRECT_LIGHTS-2; i++)
result += calcDirectLight(directLights[i],normal,tDirectLightPos[i],diffColor,specColor);
for(int i = 0; i < NR_POINT_LIGHTS-2; i++)
result += calcPointLight(pointLights[i],normal,tPointLightPos[i],vec3(0.0,0.2,0.4),specColor);
for(int i = 0; i < NR_SPOT_LIGHTS-2; i++)
result += calcSpotLight(spotLights[i],normal,tSpotLightPos[i],diffColor,specColor);
vec4 color =vec4(result,1.0);
float gamma = 2.2;
color.rgb = pow(color.rgb, vec3(1.0/gamma));
vec4 ambient=vec4(0.2,0.2,0.2,1.0)*vec4(diffColor,1.0);
glFragColor=ambient+color;
}
vec3 calcDirectLight(DirectLight light,vec3 norm,vec3 tLightPos,vec3 diffColor,vec3 specColor){
vec3 lightDir ;
if(Has_normal_map)
lightDir= normalize(tLightPos);
else
lightDir = normalize(light.direction);
float diff = max(dot(lightDir,norm), 0.0);
vec3 diffuse = light.color * diff *diffColor;
vec3 viewDir = normalize(tViewPos- tFragPos);
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(norm, halfwayDir), 0.0), 32.0);
vec3 specular = shininess* spec *specColor* light.color;
vec3 result;
if(light.castShadow==1){
float shadow = directShadowCalculation();
result =light.intensity* ( shadow* (diffuse + specular));
}
else
result =light.intensity* (diffuse + specular);
return result;
}
vec3 calcPointLight(PointLight light,vec3 norm,vec3 tLightPos,vec3 diffColor,vec3 specColor){
vec3 lightDir ;
if(Has_normal_map)
lightDir= normalize(tLightPos-tFragPos);
else
lightDir = normalize(light.position - tFragPos);
float diff = max(dot(lightDir,norm), 0.0);
vec3 diffuse = light.color * diff * diffColor;
vec3 viewDir = normalize(tViewPos- tFragPos);
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(norm, halfwayDir), 0.0), 16.0);
vec3 specular =shininess* specColor * spec * light.color;
vec3 result;
float distance = length(light.position - tFragPos);
float attenuation = 1.0f / (light.constant + light.linear * distance +light.quadratic * (distance * distance));
diffuse *= attenuation;
specular *= attenuation;
result=light.intensity*(diffuse+specular);
return result;
}
vec3 calcSpotLight(SpotLight light,vec3 norm,vec3 tLightPos,vec3 diffColor,vec3 specColor){
vec3 lightDir ;
if(Has_normal_map)
lightDir= normalize(tLightPos-tFragPos);
else
lightDir = normalize(light.position - tFragPos);
float diff = max(dot(lightDir,norm), 0.0);
vec3 diffuse = light.color * diff * diffColor;
vec3 viewDir = normalize(tViewPos- tFragPos);
float spec =0.0;
vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(norm, halfwayDir), 0.0), 16.0);
vec3 specular = shininess* light.color * spec * specColor;
// Spotlight (soft edges)
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = (light.cutoff - light.outerCutOff);
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
diffuse *= intensity;
specular *= intensity;
// Attenuation
float distance = length(light.position - tFragPos);
float attenuation = 1.0f / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
diffuse *= attenuation;
specular *= attenuation;
vec3 result = intensity*(diffuse+specular);
return result;
}
float directShadowCalculation(){
vec3 projCoords = FragPosLightSpace.xyz / FragPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
float shadow = 1.0;
for (int i=0;i<4;i++){
if ( texture( shadowMap, -projCoords.xy + poissonDisk[i]/700.0 ).z < -projCoords.z ){
shadow-=0.2;
}
}
if(projCoords.z > 1.0)
shadow = 0.0;
return shadow;
}
sorry for all that code but I don't know where is the problem, it takes a week searching and debugging with no progress.
Edit
1- the light position vector is (-3.5f, 8.0f, 1.0f)
2- I changed the directShadowCalculation() to:
float directShadowCalculation(){
vec3 projCoords = FragPosLightSpace.xyz / FragPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
float shadow = 1.0;
for (int i=0;i<4;i++){
if ( texture( shadowMap, projCoords.xy + poissonDisk[i]/700.0 ).z < projCoords.z ){
shadow-=0.2;
}
}
if(projCoords.z > 1.0)
shadow = 0.0;
return shadow;
}
this is the result
If you have to convert view space coordinates to the local space of the light source, then the lightSpaceMatrix would have to be setup as you do it:
lightSpaceMatrix = lightSpaceProjection * (lightSpaceView*camInv)
Because, you have to convert from view space to world space, by camInv. Then you have to convert the world space coordinates, as seen from the light source (lightSpaceView). And finaly you have to project it lightSpaceProjection.
But you convert directly from world coordinates to the local space of the light source, in the vertex shader:
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos,1.0);
Because of that you have to set up the lightSpaceMatrix like this:
lightSpaceMatrix = lightSpaceProjection * lightSpaceView
The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. It transforms from view (eye) space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates. The NDC are in range (-1,-1,-1) to (1,1,1).
This is regardless of orthographic or perspective projection.
After dividing the projected fragment position (light space) by its w component, the projCoords are in the range from (-1, -1, -1) to (1, 1, 1).
projCoords = projCoords * 0.5 + 0.5; transforms the XY coordinates to texture coordinates, and transforms the Z coordinate to a depth value in the range [0, 1].
vec3 projCoords = FragPosLightSpace.xyz / FragPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
The inversions in the shadow test make no sense, since the content of the texture should be also a depth value in the range [0,1].
The shadow test should look somehow like this:
if ( texture( shadowMap, projCoords.xy ).z < projCoords.z )
{
....
}
If sun->direction is the direction up to the sun, then lightSpaceView has to be set up like this:
glm::mat4 lightSpaceView = glm::lookAt(sun->direction, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
But, If sun->direction is the direction in which the sun shines, then lightSpaceView has to be set up like this:
glm::mat4 lightSpaceView = glm::lookAt(-sun->direction, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
Since you use orthographic projection for the light and the origin of the light space matrix is near the origin of the worldspace, the near plane of the light projection should be far in the back of the light space. Otherwise the objects which are near to the the sun would be clipped, by the near plane of the light projection, when generating the light depth map.
glm::mat4 lightSpaceProjection = glm::ortho(-40.0f, 40.0f, -40.0f, 40.0f, -100.0f, 100.0f);
Since the light calculations are done in view space, you have to convert the light positions from the world space to the view space:
GLuint directLightPosLoc = glGetUniformLocation(phongShader.getProgramID(), (const GLchar*) ("directLightPos[" + ToString((*it)->index) + "]").c_str());
glm::vec3 dir = glm::mat3(camera->getViewMatrix()) * (*it)->direction;
glUniform3fv( directLightPosLoc, 1, &dir[0] );
GLuint pointLightPosLoc = glGetUniformLocation(phongShader.getProgramID(), (const GLchar*) ("pointLightPos[" + ToString((*it)->index) + "]").c_str());
glm::vec4 pos = camera->getViewMatrix( * glm::vec4((*it)->position.x, (*it)->position.y, (*it)->position.z, 1.0);
glUniform3fv( directLightPosLoc, 1, &pos[0] );
GLuint spotLightPosLoc = glGetUniformLocation(phongShader.getProgramID(), (const GLchar*) ("spotLightPos[" + ToString((*it)->index) + "]").c_str());
glm::vec4 pos = camera->getViewMatrix( * glm::vec4((*it)->position.x, (*it)->position.y, (*it)->position.z, 1.0);
glUniform3fv( spotLightPosLoc, 1, &pos[0] );
See the WebGL example which demonstrates the algorithm:
(function loadscene() {
var sliderScale = 100.0
var gl;
var progShadow;
var progDraw;
var shadowFB;
var bufTorus;
var bufGround;
var canvas;
var vp_size;
var fb_size;
function render(deltaMS){
var ambient = document.getElementById( "ambient" ).value / sliderScale;
var diffuse = document.getElementById( "diffuse" ).value / sliderScale;
var specular = document.getElementById( "specular" ).value / sliderScale;
var shininess = document.getElementById( "shininess" ).value;
canvas = document.getElementById( "scene-canvas" );
var lightPos = [-3.0, 0.0, 2.0];
var lightAnimationMat = RotateAxis( IdentityMat44(), CalcAng( deltaMS, 20.0 ), 2 );
lightPos = Transform( lightPos, lightAnimationMat );
var lightDir = [ -lightPos[0], -lightPos[1], -lightPos[2] ];
var light = Camera.Create( lightPos, [0, 0, 0], [0, 0, 1], 110, [ 5.0, 5.0 ], -20.0, 20.0 );
var camera = Camera.Create( [0, 2.5, 2], [0, 0, 0], [0, 0, 1], 110, [vp_size[0], vp_size[1]], 0.5, 100.0 );
var lightPrjMat = Camera.Ortho( light );
var lightViewMat = Camera.LookAt( light );
var prjMat = Camera.Perspective( camera );
var viewMat = Camera.LookAt( camera );
var modelMat = IdentityMat44();
modelMat = RotateAxis( modelMat, CalcAng( deltaMS, 13.0 ), 0 );
modelMat = RotateAxis( modelMat, CalcAng( deltaMS, 17.0 ), 1 );
groundModelMat = IdentityMat44();
var viewLightDir = TransformVec( lightDir, viewMat );
gl.viewport( 0, 0, fb_size[0], fb_size[1] );
gl.enable( gl.DEPTH_TEST );
shadowFB.Bind( true );
ShaderProgram.Use( progShadow );
ShaderProgram.SetUniformM44( progShadow, "u_projectionMat44", lightPrjMat );
ShaderProgram.SetUniformM44( progShadow, "u_viewMat44", lightViewMat );
ShaderProgram.SetUniformM44( progShadow, "u_modelMat44", modelMat );
ShaderProgram.SetUniformF2( progShadow, "u_depthRange", [light.near, light.far] );
VertexBuffer.Draw( bufTorus );
gl.viewport( 0, 0, vp_size[0], vp_size[1] );
shadowFB.Release( true );
shadowFB.BindTexture( 1 );
ShaderProgram.Use( progDraw );
ShaderProgram.SetUniformM44( progDraw, "u_projectionMat44", prjMat );
ShaderProgram.SetUniformM44( progDraw, "u_viewMat44", viewMat );
ShaderProgram.SetUniformM44( progDraw, "u_lightProjectionMat44", lightPrjMat );
ShaderProgram.SetUniformM44( progDraw, "u_lightViewMat44", lightViewMat );
ShaderProgram.SetUniformM44( progDraw, "u_modelMat44", modelMat );
ShaderProgram.SetUniformI1( progDraw, "u_depthSampler", 1 );
ShaderProgram.SetUniformF3( progDraw, "u_lightDir", viewLightDir )
ShaderProgram.SetUniformF1( progDraw, "u_ambient", ambient )
ShaderProgram.SetUniformF1( progDraw, "u_diffuse", diffuse )
ShaderProgram.SetUniformF1( progDraw, "u_specular", specular )
ShaderProgram.SetUniformF1( progDraw, "u_shininess", shininess )
VertexBuffer.Draw( bufTorus );
ShaderProgram.SetUniformM44( progDraw, "u_modelMat44", groundModelMat );
VertexBuffer.Draw( bufGround );
requestAnimationFrame(render);
}
function nearestPow2( aSize ){
return Math.pow( 2, Math.round( Math.log( aSize ) / Math.log( 2 ) ) );
}
function resize() {
//vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
vp_size = [window.innerWidth, window.innerHeight]
canvas.width = vp_size[0];
canvas.height = vp_size[1];
var size = Math.max(256, Math.max(vp_size[0], vp_size[1]));
size = nearestPow2(size/2);
fb_size = [size, size]
shadowFB = FrameBuffer.Create( fb_size );
}
function initScene() {
document.getElementById( "ambient" ).value = 0.2 * sliderScale;
document.getElementById( "diffuse" ).value = 0.7 * sliderScale;
document.getElementById( "specular" ).value = 0.5 * sliderScale;
document.getElementById( "shininess" ).value = 8.0;
canvas = document.getElementById( "scene-canvas");
vp_size = [canvas.width, canvas.height];
gl = canvas.getContext( "experimental-webgl" );
if ( !gl )
return;
progShadow = ShaderProgram.Create(
[ { source : "shadow-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "shadow-shader-fs", stage : gl.FRAGMENT_SHADER }
] );
if (!progShadow.progObj)
return null;
progShadow.inPos = ShaderProgram.AttributeIndex( progShadow, "inPos" );
progShadow.inNV = ShaderProgram.AttributeIndex( progShadow, "inNV" );
progShadow.inCol = ShaderProgram.AttributeIndex( progShadow, "inCol" );
progDraw = ShaderProgram.Create(
[ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
] );
if (!progDraw.progObj)
return null;
progDraw.inPos = ShaderProgram.AttributeIndex( progDraw, "inPos" );
progDraw.inNV = ShaderProgram.AttributeIndex( progDraw, "inNV" );
progDraw.inCol = ShaderProgram.AttributeIndex( progDraw, "inCol" );
// create torus
var circum_size = 32, tube_size = 32;
var rad_circum = 1.0;
var rad_tube = 0.5;
var torus_pts = [];
var torus_nv = [];
var torus_col = [];
var torus_inx = [];
var col = [1, 0.5, 0.0];
for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
var center = [
Math.cos(2 * Math.PI * i_c / circum_size),
Math.sin(2 * Math.PI * i_c / circum_size) ]
for ( var i_t = 0; i_t < tube_size; ++ i_t ) {
var tubeX = Math.cos(2 * Math.PI * i_t / tube_size)
var tubeY = Math.sin(2 * Math.PI * i_t / tube_size)
var pt = [
center[0] * ( rad_circum + tubeX * rad_tube ),
center[1] * ( rad_circum + tubeX * rad_tube ),
tubeY * rad_tube ]
var nv = [ pt[0] - center[0] * rad_tube, pt[1] - center[1] * rad_tube, tubeY * rad_tube ]
torus_pts.push( pt[0], pt[1], pt[2] );
torus_nv.push( nv[0], nv[1], nv[2] );
torus_col.push( col[0], col[1], col[2] );
var i_cn = (i_c+1) % circum_size
var i_tn = (i_t+1) % tube_size
var i_c0 = i_c * tube_size;
var i_c1 = i_cn * tube_size;
torus_inx.push( i_c0+i_t, i_c0+i_tn, i_c1+i_t, i_c0+i_tn, i_c1+i_t, i_c1+i_tn )
}
}
bufTorus = VertexBuffer.Create(
[ { data : torus_pts, attrSize : 3, attrLoc : progDraw.inPos },
{ data : torus_nv, attrSize : 3, attrLoc : progDraw.inNV },
{ data : torus_col, attrSize : 3, attrLoc : progDraw.inCol } ],
torus_inx
);
var g_l = 8.0;
var g_h = -2.5;
var g_c = [ 0.8, 0.6, 0.8 ];
bufGround = VertexBuffer.Create(
[ { data : [ -g_l, -g_l, g_h, g_l, -g_l, g_h, g_l, g_l, g_h, -g_l, g_l, g_h ], attrSize : 3, attrLoc : progDraw.inPos },
{ data : [ 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0 ], attrSize : 3, attrLoc : progDraw.inNV },
{ data : [ g_c[0], g_c[1], g_c[2], g_c[0], g_c[1], g_c[2], g_c[0], g_c[1], g_c[2], g_c[0], g_c[1], g_c[2] ], attrSize : 3, attrLoc : progDraw.inCol } ],
[ 0, 1, 2, 0, 2, 3 ]
);
window.onresize = resize;
resize();
requestAnimationFrame(render);
}
var startTime;
function Fract( val ) {
return val - Math.trunc( val );
}
function CalcAng( deltaTime, intervall ) {
return Fract( deltaTime / (1000*intervall) ) * 2.0 * Math.PI;
}
function IdentityMat44() { return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; }
function RotateAxis(matA, angRad, axis) {
var aMap = [ [1, 2], [2, 0], [0, 1] ];
var a0 = aMap[axis][0], a1 = aMap[axis][1];
var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);
var matB = IdentityMat44();
for ( var i = 0; i < 16; ++ i ) matB[i] = matA[i];
for ( var i = 0; i < 3; ++ i ) {
matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;
matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;
}
return matB;
}
function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; }
function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
function Normalize( v ) {
var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
return [ v[0] / len, v[1] / len, v[2] / len ];
}
Transform = function(vec, mat) {
return [
vec[0] * mat[0*4+0] + vec[1] * mat[1*4+0] + vec[2] * mat[2*4+0] + mat[3*4+0],
vec[0] * mat[0*4+1] + vec[1] * mat[1*4+1] + vec[2] * mat[2*4+1] + mat[3*4+1],
vec[0] * mat[0*4+2] + vec[1] * mat[1*4+2] + vec[2] * mat[2*4+2] + mat[3*4+2],
vec[0] * mat[0*4+3] + vec[1] * mat[1*4+3] + vec[2] * mat[2*4+3] + mat[3*4+3] ]
if ( h[3] == 0.0 )
return [0, 0, 0]
return [ h[0]/h[3], h[1]/h[3], h[2]/h[3] ];
}
TransformVec = function(vec, mat) {
return [
vec[0] * mat[0*4+0] + vec[1] * mat[1*4+0] + vec[2] * mat[2*4+0],
vec[0] * mat[0*4+1] + vec[1] * mat[1*4+1] + vec[2] * mat[2*4+1],
vec[0] * mat[0*4+2] + vec[1] * mat[1*4+2] + vec[2] * mat[2*4+2] ]
}
var Camera = {};
Camera.Create = function( pos, target, up, fov_y, vp, near, far ) {
var camera = {};
camera.pos = pos;
camera.target = target;
camera.up = up;
camera.fov_y = fov_y;
camera.vp = vp;
camera.near = near;
camera.far = far;
return camera;
}
Camera.Ortho = function( camera ) {
var fn = camera.far + camera.near;
var f_n = camera.far - camera.near;
var w = camera.vp[0];
var h = camera.vp[1];
var m = IdentityMat44();
m[0] = 2 / w; m[1] = 0; m[2] = 0; m[3] = 0;
m[4] = 0; m[5] = 2 / h; m[6] = 0; m[7] = 0;
m[8] = 0; m[9] = 0; m[10] = -2 / f_n; m[11] = 0;
m[12] = 0; m[13] = 0; m[14] = -fn / f_n; m[15] = 1;
return m;
}
Camera.Perspective = function( camera ) {
var fn = camera.far + camera.near;
var f_n = camera.far - camera.near;
var r = camera.vp[0] / camera.vp[1];
var t = 1 / Math.tan( Math.PI * camera.fov_y / 360 );
var m = IdentityMat44();
m[0] = t/r; m[1] = 0; m[2] = 0; m[3] = 0;
m[4] = 0; m[5] = t; m[6] = 0; m[7] = 0;
m[8] = 0; m[9] = 0; m[10] = -fn / f_n; m[11] = -1;
m[12] = 0; m[13] = 0; m[14] = -2 * camera.far * camera.near / f_n; m[15] = 0;
return m;
}
Camera.LookAt = function( camera ) {
var mz = Normalize( [ camera.pos[0]-camera.target[0], camera.pos[1]-camera.target[1], camera.pos[2]-camera.target[2] ] );
var mx = Normalize( Cross( camera.up, mz ) );
var my = Normalize( Cross( mz, mx ) );
var tx = Dot( mx, camera.pos );
var ty = Dot( my, camera.pos );
var tz = Dot( [-mz[0], -mz[1], -mz[2]], camera.pos );
var m = IdentityMat44();
m[0] = mx[0]; m[1] = my[0]; m[2] = mz[0]; m[3] = 0;
m[4] = mx[1]; m[5] = my[1]; m[6] = mz[1]; m[7] = 0;
m[8] = mx[2]; m[9] = my[2]; m[10] = mz[2]; m[11] = 0;
m[12] = tx; m[13] = ty; m[14] = tz; m[15] = 1;
return m;
}
var ShaderProgram = {};
ShaderProgram.Create = function (shaderList) {
var shaderObjs = [];
for (var i_sh = 0; i_sh < shaderList.length; ++i_sh) {
var shderObj = this.CompileShader(shaderList[i_sh].source, shaderList[i_sh].stage);
if (shderObj == 0)
return 0;
shaderObjs.push(shderObj);
}
var prog = {}
prog.progObj = this.LinkProgram(shaderObjs)
if (prog.progObj) {
prog.attribIndex = {};
var noOfAttributes = gl.getProgramParameter(prog.progObj, gl.ACTIVE_ATTRIBUTES);
for (var i_n = 0; i_n < noOfAttributes; ++i_n) {
var name = gl.getActiveAttrib(prog.progObj, i_n).name;
prog.attribIndex[name] = gl.getAttribLocation(prog.progObj, name);
}
prog.unifomLocation = {};
var noOfUniforms = gl.getProgramParameter(prog.progObj, gl.ACTIVE_UNIFORMS);
for (var i_n = 0; i_n < noOfUniforms; ++i_n) {
var name = gl.getActiveUniform(prog.progObj, i_n).name;
prog.unifomLocation[name] = gl.getUniformLocation(prog.progObj, name);
}
}
return prog;
}
ShaderProgram.AttributeIndex = function (prog, name) { return prog.attribIndex[name]; }
ShaderProgram.UniformLocation = function (prog, name) { return prog.unifomLocation[name]; }
ShaderProgram.Use = function (prog) { gl.useProgram(prog.progObj); }
ShaderProgram.SetUniformI1 = function (prog, name, val) { if (prog.unifomLocation[name]) gl.uniform1i(prog.unifomLocation[name], val); }
ShaderProgram.SetUniformF1 = function (prog, name, val) { if (prog.unifomLocation[name]) gl.uniform1f(prog.unifomLocation[name], val); }
ShaderProgram.SetUniformF2 = function (prog, name, arr) { if (prog.unifomLocation[name]) gl.uniform2fv(prog.unifomLocation[name], arr); }
ShaderProgram.SetUniformF3 = function (prog, name, arr) { if (prog.unifomLocation[name]) gl.uniform3fv(prog.unifomLocation[name], arr); }
ShaderProgram.SetUniformF4 = function (prog, name, arr) { if (prog.unifomLocation[name]) gl.uniform4fv(prog.unifomLocation[name], arr); }
ShaderProgram.SetUniformM33 = function (prog, name, mat) { if (prog.unifomLocation[name]) gl.uniformMatrix3fv(prog.unifomLocation[name], false, mat); }
ShaderProgram.SetUniformM44 = function (prog, name, mat) { if (prog.unifomLocation[name]) gl.uniformMatrix4fv(prog.unifomLocation[name], false, mat); }
ShaderProgram.CompileShader = function (source, shaderStage) {
var shaderScript = document.getElementById(source);
if (shaderScript)
source = shaderScript.text;
var shaderObj = gl.createShader(shaderStage);
gl.shaderSource(shaderObj, source);
gl.compileShader(shaderObj);
var status = gl.getShaderParameter(shaderObj, gl.COMPILE_STATUS);
if (!status) alert(gl.getShaderInfoLog(shaderObj));
return status ? shaderObj : null;
}
ShaderProgram.LinkProgram = function (shaderObjs) {
var prog = gl.createProgram();
for (var i_sh = 0; i_sh < shaderObjs.length; ++i_sh)
gl.attachShader(prog, shaderObjs[i_sh]);
gl.linkProgram(prog);
status = gl.getProgramParameter(prog, gl.LINK_STATUS);
if (!status) alert("Could not initialise shaders");
gl.useProgram(null);
return status ? prog : null;
}
var VertexBuffer = {};
VertexBuffer.Create = function( attributes, indices ) {
var buffer = {};
buffer.buf = [];
buffer.attr = []
for ( var i = 0; i < attributes.length; ++ i ) {
buffer.buf.push( gl.createBuffer() );
buffer.attr.push( { size : attributes[i].attrSize, loc : attributes[i].attrLoc } );
gl.bindBuffer( gl.ARRAY_BUFFER, buffer.buf[i] );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( attributes[i].data ), gl.STATIC_DRAW );
}
buffer.inx = gl.createBuffer();
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, buffer.inx );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW );
buffer.inxLen = indices.length;
gl.bindBuffer( gl.ARRAY_BUFFER, null );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
return buffer;
}
VertexBuffer.Draw = function( bufObj ) {
for ( var i = 0; i < bufObj.buf.length; ++ i ) {
gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.buf[i] );
gl.vertexAttribPointer( bufObj.attr[i].loc, bufObj.attr[i].size, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( bufObj.attr[i].loc );
}
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
gl.drawElements( gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0 );
for ( var i = 0; i < bufObj.buf.length; ++ i )
gl.disableVertexAttribArray( bufObj.attr[i].loc );
gl.bindBuffer( gl.ARRAY_BUFFER, null );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
}
var FrameBuffer = {};
FrameBuffer.Create = function( vp, texturePlan ) {
var texPlan = texturePlan ? new Uint8Array( texturePlan ) : null;
var fb = gl.createFramebuffer();
var fbsize = Math.max(vp[0], vp[1]);
fbsize = 1 << 31 - Math.clz32(fbsize); // nearest power of 2
fb.width = fbsize;
fb.height = fbsize;
gl.bindFramebuffer( gl.FRAMEBUFFER, fb );
fb.color0_texture = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, fb.color0_texture );
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, fb.width, fb.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, texPlan );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
fb.renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer( gl.RENDERBUFFER, fb.renderbuffer );
gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, fb.width, fb.height );
gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fb.color0_texture, 0 );
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fb.renderbuffer );
gl.bindTexture( gl.TEXTURE_2D, null );
gl.bindRenderbuffer( gl.RENDERBUFFER, null );
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
fb.Bind = function( clear ) {
gl.bindFramebuffer( gl.FRAMEBUFFER, this );
if ( clear ) {
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
}
};
fb.Release = function( clear ) {
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
if ( clear ) {
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
}
};
fb.BindTexture = function( textureUnit ) {
gl.activeTexture( gl.TEXTURE0 + textureUnit );
gl.bindTexture( gl.TEXTURE_2D, this.color0_texture );
};
return fb;
}
initScene();
})();
html,body {
height: 100%;
width: 100%;
margin: 0;
overflow: hidden;
}
#gui {
position : absolute;
top : 0;
left : 0;
}
<script id="shadow-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec3 inPos;
attribute vec3 inNV;
attribute vec3 inCol;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
varying vec4 vPosPrj;
uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;
void main()
{
vec3 modelNV = mat3( u_modelMat44 ) * normalize( inNV );
vertNV = mat3( u_viewMat44 ) * modelNV;
vertCol = inCol;
vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
vec4 viewPos = u_viewMat44 * modelPos;
vertPos = viewPos.xyz / viewPos.w;
vPosPrj = u_projectionMat44 * viewPos;
gl_Position = vPosPrj;
}
</script>
<script id="shadow-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
varying vec4 vPosPrj;
uniform vec2 u_depthRange;
vec3 PackDepth( in float depth )
{
float depthVal = depth * (256.0*256.0*256.0 - 1.0) / (256.0*256.0*256.0);
vec4 encode = fract( depthVal * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
return encode.xyz - encode.yzw / 256.0 + 1.0/512.0;
}
void main()
{
float ndc_depth = vPosPrj.z / vPosPrj.w;
float nearZ = u_depthRange.x;
float farZ = u_depthRange.y;
float depth = ndc_depth * 0.5 + 0.5;
gl_FragColor = vec4( PackDepth( depth ).xyz, 1.0 );
}
</script>
<script id="draw-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec3 inPos;
attribute vec3 inNV;
attribute vec3 inCol;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
varying vec4 lightPrj;
varying vec4 vPosPrj;
uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;
uniform mat4 u_lightProjectionMat44;
uniform mat4 u_lightViewMat44;
void main()
{
vec3 modelNV = mat3( u_modelMat44 ) * normalize( inNV );
vertNV = mat3( u_viewMat44 ) * modelNV;
vertCol = inCol;
vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
vec4 lightPos = u_lightViewMat44 * modelPos;
vec4 viewPos = u_viewMat44 * modelPos;
lightPrj = u_lightProjectionMat44 * lightPos;
vertPos = viewPos.xyz / viewPos.w;
vPosPrj = u_projectionMat44 * viewPos;
gl_Position = vPosPrj;
}
</script>
<script id="draw-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;
varying vec4 lightPrj;
varying vec4 vPosPrj;
uniform sampler2D u_depthSampler;
uniform vec3 u_lightDir;
uniform float u_ambient;
uniform float u_diffuse;
uniform float u_specular;
uniform float u_shininess;
float UnpackDepth( in vec3 pack )
{
float depth = dot( pack, 1.0 / vec3(1.0, 256.0, 256.0*256.0) );
return depth * (256.0*256.0*256.0) / (256.0*256.0*256.0 - 1.0);
}
float Depth( in sampler2D depthSampler, in vec2 texC )
{
vec3 depthVal = texture2D( depthSampler, texC.st ).xyz;
return UnpackDepth( depthVal.rgb );
}
void main()
{
vec3 ndc_light = lightPrj.xyz / lightPrj.w;
vec2 lightTexC = ndc_light.xy * 0.5 + 0.5;
float lightDepth = ndc_light.z * 0.5 + 0.5;
float testDepth = Depth( u_depthSampler, lightTexC );
float shadow = step( lightDepth-0.01, testDepth ) + step( testDepth, 0.0 );
vec3 color = vertCol;
vec3 lightCol = u_ambient * color;
vec3 normalV = normalize( vertNV );
vec3 lightV = normalize( -u_lightDir );
float NdotL = max( 0.0, dot( normalV, lightV ) );
lightCol += shadow * NdotL * u_diffuse * color;
vec3 eyeV = normalize( -vertPos );
vec3 halfV = normalize( eyeV + lightV );
float NdotH = max( 0.0, dot( normalV, halfV ) );
float kSpecular = ( u_shininess + 2.0 ) * pow( NdotH, u_shininess ) / ( 2.0 * 3.14159265 );
lightCol += shadow * kSpecular * u_specular * color;
gl_FragColor = vec4( lightCol.rgb, 1.0 );
}
</script>
<div><form id="gui" name="inputs"><table>
<tr> <td> <font color= #CCF>ambient</font> </td>
<td> <input type="range" id="ambient" min="0" max="100" value="0"/></td> </tr>
<tr> <td> <font color= #CCF>diffuse</font> </td>
<td> <input type="range" id="diffuse" min="0" max="100" value="0"/></td> </tr>
<tr> <td> <font color= #CCF>specular</font> </td>
<td> <input type="range" id="specular" min="0" max="100" value="0"/></td> </tr>
<tr> <td> <font color= #CCF>shininess</font> </td>
<td> <input type="range" id="shininess" min="0" max="100" value="0"/></td> </tr>
</table></form></div>
<canvas id="scene-canvas" style="border: none;" width="512" height="512"></canvas>
See also
How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader
Transform the modelMatrix

Metal - the scene rendered upside down

I am trying to convert this glsl into my Metal app for learning purposes. It can render successfully. However, There are 2 issues:
the scene is upside down.
I use mouse to rotate the camera. When I move my mouse, the scene rotate to totally unseen angle.
I believe the 2 issues is related, How can I resolve this issues? Below are my Metal code:
#include <metal_stdlib>
using namespace metal;
constant const float gtime = 0.0;//<-- stop the animation for now.
constant const float pi = 3.141592653589793;
float sdPlane( float3 p) {
return p.y + 0.4;
}
float sdSphere( float3 p, float r) {
return length(p) - r;
}
float sdCapsule( float3 p, float3 a, float3 b, float r ) {
float3 pa = p - a, ba = b - a;
float h = clamp( dot(pa, ba) / dot(ba , ba), 0.0, 1.0 );
return length( pa - ba * h ) - r;
}
float motor(float _min, float _max, float time) {
float t = 0.5 + 0.5 * sin(time);
return mix(_min, _max, t);
}
float3 rotate_from_origin(float3 origin, float3 target, float r, float angle) {
return float3(
origin.x + r * cos(angle),
origin.y + r * sin(angle),
target.z
);
}
float3 preserve(float3 p0, float3 p1, float len) {
float3 v = p1 - p0;
float3 u = normalize(v);
return p0 + len * u;
}
float smin( float a, float b, float k ) {
float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
return mix( b, a, h ) - k*h*(1.0-h);
}
float2 smin2( float2 a, float2 b, float k ) {
float h = clamp( 0.5+0.5*(b.x-a.x)/k, 0.0, 1.0 );
return mix( b, a, h ) - k*h*(1.0-h);
}
float2 map( float3 p) {
float t = gtime * 2.0;
float cx = 0.2;
float cz = 0.1;
float3 p0 = float3(-cx, 0.0, 0.0);
float3 p1 = float3(-cx, -0.2, -cz);
float3 p2 = float3(-cx, -0.4, -cz);
float3 p3 = float3(-cx, 0.2, cz);
float3 p4 = float3(-cx, -0.4, cz);
float3 p5 = float3(cx, 0.0, 0.0);
float3 p6 = float3(cx, -0.2, -cz);
float3 p7 = float3(cx, -0.4, -cz);
float3 p8 = float3(cx, 0.2, cz);
float3 p9 = float3(cx, -0.4, cz);
float3 p10 = float3(0.0, 0.0, 0.0);
float3 p11 = float3(cx, -0.2, 0.0);
float angle0 = 0.0;
float angle1 = 0.0;
p0.y = -motor(-0.05, 0.05, t * 4.0);
angle0 = -motor(pi * 0.15, pi * 0.65, t * 2.0 - pi * 0.5);
angle1 = -motor(pi * 0.15, pi * 0.65, t * 2.0 + pi * 0.5);
p1 = rotate_from_origin(p0, p1, 0.2, pi-angle0);
p3 = rotate_from_origin(p0, p3, 0.2, pi-angle1);
angle0 += -motor(0.0, pi * 0.5, t * 2.0 + pi);
angle1 += -motor(0.0, pi * 0.5, t * 2.0 + pi + pi);
p2 = rotate_from_origin(p1, p2, 0.2, pi-angle0*0.6);
p4 = rotate_from_origin(p3, p4, 0.2, pi-angle1*0.6);
p5.y = -motor(-0.05, 0.05, t * 4.0);
angle0 = -motor(pi * 0.15, pi * 0.65, t * 2.0 - pi * 0.5);
angle1 = -motor(pi * 0.15, pi * 0.65, t * 2.0 + pi * 0.5);
p6 = rotate_from_origin(p5, p6, 0.2, angle0);
p8 = rotate_from_origin(p5, p8, 0.2, angle1);
angle0 += -motor(0.0, pi * 0.5, t * 2.0 + pi);
angle1 += -motor(0.0, pi * 0.5, t * 2.0 + pi + pi);
p7 = rotate_from_origin(p6, p7, 0.2, angle0*0.6);
p9 = rotate_from_origin(p8, p9, 0.2, angle1*0.6);
p10.y = -motor(-0.02, 0.02, t * 4.0 - pi * 0.5);
p11 = preserve(p5, p11, -0.25);
float w = 0.05;
float2 dd = float2(sdPlane(p - float3(0.0, -0.05, 0.0)), 1.0);
float2 d = float2(10.0);
d = smin2(d, float2(sdCapsule(p, p0, p1, w), 30.0), 0.001);
d = smin2(d, float2(sdCapsule(p, p1, p2, w), 30.0), 0.001);
d = smin2(d, float2(sdCapsule(p, p0, p3, w), 40.0), 0.001);
d = smin2(d, float2(sdCapsule(p, p3, p4, w), 40.0), 0.001);
d = smin2(d, float2(sdCapsule(p, p5, p6, w), 30.0), 0.001);
d = smin2(d, float2(sdCapsule(p, p6, p7, w), 30.0), 0.001);
d = smin2(d, float2(sdCapsule(p, p5, p8, w), 40.0), 0.001);
d = smin2(d, float2(sdCapsule(p, p8, p9, w), 40.0), 0.001);
d = smin2(d, float2(sdCapsule(p, p0, p10, w + 0.0025 * sin(p.x * pi * 60.0)), 90.0), 0.1);
d = smin2(d, float2(sdCapsule(p, p10, p5, w), 90.0), 0.1 + 0.8*(0.5 + 0.5 * sin(gtime * 0.2)));
d = smin2(d, float2(sdCapsule(p, p5, p11, w), 90.0), 0.15);
d = smin2(d, dd, 0.01);
return d;
}
float3 calcNormal( float3 p) {
float2 e = float2(-1.0, 1.0) * 0.001;
float3 nor = normalize(
e.xyy * map(p + e.xyy).x +
e.yxy * map(p + e.yxy).x +
e.yyx * map(p + e.yyx).x +
e.xxx * map(p + e.xxx).x
);
return nor;
}
float2 castRay( float3 ro, float3 rd, float maxt) {
float precis = 0.001;
float h = precis * 2.0;
float t = 0.0;
float m = -1.0;
for(int i = 0; i < 60; i++) {
if(abs(h) < precis || t > maxt) continue;
float2 res = map(ro + rd * t);
h = res.x;
t += h;
m = res.y;
}
if(t > maxt) m = -1.0;
return float2(t, m);
}
float softshadow( float3 ro, float3 rd, float mint, float maxt, float k) {
float sh = 1.0;
float t = mint;
float h = 0.0;
for(int i = 0; i < 30; i++) {
if(t > maxt) continue;
h = map(ro + rd * t).x;
sh = min(sh, k * h / t);
t += h;
}
return sh;
}
float3 render( float3 ro, float3 rd) {
float3 col = float3(1.0);
float2 res = castRay(ro, rd, 20.0);
float t = res.x;
float m = res.y;
col = 0.45 + 0.3*sin(float3(0.05,0.08,0.10)*(m-1.0)+gtime);
if(abs(m - 1.0) < 0.01) col = float3(0.5);
float3 pos = ro + rd * t;
float3 nor = calcNormal(pos);
float3 lig = normalize(float3(-0.4, 0.7, 0.5));
float dif = clamp(dot(lig, nor), 0.0, 1.0);
float spe = pow(clamp(dot(reflect(rd, nor), lig), 0.0, 1.0), 64.0);
float fre = 1.0 - dot(-rd, nor);
float sh = softshadow(pos, lig, 0.02, 20.0, 7.0);
col = 1.0*col * (dif + spe + fre * 0.5) * (0.5 + sh * 0.5);
return col;
}
kernel void compute(texture2d<float, access::write> output [[texture(0)]],
constant float &time [[buffer(1)]],
constant float &mouseX [[buffer(2)]],
constant float &mouseY [[buffer(3)]],
uint2 gid [[thread_position_in_grid]]) {
int width = output.get_width();
int height = output.get_height();
float2 uv = float2(gid) / float2(width, height);
float2 p = uv * 2.0 - 1.0;
p.x *= width / height;
float2 ms = 2.0 * float2(mouseX,mouseY) - 1.0;
float3 ro = float3(ms.x * 2.0, 2.0 - ms.y, 1.5);
float3 ta = float3(0.0, 0.0, 0.0);
float3 cw = normalize(ta - ro);
float3 cp = float3(0.0, 1.0, 0.0);
float3 cu = normalize(cross(cw, cp));
float3 cv = normalize(cross(cu, cw));
float3 rd = normalize(p.x * cu + p.y * cv + 2.5 * cw);
float3 col = render(ro, rd);
output.write(float4(col, 1.), gid);
}
Based on Marius's comment, I found out the solution. I just invert the y value by adding a - then everything become normal again:
float2 ms = 2.0 * normalize(float2(mouseX,-mouseY)) - 1.0;//<-- make mouseY negative

GLSL Shader: Half a colour value in var A, other half in var B, without conditional statement

I'm working on a texture / terrain splatting GLSL shader that will support 8 textures.
The first version I made uses RGBA as input - each channel is the intensity for each texture.
The second version I tried to double the "channels" by splitting them in half. For example;
R0 = nothing on Texture1
R64 = Half on texture 1
R127 = Full texture 1
R128 = nothing Texture 5
R196 = half texture 5
R254 = Full texture 5
andsoforth.
I've come to know that if- statements in shaders are very bad practice - it also felt like doing something wrong.
The thing is, I dont know the mathmatical functions to take half of each channel as use it as a full variable.
Here's the fragment shader code;
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform sampler2D texture; //Texture
uniform float surfWidth;
uniform float surfHeight;
uniform float xpos;
uniform float ypos;
void main()
{
//Setting the main texture position
vec2 texpos = (v_vTexcoord*vec2(surfWidth, surfHeight)) + vec2(xpos, ypos);
//Modulo 1 for repeat, devide by 4 because its a 4x4 texture sheet
float tpx = mod(texpos.x,1.0)/4.0;
float tpy = mod(texpos.y,1.0)/4.0;
//Setup terrain "intensities"
float t1 = 0.0;
float t2 = 0.0;
float t3 = 0.0;
float t4 = 0.0;
float t5 = 0.0;
float t6 = 0.0;
float t7 = 0.0;
float t8 = 0.0;
//Load from the surface (splatmap)
float btr = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).r;
float btg = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).g;
float btb = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).b;
float bta = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).a;
//Calculating what texture to use (also deviding each channel into 2)
if (btr <= 0.5) {
t1 = btr*2.0;
} else {
t5 = (btr-0.5)*2.0;
}
if (btg <= 0.5) {
t2 = btg*2.0;
} else {
t6 = (btg-0.5)*2.0;
}
if (btb <= 0.5) {
t3 = btb*2.0;
} else {
t7 = (btb-0.5)*2.0;
}
if (bta <= 0.5) {
t4 = bta*2.0;
} else {
t8 = (bta-0.5)*2.0;
}
//Get terrain pixels at proper positions
vec4 ter1 = texture2D(texture, vec2(tpx, tpy));
ter1.a = t1;
vec4 ter2 = texture2D(texture, vec2(tpx+0.25, tpy));
ter2.a = t2;
vec4 ter3 = texture2D(texture, vec2(tpx+0.50, tpy));
ter3.a = t3;
vec4 ter4 = texture2D(texture, vec2(tpx+0.75, tpy));
ter4.a = t4;
vec4 ter5 = texture2D(texture, vec2(tpx, tpy+0.25));
ter5.a = t5;
vec4 ter6 = texture2D(texture, vec2(tpx+0.25, tpy+0.25));
ter6.a = t6;
vec4 ter7 = texture2D(texture, vec2(tpx+0.50, tpy+0.25));
ter7.a = t7;
vec4 ter8 = texture2D(texture, vec2(tpx+0.75, tpy+0.25));
ter8.a = t8;
//Output to screen
gl_FragColor =
ter1*vec4(t1) +
ter2*vec4(t2) +
ter3*vec4(t3) +
ter4*vec4(t4) +
ter5*vec4(t5) +
ter6*vec4(t6) +
ter7*vec4(t7) +
ter8*vec4(t8);
}
I'm quite sure that I'm going to need something like clamp() or lerp() but I can't wrap my head around it..
Also, when textures overlap, they get "brighter" (because both textures are simply added in the last statement... I have no idea how I could prevent that from happening and always outputting a "maximum" of the texture itself (so that it doesn't "light up"). Excuse me if I sound dumb, this is my first real shader :)
Branches are not that bad on modern hardware assuming they span multiple fragments and potentially save quite a bunch of work. Writing your logic wihout branches would look like this:
btr *= 2.;
t1 = fract(min(btr,1.));
t5 = max(btr-1.,0.);
Note that with your approach you can not blend two "splatting channels" that are packed in the same color channel(i.e. blending t1 and t5). It would be simpler(and probably more efficient) to just sample another splatmap.
As to blending the final output, assuming you want to linearly blend you'd divide the individual weights by the sum of all weights.
float sum = t1+t2+t3+t4+t5+t6+t7+t8;
gl_FragColor = ter1*(t1/sum) + ter2*(t2/sum) + ter3*(t3/sum) + ...

Point Lighting Error Directx 11

I'm new to Directx 11, and I programmed a distance dependent point light shader that works pretty well for rotated and translated objects, but after I tried scaling my models, the lighting got dimmer if I scaled the model larger, and the lighting got brighter if I scaled the model smaller. I thought it might be the normals, but I made sure to multiply them by the inverse transpose of the world matrix, and I made sure to normalize them in the pixel shader after they are interpolated. Here is the shader code:
Texture2D txDiffuse : register( t0 );
SamplerState samAnisotropic
{
Filter = ANISOTROPIC;
MaxAnisotropy = 4;
};
cbuffer ConstantBuffer : register( b0 )
{
matrix World;
matrix View;
matrix Projection;
matrix WorldInvTrans;
float3 LightPos;
float pad1;
float3 EyePos;
float pad2;
float3 At;
float pad3;
float showNorms;
}
struct VS_INPUT
{
float4 Pos : POSITION;
float3 Norm : NORMAL;
float2 TexCoor : TEXCOORD0;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float3 Norm : NORMAL;
float3 LightDir : POSITION0;
float3 EyeVector : POSITION1;
float2 TexCoor : TEXCOORD0;
float distance : FLOAT0;
float showNorms : FLOAT1;
};
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, World );
output.LightDir = normalize( LightPos - output.Pos );
output.EyeVector = normalize( EyePos - At );
output.distance = distance( LightPos, output.Pos);
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = mul( input.Norm, WorldInvTrans );
output.TexCoor = input.TexCoor;
output.showNorms = showNorms;
return output;
}
float4 PS( PS_INPUT input) : SV_Target
{
input.Norm = normalize( input.Norm );
float specTerm = 0;
float3 ReflVector = normalize( reflect( input.LightDir, input.Norm ) );
[flatten]
if ( dot( ReflVector, input.EyeVector ) >= 0 )
{
specTerm = pow( dot( ReflVector, input.EyeVector ) , 50 );
}
float diffuseTerm = saturate( dot( input.LightDir, input.Norm ) );
float4 ambient = float4( 0.25f, 0.25f, 0.25f, 1.0f );
float4 lightColor = float4( 1.0f, 1.0f, 1.0f, 1.0f );
return ( (ambient + (diffuseTerm + specTerm) / (pow( input.distance, 1 ) * 0.025f)) * lightColor * txDiffuse.Sample( samAnisotropic, input.TexCoor ) ) * ( 1 - input.showNorms ) + float4( input.Norm, 1.0f ) * input.showNorms;
}
I was still suspicious that the normals weren't correct, so I edited the last line in my pixel shader to shade the model based on the normal vectors if showNorms = 1.0f. The normals looked like they were transformed correctly. Still suspicious, I replaced my model with a plane on the XZ axis, and scaled it up 50 times. When I rendered it, the lighting was still dim, but the plane was green when I set showNorms to 1.0f, which must mean that the normals are all pointing in the upwards Y direction. If I'm transforming my normals correctly and normalizing them, what could be causing these lighting errors?
If this helps, here is my code when I set the constant buffers for the plane:
//Render Plane
mWorld = XMMatrixIdentity();
cb1.mWorld = XMMatrixTranspose( XMMatrixMultiply( XMMatrixMultiply( mWorld, XMMatrixScaling( 50.0f, 1.0f, 50.0f ) ), XMMatrixTranslation( 0.0f, -5.0f, 0.0f ) ) );
XMMATRIX A = cb1.mWorld;
A.r[3] = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f);
det = XMMatrixDeterminant(A);
cb1.mWorldInvTrans = XMMatrixInverse(&det, A);
g_pImmediateContext->UpdateSubresource( g_pcBufferShader1, 0, NULL, &cb1, 0, 0 );
Edit: I changed the code a little bit to fix the specTerm:
Texture2D txDiffuse : register( t0 );
SamplerState samAnisotropic
{
Filter = ANISOTROPIC;
MaxAnisotropy = 4;
};
cbuffer ConstantBuffer : register( b0 )
{
matrix World;
matrix View;
matrix Projection;
matrix WorldInvTrans;
float3 LightPos;
float pad1;
float3 EyePos;
float pad2;
float3 At;
float pad3;
float showNorms;
}
struct VS_INPUT
{
float4 Pos : POSITION;
float3 Norm : NORMAL;
float2 TexCoor : TEXCOORD0;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float3 Norm : NORMAL;
float3 LightDir : POSITION0;
float3 EyeVector : POSITION1;
float2 TexCoor : TEXCOORD0;
float distance : FLOAT0;
float showNorms : FLOAT1;
};
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, World );
output.LightDir = LightPos - output.Pos;
output.EyeVector = EyePos - At;
output.distance = distance( LightPos, output.Pos );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = mul( input.Norm, WorldInvTrans );
output.TexCoor = input.TexCoor;
output.showNorms = showNorms;
return output;
}
float4 PS( PS_INPUT input) : SV_Target
{
input.Norm = normalize( input.Norm );
input.LightDir = normalize( input.LightDir );
input.EyeVector = normalize( input.EyeVector );
float specTerm = 0;
float3 ReflVector = normalize( reflect( -input.LightDir, input.Norm ) );
[flatten]
if ( dot( ReflVector, input.EyeVector ) >= 0 )
{
specTerm = pow( dot( ReflVector, input.EyeVector ) , 50 );
}
float diffuseTerm = saturate( dot( input.LightDir, input.Norm ) );
float4 ambient = float4( 0.25f, 0.25f, 0.25f, 1.0f );
float4 lightColor = float4( 1.0f, 1.0f, 1.0f, 1.0f );
return ( (ambient + (diffuseTerm + specTerm) / (pow( input.distance, 1 ) * 0.025f)) * lightColor * txDiffuse.Sample( samAnisotropic, input.TexCoor ) ) * ( 1 - input.showNorms ) + float4( input.Norm, 1.0f ) * input.showNorms;
}
I think you should try to normalize the LightDir vector in the pixel shader as well. If the plane is really large it may happen, that after the interpolation of these two vectors, the vector you get in the pixel shader is not normalized. This error is likely to increase as the scale goes up. Give it a try. The picture below shows this problem.