I've been trying to implement a basic fog function, and some resources I've found have led me to try a linear fog function that my understanding has led me to believe is based on the original fixed function fog equation (though I could be wrong on that). However, when I try to implement it, all my surfaces become black. I'm pretty sure my problem lies in how I (attempt to) compute the eye distance, as the rest of the equation is pretty straightforward.
My vertex shader:
precision mediump float;
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoordIn;
varying vec3 eyeNormal;
varying vec4 eyePos;
varying vec2 texCoordOut;
varying float eyeDistance;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 normalMatrix;
uniform vec3 cameraPosition;
void main()
{
eyeNormal = (normalMatrix * normal);
eyePos = modelViewMatrix * position;
eyeDistance = sqrt((eyePos.x - cameraPosition.x) * (eyePos.x - cameraPosition.x) + (eyePos.y - cameraPosition.y) * (eyePos.y - cameraPosition.y) + (eyePos.z - cameraPosition.z) * (eyePos.z - cameraPosition.z));
texCoordOut = texCoordIn;
gl_Position = modelViewProjectionMatrix * position;
}
My fragment shader:
precision mediump float;
varying vec3 eyeNormal;
varying vec4 eyePos;
varying vec2 texCoordOut;
varying float eyeDistance;
uniform sampler2D texture;
uniform vec3 flashlightPosition;
uniform vec3 diffuseLightPosition;
uniform vec4 diffuseComponent;
uniform float shininess;
uniform vec4 specularComponent;
uniform vec4 ambientComponent;
uniform float maxFogDistance;
uniform float minFogDistance;
uniform vec4 fogColor;
void main()
{
vec4 ambient = ambientComponent;
vec3 N = normalize(eyeNormal);
float nDotVP = max(0.0, dot(N, normalize(diffuseLightPosition)));
vec4 diffuse = diffuseComponent * nDotVP;
vec3 E = normalize(-eyePos.xyz);
vec3 L = normalize(flashlightPosition - eyePos.xyz);
vec3 H = normalize(L+E);
float Ks = pow(max(dot(N, H), 0.0), shininess);
vec4 specular = Ks*specularComponent;
if( dot(L, N) < 0.0 ) {
specular = vec4(0.0, 0.0, 0.0, 1.0);
}
float factor = (maxFogDistance - eyeDistance) / (maxFogDistance - minFogDistance);
factor = clamp(factor, 0.0, 1.0);
vec4 finalFogColor = factor * fogColor;
vec4 finalColor = (ambient + specular) * texture2D(texture, texCoordOut);
gl_FragColor = finalColor * factor + fogColor * (1.0 - factor);
gl_FragColor.a = 1.0;
}
Additionally, the minimum fog distance has been set to 1f and the maximum to 10f (my movement space is quite small, currently 5x5, so this should be appropriate) and the fog color is set to white.
Any help anybody could provide would be much appreciated. I can post additional code if the problem isn't in the shaders (though, I can't figure anywhere else it would be, the other aspects of the shaders worked fine before this).
Related
I am completely new to opengl es shader and cook-torrance,
the following shader only output red, no texture color processed for ambient light and point light.
the cube is for testing,no shader applied to it, the right side rocket with texture with no output,just red color. Any opengl es guy can help?
no texture only red
original texture before apply cook-torrance and output by gl_FragColor =texture2D(texture,vertTexCoord.st).rgb*vertColor;
But what make CookTorance() below fail?
fragment shader
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#define PI 3.14159265
//copper
uniform vec3 diffuseColor = vec3(0.75164,0.60648,0.22648);
uniform vec3 specularColor = vec3(0.256777,0.137622,0.086014);
uniform float F0 = 0.8;
uniform float roughness = 0.1;
uniform float k = 0.2;
//uniform vec3 lightColor = vec3(1, 1, 1);
uniform sampler2D texture;
varying vec4 varyvertColor;
varying vec3 ecNormal; //eye normal
varying vec3 lightDir;
varying vec4 varyambient;
varying vec4 varyspecular;
varying float varyshininess; //0.1
varying vec4 vertTexCoord;
varying vec4 vposition;
vec3 CookTorrance(vec3 materialDiffuseColor,
vec3 materialSpecularColor,
vec3 normal,
vec3 lightDir,
vec3 viewDir,
vec3 lightColor)
{
float NdotL = max(0, dot(normal, lightDir));
float Rs = 0.0;
if (NdotL > 0)
{
vec3 H = normalize(lightDir + viewDir);
float NdotH = max(0, dot(normal, H));
float NdotV = max(0, dot(normal, viewDir));
float VdotH = max(0, dot(lightDir, H));
// Fresnel reflectance
float F = pow(1.0 - VdotH, 5.0);
F *= (1.0 - F0);
F += F0;
// Microfacet distribution by Beckmann
float m_squared = roughness * roughness;
float r1 = 1.0 / (4.0 * m_squared * pow(NdotH, 4.0));
float r2 = (NdotH * NdotH - 1.0) / (m_squared * NdotH * NdotH);
float D = r1 * exp(r2);
// Geometric shadowing
float two_NdotH = 2.0 * NdotH;
float g1 = (two_NdotH * NdotV) / VdotH;
float g2 = (two_NdotH * NdotL) / VdotH;
float G = min(1.0, min(g1, g2));
Rs = (F * D * G) / (PI * NdotL * NdotV);
}
return materialDiffuseColor * lightColor * NdotL + lightColor * materialSpecularColor * NdotL * (k + Rs * (1.0 - k));
}
void main(){
vec3 direction = normalize(lightDir);
//vec3 normal = normalize(ecNormal);
vec3 normal = -normalize(ecNormal);
vec4 vertColor = varyambient +
vec4(CookTorrance(texture2D(texture,vertTexCoord.st).rgb*varyvertColor.xyz,
varyspecular.xyz*specularColor,
vposition.xyz,
direction,
normal,
varyvertColor.rgb),1.0);
gl_FragColor = vertColor;
}
is there any error in the above cook-torrance?
please help on it.
the vertex shader
uniform mat4 modelviewMatrix;
uniform mat4 transformMatrix;
uniform mat3 normalMatrix;
uniform mat4 texMatrix;
attribute vec4 position;
attribute vec4 color;
attribute vec3 normal;
attribute vec4 ambient;
attribute vec4 specular;
attribute float shininess;
attribute vec2 texCoord;
varying vec4 vposition;
varying vec4 vertColor;
varying vec3 ecNormal;
varying vec3 lightDir;
varying vec4 varyambient;
varying vec4 varyspecular;
varying float varyshininess;
varying vec4 varyvertColor;
varying vec4 vertTexCoord;
void main() {
// Vertex in clip coordinates
gl_Position = transformMatrix * position;
vposition = transformMatrix * position;
// Vertex in eye coordinates
vec3 ecVertex = vec3(modelviewMatrix * position);
// Normal vector in eye coordinates
ecNormal = normalize(normalMatrix * normal);
varyambient=ambient;
varyspecular=specular;
varyshininess=shininess;
varyvertColor=color;
vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);
}
How can I add lighting ( ambient + directional ) to the shader that used with InstancedBufferGeometry?
For example, I want to add lighting to this:
https://threejs.org/examples/?q=inst#webgl_buffergeometry_instancing_dynamic
Here is my vertex shader:
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
attribute vec3 position;
attribute vec3 offset;
attribute vec3 normal;
attribute vec2 uv;
attribute vec4 orientation;
varying vec2 vUv;
// lighting
struct DirectionalLight {
vec3 direction;
vec3 color;
int shadow;
float shadowBias;
float shadowRadius;
vec2 shadowMapSize;
};
uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
uniform vec3 ambientLightColor;
varying vec3 vLightFactor;
//
void main() {
vec3 vPosition = position;
vec3 vcV = cross(orientation.xyz, vPosition);
vPosition = vcV * (2.0 * orientation.w) + (cross(orientation.xyz, vcV) * 2.0 + vPosition);
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );
// lighting
vec4 ecPosition = modelViewMatrix*vec4(offset + vPosition,1.0);
vec3 ecNormal= -(normalize(normalMatrix*normal));
vec3 fromLight = normalize(directionalLights[0].direction);
vec3 toLight = -fromLight;
vec3 reflectLight = reflect(toLight,ecNormal);
vec3 viewDir = normalize(-ecPosition.xyz);
float ndots = dot(ecNormal, toLight);
float vdotr = max(0.0,dot(viewDir,reflectLight));
vec3 ambi = ambientLightColor;
vec3 diff = directionalLights[0].color * ndots;
vLightFactor = ambi + diff;
//
}
Here is my fragment shader:
precision highp float;
uniform sampler2D map;
varying vec2 vUv;
// lighting
varying vec3 vLightFactor;
//
void main() {
gl_FragColor = texture2D(map, vUv) * vec4(vLightFactor,1.0);
}
Here is my material:
var uniforms = Object.assign(
THREE.UniformsLib['lights'],
{
map: { value: texture }
}
);
var material = new THREE.RawShaderMaterial({
lights: true,
uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
});
Thanks
In a rendering, each mesh of the scene usually is transformed by the model matrix, the view matrix and the projection matrix.
The model matrix defines the location, orientation and the relative size of an mesh in the scene. The model matrix transforms the vertex positions from of the mesh to the world space.
The view matrix describes the direction and position from which the scene is looked at. The view matrix transforms from the world space to the view (eye) space.
Note, The model view matrix modelViewMatrix is the combination of the view matrix and the model matrix. But in your case, the model matrix is possibly the identity matrix, and the modelViewMatrix is possibly equal to the view matrix. I assume that, because you don't do the model transformations by a model matrix, but by the vectors orientation and offset.
The light can either be calculated in view space or in world space.
If the light is calculated in view space the light positions and light directions have to be transformed from world space to view space. Commonly this is done on the CPU (before every frame) and the light parameters uniforms are set up with view space coordinates. Since the view position is (0, 0, 0) in view space, is the view vector the the normalized and inverse vertex position (in view space).
If the light calculations are done in world space, then the view vector has to be calculated by the difference of the view position (eye position) and the vertex position (of course in world space).
You can do the light calculations in view space, because the light direction and position is set up in view space (see three.js - Light). You have to transform the normal vector to world space first and then you have to convert from world space to view space. This has to be done similar as you do it for the vertex position. Add the normal vector to the vertex position. Transform this position to world space. The normal vector in world space, is the difference of the calculated position and the vertex position in world space.
vec3 wNPosition = position + normal;
vec3 wNV = cross(orientation.xyz, wNPosition);
wNPosition = wNV * 2.0 * orientation.w + cross(orientation.xyz, wNV) * 2.0 + wNPosition;
vec3 wNormal = normalize( wNPosition - vPosition );
Under this assumption, your shader code might look like this:
vec3 wPosition = position;
vec3 wV = cross(orientation.xyz, wPosition);
wPosition = offset + wV * 2.0 * orientation.w + cross(orientation.xyz, wV) * 2.0 + wPosition;
vec4 ecPosition = modelViewMatrix * vec4(wPosition, 1.0);
vUv = uv;
gl_Position = projectionMatrix * ecPosition;
// transform normal vector to world space
vec3 wNPosition = position + normal;
vec3 wNV = cross(orientation.xyz, wNPosition);
wNPosition = offset + wNV * 2.0 * orientation.w + cross(orientation.xyz, wNV) * 2.0 + wNPosition;
vec3 ecNormal = normalize(mat3(modelViewMatrix) * (wNPosition - wPosition));
// ambient light
vLightFactor = ambientLightColor;
// diffuse light
vec3 ecToLight = normalize(directionalLights[0].direction);
float NdotL = max(0.0, dot(ecNormal, ecToLight));
vLightFactor += NdotL * directionalLights[0].color;
If you want to add specular light you have to do it like this:
// specular light
vec3 ecReflectLight = reflect( ecFromLight, ecNormal );
vec3 ecViewDir = normalize(-ecPosition.xyz);
float VdotR = max(0.0, dot(ecViewDir, ecReflectLight));
float kSpecular = 4.0 * pow( VdotR, 0.3 * shininess ); // <--- set up shininess parameter
vLightFactor += kSpecular * directionalLights[0].color;
Extension to the answer: Per fragment lighting
While Gouraud shading calculates the light in the the vertex shader, Phong shading calculates the light in the fragment shader.
(see further GLSL fixed function fragment program replacement)
Vertex shader:
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
attribute vec3 position;
attribute vec3 offset;
attribute vec3 normal;
attribute vec2 uv;
attribute vec4 orientation;
varying vec2 vUv;
varying vec3 ecPosition;
varying vec3 ecNormal;
void main()
{
vec3 wPosition = position;
vec3 wV = cross(orientation.xyz, wPosition);
pos = offset + wV * 2.0 * orientation.w + cross(orientation.xyz, wV) * 2.0 + wPosition;
vec4 vPos = modelViewMatrix * vec4(wPosition, 1.0);
ecPosition = vPos.xyz;
vUv = uv;
gl_Position = projectionMatrix * vPos;
// transform normal vector to world space
vec3 wNPosition = position + normal;
vec3 wNV = cross(orientation.xyz, wNPosition);
wNPosition = offset + wNV * 2.0 * orientation.w + cross(orientation.xyz, wNV) * 2.0 + wNPosition;
ecNormal = normalize(mat3(modelViewMatrix) * (wNPosition - wPosition));
}
Fragment shader:
precision highp float;
varying vec2 vUv;
varying vec3 ecPosition;
varying vec3 ecNormal;
uniform sampler2D map;
uniform mat4 modelViewMatrix;
struct DirectionalLight {
vec3 direction;
vec3 color;
int shadow;
float shadowBias;
float shadowRadius;
vec2 shadowMapSize;
};
uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
uniform vec3 ambientLightColor;
void main()
{
// ambient light
float lightFactor = ambientLightColor;
// diffuse light
vec3 ecToLight = normalize(directionalLights[0].direction);
float NdotL = max(0.0, dot(ecNormal, ecToLight));
lightFactor += NdotL * directionalLights[0].color;
// specular light
vec3 ecReflectLight = reflect( ecFromLight, ecNormal );
vec3 ecViewDir = normalize(-ecPosition.xyz);
float VdotR = max(0.0, dot(ecViewDir, ecReflectLight));
float kSpecular = 4.0 * pow( VdotR, 0.3 * shininess ); // <--- set up shininess parameter
lightFactor += kSpecular * directionalLights[0].color;
gl_FragColor = texture2D(map, vUv) * vec4(vec3(lightFactor), 1.0);
}
see also
Transform the modelMatrix
How does this faking the light work on aerotwist?
GLSL fixed function fragment program replacement
what i mean is the fragment shader should look like this:
precision highp float;
varying vec2 vUv;
varying vec3 ecPosition;
varying vec3 ecNormal;
uniform sampler2D map;
uniform mat4 modelViewMatrix;
struct DirectionalLight {
vec3 direction;
vec3 color;
int shadow;
float shadowBias;
float shadowRadius;
vec2 shadowMapSize;
};
uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
uniform vec3 ambientLightColor;
void main()
{
// ambient light
vec3 lightFactor = ambientLightColor;
// diffuse light
vec3 ecFromLight = normalize(directionalLights[0].direction);
//vec3 ecToLight = -ecFromLight;
float NdotL = max(0.0, dot(ecNormal, ecFromLight));
lightFactor += NdotL * directionalLights[0].color;
// specular light
/*
float shininess = 10.01;
vec3 ecReflectLight = reflect( ecFromLight, ecNormal );
vec3 ecViewDir = normalize(-ecPosition.xyz);
float VdotR = max(0.0, dot(ecViewDir, ecReflectLight));
float kSpecular = 4.0 * pow( VdotR, 0.3 * shininess ); // <--- set up shininess parameter
lightFactor += kSpecular * directionalLights[0].color;
*/
gl_FragColor = texture2D(map, vUv) * vec4(lightFactor, 1.0);
}
I'm implementing the xToon shader(pdf) in glsl to use as a shader with Three.js.
I'm getting some rendering artifacts, and I think the problem is due to webgl strangeness that I am not knowledgable about, perhaps relating to a Nan or Inf or something... I'm pulling my hair out.
I'll include the complete fragment and vertex shaders below, but I think this is the offending code located in the fragment shader:
....
vec3 n = normalize(vNormal);
vec3 l = normalize(lightDir);
float d = dot(n, l) * 0.5 + 0.5;
//vec2 texLookUp = vec2(d, loa);
vec2 texLookUp = vec2(d, 0.055);
vec4 dColor = texture2D(texture, texLookUp);
gl_FragColor = dColor;
....
To the best of my debugging efforts there seems to be some problem with using the value d as a component of the texture look up vector. This code produces these strange artifacts:
There shouldn't be those yellow "lines" on those contours...
As you may have noted, I'm not actually using the "loa" value in this code. For a while I thought that this problem was in the way I was calculating loa, but it seems that this bug is independent of loa.
Any help would be much appreciated!
The fragment shader:
uniform vec3 lightDir;
uniform sampler2D texture;
varying vec3 vNormal;
varying vec3 vPosition;
varying vec2 vUv;
// loa calculation for texture lookup
varying highp float loa;
void main() {
vec3 n = normalize(vNormal);
vec3 l = normalize(lightDir);
float d = dot(n, l) * 0.5 + 0.5;
//vec2 texLookUp = vec2(d, loa);
vec2 texLookUp = vec2(d, 0.055);
vec4 dColor = texture2D(texture, texLookUp);
gl_FragColor = dColor;
}
And the vertex shader:
uniform vec3 cameraPos;
uniform vec3 lightDir;
uniform vec3 focalPos;
uniform float inflate;
uniform float zmin;
uniform float r;
varying vec3 vNormal;
varying vec2 vUv;
varying float loa;
void main() {
vec3 n = normalize(normal);
// euclidiean distance to point from camera pos
float depth = length(cameraPos - position);
// 1. detail mapping correcting for perspective projection
float z = depth / zmin;
loa = 1.0 - (log2(z)/log2(r));
loa = clamp(loa, 0.055, 0.9);
vNormal = n;
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(normal * inflate + position, 1.0 );
}
I solved the problem by setting the texture to ClampToEdgeWrapping instead of RepeatWrapping. I was led to this answer by this stack overflow question:
Using floor() function in GLSL when sampling a texture leaves glitch
The solution is explained very well in this blog post:
http://webglfundamentals.org/webgl/lessons/webgl-3d-textures.html
And the functions to deal with this in THREEjs are members of the Texture and are explained in the THREEjs docs here.
Also I needed to set the min filter to Nearest to fully get rid of the artifacts.
My phong fragment shader is not shading anything, just making everything black.
This is my fragment shader
precision mediump float;
varying vec3 vposition;
varying vec3 vnormal;
varying vec4 vcolor;
varying vec3 veyePos;
void main() {
vec3 lightPos = vec3(0,0,0);
vec4 s = normalize(vec4(lightPos,1) - vec4(veyePos,1));
vec4 r = reflect(-s,vec4(vnormal, 1));
vec4 v = normalize(-vec4(veyePos, 1));
float spec = max( dot(v,r),0.0 );
float diff = max(dot(vec4(vnormal,1),s),0.0);
vec3 diffColor = diff * vec3(1,0,0);
vec3 specColor = pow(spec,3.0) * vec3(1,1,1);
vec3 ambientColor = vec3(0.1,0.1,0.1);
gl_FragColor = vec4(diffColor + 0.5 * specColor + ambientColor, 1);
}
This is my vertex shader
uniform mat4 uMVPMatrix;
uniform mat4 uMVMatrix;
uniform vec3 eyePos;
attribute vec4 aPosition;
attribute vec4 aColor;
attribute vec4 aNormal;
varying vec4 vcolor;
varying vec3 vposition;
varying vec3 vnormal;
varying vec3 veyePos;
void main() {
mat4 normalMat = transpose(inverse(uMVMatrix));
vec4 vertPos4 = uMVMatrix * vec4(vec3(aPosition), 1.0);
vposition = vec3(vertPos4) / vertPos4.w;
vcolor = aColor;
veyePos = eyePos;
vnormal = vec3(uMVMatrix * vec4(vec3(aNormal),0.0));
gl_Position = uMVPMatrix * aPosition;
}
MVMatrix is model-view matrix
MVPMatrix is model-view-projection matrix
first of all your lighting equations are incorrect:
vector s that you use to calculate the diffuse color should be a unit vector that originates at your vertex (vposition) towards your light. so it would be
s = normalize(lightPos - vposition)
also lightPos should be given in camera space and not in world space (so you should multiply it by your MV matrix)
vector r is the reflection of s around the normal so i dont understand why you take -s also the normal there should be in non-homegenous coordinates so it would be:
r = reflect(s,vnormal)
and finally v is the viewing ray (multiplied by -1) so it should be the vector that originates at vposition and goes towards eyepos.
v = normalize(veyepos - vposition)
also in your vertex shader veyepos (assuming it is the position of your camera) should not be varying (should be flat variable) because you dont want to interpolate it.
in your vertex shader you calculate normalMat but you forgot to use it when calculating your normals in camera space.
also normalMat should be mat3 because it is the inverse transpose of the
3by3 block of your MV matrix originating at (0,0)
** in order to be efficient you should calculate your normalMat on the cpu and pass it as a uniform to your vertex shader
hope this helps
I'm very new to OpenGL, GLSL and WebGL. I'm trying to get this sample code to work in a tool like http://shdr.bkcore.com/ but I can't get it to work.
Vertex Shader:
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
Fragment Shader:
precision highp float;
uniform float time;
uniform vec2 resolution;
varying vec3 fPosition;
varying vec3 fNormal;
uniform sampler2D tex0;
void main()
{
float border = 0.01;
float circle_radius = 0.5;
vec4 circle_color = vec4(1.0, 1.0, 1.0, 1.0);
vec2 circle_center = vec2(0.5, 0.5);
vec2 uv = gl_TexCoord[0].xy;
vec4 bkg_color = texture2D(tex0,uv * vec2(1.0, -1.0));
// Offset uv with the center of the circle.
uv -= circle_center;
float dist = sqrt(dot(uv, uv));
if ( (dist > (circle_radius+border)) || (dist < (circle_radius-border)) )
gl_FragColor = bkg_color;
else
gl_FragColor = circle_color;
}
I figured that this code must be from an outdated version of the language, so I changed the vertex shader to:
precision highp float;
attribute vec2 position;
attribute vec3 normal;
varying vec2 TextCoord;
attribute vec2 textCoord;
uniform mat3 normalMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec3 fNormal;
varying vec3 fPosition;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
TextCoord = vec2(textCoord);
}
That seemed to fix the error messages about undeclared identifiers and not being able to "convert from 'float' to highp 4-component something-or-other", but I have no idea if, functionally, this will do the same thing as the original intended.
Also, when I convert to this version of the Vertex Shader I have no idea what I'm supposed to do with this line in the Fragment Shader:
vec2 uv = gl_TexCoord[0].xy;
How do I convert this line to fit in with the converted vertex shader and how can I be sure that the vertex shader is even converted correctly?
gl_TexCoord is from desktop OpenGL, and not part of OpenGL ES. You'll need to create a new user-defined vec2 varying to hold the coordinate value.