WebGL lighting isn't applied to some edges? - opengl-es

No idea what this is called, but when viewing my model at a distance, it doesn't look like the lighting is being applied to some of the edges, which makes them stand out. Any ideas? I'm not using any textures.
Vertex Shader:
attribute vec3 aPosition;
attribute vec3 aNormal;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat4 uNormalMatrix;
varying vec3 vLighting;
void main(void) {
vec3 ambientLight = vec3(0.2, 0.2, 0.2);
vec3 directionalLight = vec3(1.0, 0.5, 0.5);
vec3 directionalLightDirection = vec3(0.8, 0.7, 0.6);
vec4 transformedNormal = uNormalMatrix * vec4(aNormal, 1.0);
float directional = max(dot(transformedNormal.xyz, directionalLightDirection), 0.0);
vLighting = ambientLight + (directionalLight * directional);
gl_Position = uPMatrix * uMVMatrix * vec4(aPosition / 80.0, 1.0);
}
Fragment Shader:
precision mediump float;
varying vec3 vLighting;
void main(void) {
vec4 skin = vec4(0.8, 0.6, 0.4, 1.0);
gl_FragColor = vec4(skin.rgb * vLighting, skin.a);
}
Picture:

Related

Incorrect lighting of a bone-animated object on OpenGL ES 2.0

I imported a simple animated object from Blender on three bones. I have a problem with lighting of skinning object. I set a light position above the object:
const vec3 lightPosition = vec3(0.0, 15.0, 0.0);
You can see that lighting is affected under object too:
precision mediump float;
attribute vec3 aPosition;
attribute vec4 aNormal;
attribute vec2 aTexCoord;
attribute vec3 aJoints;
attribute vec3 aWeights;
uniform mat4 uMvpMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uNormalMatrix;
uniform mat4 uTransforms[3];
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vTexCoord;
void main()
{
vec4 totalLocalPos = vec4(0.0);
vec4 totalNormal = vec4(0.0);
for (int i = 0; i < 3; i++)
{
int jointIndex = int(aJoints[i]);
mat4 jointTransform = uTransforms[jointIndex];
vec4 posePosition = jointTransform * vec4(aPosition, 1.0);
totalLocalPos += posePosition * aWeights[i];
vec4 worldNormal = jointTransform * aNormal;
totalNormal += worldNormal * aWeights[i];
}
gl_Position = uMvpMatrix * totalLocalPos;
vPosition = vec3(uModelMatrix * vec4(aPosition, 1.0));
vNormal = totalNormal.xyz;
vTexCoord = aTexCoord;
}
precision mediump float;
const vec3 lightColor = vec3(0.8, 0.8, 0.8);
const vec3 lightPosition = vec3(0.0, 15.0, 0.0);
const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
uniform sampler2D uSampler;
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vTexCoord;
void main()
{
vec4 color = texture2D(uSampler, vTexCoord);
vec3 normal = normalize(vNormal);
vec3 lightDirection = normalize(lightPosition - vPosition);
float nDotL = max(dot(lightDirection, normal), 0.0);
vec3 diffuse = lightColor * color.rgb * nDotL;
vec3 ambient = ambientLight * color.rgb;
gl_FragColor = vec4(diffuse + ambient, color.a);
}
Aroch helped me on Russian forum here:
the normal only needs to be rotated.
Now it works as it should. I took shaders (except lighting model) from source for a video tutorial series from ThinMatrix. It works fine for ThinMatrix. This means that for some reason its lighting model is not affected by the translation of the normal vector. It will be necessary to figure out later why he does not have this problem. I made the transfer of the array of rotation matrices a separate uniform:
uniform mat4 uTransforms[3];
uniform mat4 uRotations[3];
...
for (int i = 0; i < 3; i++)
{
int jointIndex = int(aJoints[i]);
mat4 jointTransform = uTransforms[jointIndex];
vec4 posePosition = jointTransform * vec4(aPosition, 1.0);
totalLocalPos += posePosition * aWeights[i];
mat4 rotation = uRotations[jointIndex];
vec4 worldNormal = rotation * aNormal;
totalNormal += worldNormal * aWeights[i];
}
Gif Animation: https://gamedev.ru/files/images/solution-with-lighting.gif

Shader wireframe of an object

I want to see a wireframe of an object without the diagonals like
Currently, I add lines according to the vertices, the problem is after I have several of those I experience a major performance degradation.
The examples here are either too new for my version of Three or don't work (I commented there about it).
So I want to try to implement a shader instead.
I tried to use this shader: https://stackoverflow.com/a/31610464/4279201 but it breaks the shape to parts and I'm getting WebGL errors.
That's how I use it:
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`
const fragmentShader = `
#version 150 compatibility
flat in float diffuse;
flat in float specular;
flat in vec3 edge_mask;
in vec2 bary;
uniform float mesh_width = 1.0;
uniform vec3 mesh_color = vec3(0.0, 0.0, 0.0);
uniform bool lighting = true;
out vec4 frag_color ;
float edge_factor(){
vec3 bary3 = vec3(bary.x, bary.y, 1.0 - bary.x - bary.y);
vec3 d = fwidth(bary3);
vec3 a3 = smoothstep(vec3(0.0, 0.0, 0.0), d * mesh_width, bary3);
a3 = vec3(1.0, 1.0, 1.0) - edge_mask + edge_mask * a3;
return min(min(a3.x, a3.y), a3.z);
}
void main() {
float s = (lighting && gl_FrontFacing) ? 1.0 : -1.0;
vec4 Kdiff = gl_FrontFacing ?
gl_FrontMaterial.diffuse : gl_BackMaterial.diffuse;
float sdiffuse = s * diffuse;
vec4 result = vec4(0.1, 0.1, 0.1, 1.0);
if (sdiffuse > 0.0) {
result += sdiffuse * Kdiff +
specular * gl_FrontMaterial.specular;
}
frag_color = (mesh_width != 0.0) ?
mix(vec4(mesh_color, 1.0), result, edge_factor()) :
result;
}`
...
const uniforms = {
color: {
value: new THREE.Vector4(0, 0, 1, 1),
type: 'v4'
}
}
const material = new THREE.ShaderMaterial({
fragmentShader: data.fragmentShader,
vertexShader: data.vertexShader,
uniforms
})
this._viewer.impl.matman().addMaterial(
data.name, material, true)
const fragList = this._viewer.model.getFragmentList()
this.toArray(fragIds).forEach((fragId) => {
fragList.setMaterial(fragId, material)
})
So to implement this shader, is the right approach would be to basically check the angle between every two vertices, and draw a line if the degree is 90?
How can I have access to all the vertices of the shape from the vertex shader?
And how can I tell the fragment shader to draw a line between two vertices that match the above condition? (also to leave the default shading for everything else as is)
I'm using Autodesk viewer that uses Three.js rev 71.
// -- Vertex Shader --
precision mediump float;
// Input from buffers
attribute vec3 aPosition;
attribute vec2 aBaryCoord;
// Value interpolated accross pixels and passed to the fragment shader
varying vec2 vBaryCoord;
// Uniforms
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;
void main() {
vBaryCoord = aBaryCoord;
gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(aPosition,1.0);
}
// ---------------------
// -- Fragment Shader --
// This shader doesn't perform any lighting
precision mediump float;
varying vec2 vBaryCoord;
uniform vec3 uMeshColour;
float edgeFactor() {
vec3 d = fwidth(vBaryCoord);
vec3 a3 = smoothstep(vec3(0.0,0.0,0.0),d * 1.5,vBaryCoord);
return min(min(a3.x,a3.y),a3.z);
}
void main() {
gl_FragColor = vec4(uMeshColour,(1.0 - edgeFactor()) * 0.95);
}
// ---------------------
/*
This code isn't tested so take it with a grain of salt
Idea taken from
http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/
*/

Three.js ShaderMaterial lighting not working

I'm experimenting with Three.js ShaderMaterial and trying to implement lighting.
I have working code for r70 but the same code (with minor changes - the MAX_POINT_LIGHTS constant has been renamed NUM_POINT_LIGHTS) doesn't work for r76.
Looking at a trace in WebGL Inspector it's clear that no light data is being sent to the shader. So, has lighting broken or do I need to set up something else to get it to work?
Using r70 (working)
http://codepen.io/anon/pen/KzjXNr?editors=1010
Fragment Shader
uniform vec3 diffuse;
varying vec3 vPos;
varying vec3 vNormal;
uniform vec3 pointLightColor[MAX_POINT_LIGHTS];
uniform vec3 pointLightPosition[MAX_POINT_LIGHTS];
uniform float pointLightDistance[MAX_POINT_LIGHTS];
void main() {
vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
for(int l = 0; l < MAX_POINT_LIGHTS; l++) {
vec3 lightDirection = normalize(vPos - pointLightPosition[l]);
addedLights.rgb += clamp(dot(-lightDirection, vNormal), 0.0, 1.0) * pointLightColor[l];
}
gl_FragColor = addedLights;
}
JavaScript - setting up the Shadermaterial with UniformsUtils and UniformsLib
var uniforms = THREE.UniformsUtils.merge([
THREE.UniformsLib['lights'],
{ diffuse: { type: 'c', value: new THREE.Color(0xff00ff) } }
]);
var vertexShader = document.getElementById('vertexShader').text;
var fragmentShader = document.getElementById('fragmentShader').text;
material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
lights: true
});
var geometry = new THREE.BoxGeometry(200, 200, 200);
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
Using r76 (futzed)
http://codepen.io/anon/pen/ZWdXLZ?editors=1010
Fragment Shader
uniform vec3 diffuse;
varying vec3 vPos;
varying vec3 vNormal;
uniform vec3 pointLightColor[NUM_POINT_LIGHTS];
uniform vec3 pointLightPosition[NUM_POINT_LIGHTS];
uniform float pointLightDistance[NUM_POINT_LIGHTS];
void main() {
vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
vec3 lightDirection = normalize(vPos - pointLightPosition[l]);
addedLights.rgb += clamp(dot(-lightDirection, vNormal), 0.0, 1.0) * pointLightColor[l];
}
gl_FragColor = addedLights;
}
JavaScript
Unchanged
The light uniforms have been changed to structs in r74 (Specifically in #7324). Note that though the change to structs happened in r74, the following works r75 and later.
A single array of structs is given for each light type. Each struct has the position and color properties you need.
Fragment Shader
uniform vec3 diffuse;
varying vec3 vPos;
varying vec3 vNormal;
struct PointLight {
vec3 position;
vec3 color;
};
uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
void main() {
vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
vec3 adjustedLight = pointLights[l].position + cameraPosition;
vec3 lightDirection = normalize(vPos - adjustedLight);
addedLights.rgb += clamp(dot(-lightDirection, vNormal), 0.0, 1.0) * pointLights[l].color;
}
gl_FragColor = addedLights;//mix(vec4(diffuse.x, diffuse.y, diffuse.z, 1.0), addedLights, addedLights);
}
Note that the light position is now relative to the camera so you offset the light position with the camera position.
Working Fiddle

Same texture offseting different position in the fragment shader using threejs rendering engine

My vertex shader:
varying vec2 texCoord;
void main() {
texCoord = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
My fragment shader:
varying vec2 texCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float multiplier;
void main( void ) {
vec3 tex1 = texture2D(texture1, texCoord).xyz ;
vec3 tex2 = texture2D(texture2, texCoord).xyz ;
vec3 finaltex = mix( tex1, tex2, multiplier) ;
gl_FragColor = vec4(finaltex , 1.0);
}
Now this work very well when i run using the two texture.check http://shaderfrog.com/app/view/68 for the multiplier action.
But now what I want is I am having texture like this:
So with the single texture I want to index the offset of my texCoord so that I just need to sample one texture and I can get three representation form this like:
var shaderMaterial = new THREE.ShaderMaterial({
uniforms:{
texture1: { type: "t", value: texture1 }
},
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
});
Can offset my tri-color in the fragment shader. or Some one can help me modifying the fragment shader so that I can pass uniform to index my tri-color into individual Yellow,pink,red.
So either from shader or threejs I can get help regarding same.
I have done reference using two texture because I want to interpolate with cross fade effect on the texture same I want cross fade using fragment shader (independent to this I have already achieve by the texture.offset.x = currentColoum / horizontal and texture.offset.y = currentRow / Vertical;
I found the answer to this question, even implemented into application :D.
vertexShader:
void main() {
texCoord = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
FragmentShader:
varying vec2 texCoord;
uniform sampler2D texture;
uniform vec2 offset_current;
uniform vec2 offset_next;
uniform float multiplier;
void main( void ) {
vec2 offset1 = offset_current + vec2( texCoord.x* 1.0, texCoord.y * 0.333333);
vec2 offset2 = offset_next + vec2( texCoord.x* 1.0, texCoord.y * 0.333333);
vec3 tex1 = texture2D(texture1,offset1).xyz ;
vec3 tex2 = texture2D(texture1, offset2).xyz ;
vec3 mixCol = mix( tex1, tex2, multiplier );
vec4 fragColor = vec4(mixCol, 1.0);
if(fragColor.a == 0.0)
discard;
gl_FragColor = fragColor;
}
Explanation:
Since I am having the vertical texture of three different type I make my offset into y direction 0.3333. Because texture is read from [0,1]. I have extended this code same for the horizontal direction.
If some one going to make this dynamic then instead of hard coded we can pass the 0.3333 as the calculate one taking the inspiration form link.

Shadow artifacts in opengl

I am trying to render an object and two lights, one of the lights cast shadows. Everything works ok but I noticed that there are some obvious artifacts, as shown in the below image, some shadows seem to overflow to bright areas.
Below is the shaders to render depth information into a framebuffer
<script id="shadow-shader-vertex" type="x-shader/x-vertex">
attribute vec4 aVertexPosition;
uniform mat4 uObjMVP;
void main() {
gl_Position = uObjMVP * aVertexPosition;
}
</script>
<script id="shadow-shader-fragment" type="x-shader/x-vertex">
precision mediump float;
void main() {
//pack gl_FragCoord.z
const vec4 bitShift = vec4(1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0);
const vec4 bitMask = vec4(1.0/256.0, 1.0/256.0, 1.0/256.0, 0.0);
vec4 rgbaDepth = fract(gl_FragCoord.z * bitShift);
rgbaDepth -= rgbaDepth.gbaa * bitMask;
gl_FragColor = rgbaDepth;
}
</script>
In the above shaders, uObjMVP is the MVP matrix used when looking from the position of the light that cast shadow (the warm light, the cold light does not cast shadow)
And here are the shaders to draw everything:
<script id="shader-vertex" type="x-shader/x-vertex">
//position of a vertex.
attribute vec4 aVertexPosition;
//vertex normal.
attribute vec3 aNormal;
//mvp matrix
uniform mat4 uObjMVP;
uniform mat3 uNormalMV;
//shadow mvp matrix
uniform mat4 uShadowMVP;
//interplate normals
varying vec3 vNormal;
//for shadow calculation
varying vec4 vShadowPositionFromLight;
void main() {
gl_Position = uObjMVP * aVertexPosition;
//convert normal direction from object space to view space
vNormal = uNormalMV * aNormal;
vShadowPositionFromLight = uShadowMVP * aVertexPosition;
}
</script>
<script id="shader-fragment" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D uShadowMap;
varying vec3 vNormal;
varying vec4 vShadowPositionFromLight;
struct baseColor {
vec3 ambient;
vec3 diffuse;
};
struct directLight {
vec3 direction;
vec3 color;
};
baseColor mysObjBaseColor = baseColor(
vec3(1.0, 1.0, 1.0),
vec3(1.0, 1.0, 1.0)
);
directLight warmLight = directLight(
normalize(vec3(-83.064, -1.99, -173.467)),
vec3(0.831, 0.976, 0.243)
);
directLight coldLight = directLight(
normalize(vec3(37.889, 47.864, -207.187)),
vec3(0.196, 0.361, 0.608)
);
vec3 ambientLightColor = vec3(0.3, 0.3, 0.3);
float unpackDepth(const in vec4 rgbaDepth) {
const vec4 bitShift = vec4(1.0, 1.0/256.0, 1.0/(256.0*256.0), 1.0/(256.0*256.0*256.0));
float depth = dot(rgbaDepth, bitShift);
return depth;
}
float calVisibility() {
vec3 shadowCoord = (vShadowPositionFromLight.xyz/vShadowPositionFromLight.w)/2.0 + 0.5;
float depth = unpackDepth(texture2D(uShadowMap, shadowCoord.xy));
return (shadowCoord.z > depth + 0.005) ? 0.4 : 1.0;
}
vec3 calAmbientLight(){
return ambientLightColor * mysObjBaseColor.ambient;
}
vec3 calDiffuseLight(const in directLight light, const in float visibility){
vec3 inverseLightDir = light.direction * -1.0;
float dot = max(dot(inverseLightDir, normalize(vNormal)), 0.0);
return light.color * mysObjBaseColor.diffuse * dot * visibility;
}
void main() {
vec3 ambientLight = calAmbientLight();
float visibility = calVisibility();
vec3 warmDiffuseLight = calDiffuseLight(warmLight, visibility);
// cold light does not cast shadow and hence visilibility is always 1.0
vec3 coldDiffuseLight = calDiffuseLight(coldLight, 1.0);
gl_FragColor = vec4(coldDiffuseLight + warmDiffuseLight + ambientLight, 1.0);
}
</script>
If I simply draw the depth information out on to the canvas,
void main() {
// vec3 ambientLight = calAmbientLight();
// float visibility = calVisibility();
// vec3 warmDiffuseLight = calDiffuseLight(warmLight, visibility);
// // cold light does not cast shadow and hence visilibility is always 1.0
// vec3 coldDiffuseLight = calDiffuseLight(coldLight, 1.0);
// gl_FragColor = vec4(coldDiffuseLight + warmDiffuseLight + ambientLight, 1.0);
vec3 shadowCoord = (vShadowPositionFromLight.xyz/vShadowPositionFromLight.w)/2.0 + 0.5;
gl_FragColor = vec4(unpackDepth(texture2D(uShadowMap, shadowCoord.xy)), 0.0, 0.0, 1.0);
}
I would get this image
Thanks in advance.

Resources