THREE.js custom shader with predefined lights - opengl-es

I have following BlendShader made based on THREE.BlendShader and AlteredQualia JupiterShader. I am struggling with adding Directional Light to the material with this shader. I have read this tutorial but it still does render fully lit object, without taking directional light into consideration. I probably do something wrong at last row when defining the gl_FragColor but can't figure out what it is. Please help. Thank you.
FragmentShader :
"#if NUM_DIR_LIGHTS > 0",
"uniform vec3 directionalLightColor[NUM_DIR_LIGHTS];",
"uniform vec3 directionalLightDirection[NUM_DIR_LIGHTS];",
"#endif",
"uniform float opacity;",
"uniform float mixRatio;",
"uniform float staticRatio;",
"uniform sampler2D tDiffuse1;",
"uniform sampler2D tDiffuse2;",
"uniform sampler2D tDiffuse3;",
"varying vec2 vUv;", // = uv
// vNormal is worldNormal calculated in vertex shader as follows:
// "vec3 worldNormal = mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal ;",
// "vNormal = normalize( worldNormal );",
"varying vec3 vNormal;",
"void main() {",
"vec4 texel1 = texture2D( tDiffuse1, vUv );", // frame i
"vec4 texel2 = texture2D( tDiffuse2, vUv );", // frame i + 1
"vec4 texel3 = texture2D( tDiffuse3, vUv );", //static texture
"texel1.xyz = pow( texel1.xyz, vec3( 1.7 ) );", // gamma correction
"texel2.xyz = pow( texel2.xyz, vec3( 1.7 ) );", // gamma correction
"float m = 1.0;",
"float m1 = smoothstep( 0.23, 0.3, vUv.y );", //
"float m2 = 1.0 - smoothstep( 0.75, 0.82, vUv.y );",
"m = m1 * m2;",
"vec4 dynamic = mix( texel1, texel2, mixRatio );", // mixing two frames
//directional light
"vec4 sumDirLights = vec4(0.0, 0.0, 0.0, 1.0);",
"#if NUM_DIR_LIGHTS > 0",
"for( int i = 0; i < NUM_DIR_LIGHTS; i++ ) {",
"vec3 dir = directionalLightDirection[i];",
"sumDirLights.rgb += clamp( dot( -dir, vNormal ), 0.0, 1.0 ) * directionalLightColor[i];",
"}",
"#endif",
"gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 ) * sumDirLights + ( opacity * mix( texel3, dynamic, staticRatio * m ) ) ;",
"}"

Related

Material shader smooth gradient between two colors

I have the following shaders used in a custom material shader in threeJS and applied to metaballs. Positions of each metaballs (2 in this example) are passed to an array allPos and they are compared in distance with vertex normal to find the closest one. Its index is used to assign a color blobColor which is then passed to the fragment shader.
vertex shader
uniform vec3 colChoice[2];
varying vec3 vNormal;
varying vec3 blobColor;
varying vec3 otherColor;
uniform vec3 allPos[2];
varying float mixScale;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vNormal = normalize( normalMatrix * normal );
float prevdist = 1000000000000000000000000000000.0;
for(int i=0;i<2;i++){
float distV = distance(allPos[i],normal.xyz);
if(distV<prevdist){
prevdist = distV;
mixScale = distV;
blobColor = colChoice[i];
otherColor = colChoice[i-1];
}
}
gl_Position = projectionMatrix * mvPosition;
}
fragment shader
"varying vec3 blobColor;",
"varying vec3 otherColor;",
"varying vec3 vNormal;",
"varying float mixScale;",
void main() {
finalColor = (0.45*vNormal) + mix(otherColor,blobColor,mixScale);
gl_FragColor = vec4( finalColor, 1.0 );
}
which gives me something like this:
It is a bit rough for now and I would like to apply a dot gradient between
the two colors. Any suggestion?

How to add lighting to shader of instancing

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);
}

a simple compare of vec4.x > 5

I cannot compile the following fragment shader:
uniform vec3 color;
uniform sampler2D tDiffuse;
varying vec2 vUv;
void main() {
vec4 texel = texture2D( tDiffuse, vUv );
vec3 luma = vec3( 0.299, 0.587, 0.114 );
float v = dot( texel.xyz, luma );
if (texel.x > 5)
gl_FragColor = vec4( v * color, texel.w );
else
gl_FragColor = texel;
}
If I change (texel.x > 5) to (1 > 5) it works fine. But somehow texel.x causes a compile error. Does anyone see an obvious problem with this code?
texel.x is a float, 5 is an int, you can't compare both directly.
Try to write 5.0 instead:
if (texel.x > 5.0)

Custom ssao in Three.js

I am trying to finish a ssao shader from a tutorial: http://www.nutty.ca/?page_id=352&link=ssao
I use multi-pass render in three.js.
There is a similar question in stackoverflow SSAO artefacts in Three, and I find we learned from the same tutorial.
I follow the tutorial in detail, I do not know which texture I render is totally wrong. Does anybody have some idea? thank you!
As following the tutorial,
I store the whole scene in a color tDiffusion texture:
,
store a view-space position to a tPosition texture:
,
store view-space linear depth to a tDepth texture:
,
the Shader are like this:
"custom_vsPosition" :{
uniforms:{
"cameraNear": { type: "f", value: 1.0 },
"cameraFar": { type: "f", value: 100.0 }
},
vertexShader:[
"varying vec4 mvPosition;", //View-space position
"void main() {",
// Calculate and include linear depth
" mvPosition = modelViewMatrix * vec4(position, 1.0);",
" gl_Position = projectionMatrix * mvPosition;",
"}"
].join("\n"),
fragmentShader:[
"uniform float cameraNear;",
"uniform float cameraFar;",
"varying vec4 mvPosition;", //View-space position
"void main() {",
" float linearDepth = length(mvPosition) / (cameraFar - cameraNear);",
" linearDepth = clamp(linearDepth, 0.0, 1.0);",
" gl_FragColor = vec4(mvPosition.xyz, linearDepth);",
"}"
].join("\n")
},
store view-space normal vector to a tNormal texture:
,
"custom_vsNormal" :{
uniforms:{
},
vertexShader:[
"varying vec3 vNormal ;",
"void main(void) {",
" vNormal = normalMatrix * normal ;", //transforming the normal vector into view
//space and then scaling and biasing the vector components
" gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
"}"
].join("\n"),
fragmentShader:[
"varying vec3 vNormal ;", //Normal transform
"void main() {",
" gl_FragColor = vec4(normalize( vNormal ).xyz, 1.0);",
"}"
].join("\n")
},
And then based on the tDepth, tPosition and tNormal to calculate the ao.
However, the Ao seems wrong. Comparing my texture to the turtorial, I do not find where is wrong. From SSAO artefacts in Three, Maybe there where problem in Normal generating. But I really generate the view-space normal.
only Ao picture:
Ao with color scene:
SSAO shader from the tutorial:
"custom_NVD_SSAOShader":
{
uniforms: {
"tDiffuse": { type: "t", value: null }, // Render texture
"tPosition": { type: "t", value: null }, // View space position data
"tNormal": { type: "t", value: null }, // View space normal vectors
"tNoise": { type: "t", value: null },// Normalmap to randomize the sampling kernel
"size": { type: "v2", value: new THREE.Vector2( 512, 512 ) },
"occluderBias": { type: "f", value: 0.005 }, // Occluder bias to minimize self-occlusion.
"samplingRadius": { type: "f", value: 20 }, // Specifies the size of the sampling radius.
"cAttenuation": { type: "v3", value: new THREE.Vector3( 1, 1.5, 0 ) },
"onlyAo": { type: "f", value: 0.0 },
"lumInfluence": { type: "f", value: 0.9 }
// Ambient occlusion attenuation values. These parameters control the amount of AO calculated based on distance to the occluders. You need to play with them to find the right balance.
// .x = constant attenuation. This is useful for removing self occlusion. When
// set to zero or a low value, you will start to notice edges or wireframes
// being shown. Typically use a value between 1.0 and 3.0.
// .y = linear attenuation. This provides a linear distance falloff.
// .z = quadratic attenuation. Smoother falloff, but is not used in this shader.
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"#define sampleCount 16",
"#define patternSize 4.0",
"varying vec2 vUv;",
"uniform sampler2D tDiffuse;",
"uniform sampler2D tPosition;",
"uniform sampler2D tNormal;",
"uniform sampler2D tNoise;", //input random noise for random sampling
"uniform vec2 size;",
"uniform float occluderBias;",
"uniform float samplingRadius;",
"uniform vec3 cAttenuation;",
"uniform float onlyAo;",
"uniform float lumInfluence;",
"const vec3 onlyAOColor = vec3( 1.0, 0.7, 0.5 );",
"float SamplePixels (vec3 srcPosition, vec3 srcNormal, vec2 uv)",
"{",
// Get the 3D position of the destination pixel
" vec3 dstPosition = texture2D(tPosition, uv).xyz;",
// Calculate ambient occlusion amount between these two points
// It is simular to diffuse lighting. Objects directly above the fragment cast
// the hardest shadow and objects closer to the horizon have minimal effect.
" vec3 positionVec = dstPosition - srcPosition;",
" float intensity = max(dot(normalize(positionVec), srcNormal)- occluderBias, 0.0);",
" float dist = length(positionVec);",
" float attenuation = 1.0 / (cAttenuation.x + (cAttenuation.y * dist));",
" return intensity * attenuation;",
"}",
"vec2 texelSize = vec2(0.5 , 0.5);",
/*
// These are the Poisson Disk Samples
"vec2 getPoisson16(int i){;",
"vec2 poisson16;",
"if(i==0)",
" poisson16 = vec2( -0.94201624, -0.39906216 );",
"else if(i==1)",
" poisson16 = vec2( 0.94558609, -0.76890725 );",
"else if(i==2)",
" poisson16 = vec2( -0.094184101, -0.92938870 );",
"else if(i==3)",
" poisson16 = vec2( 0.34495938, 0.29387760 );",
"else if(i==4)",
" poisson16 = vec2( -0.91588581, 0.45771432 );",
"else if(i==5)",
" poisson16 = vec2( -0.81544232, -0.87912464 );",
"else if(i==6)",
" poisson16 = vec2( -0.38277543, 0.27676845 );",
"else if(i==7)",
" poisson16 = vec2( 0.97484398, 0.75648379 );",
"else if(i==8)",
" poisson16 = vec2( 0.44323325, -0.97511554 );",
"else if(i==9)",
" poisson16 = vec2( 0.53742981, -0.47373420 );",
"else if(i==10)",
" poisson16 = vec2( -0.26496911, -0.41893023 );",
"else if(i==11)",
" poisson16 = vec2( 0.79197514, 0.19090188 );",
"else if(i==12)",
" poisson16 = vec2( -0.24188840, 0.99706507 );",
"else if(i==13)",
" poisson16 = vec2( -0.81409955, 0.91437590 );",
"else if(i==14)",
" poisson16 = vec2( 0.19984126, 0.78641367 );",
"else if(i==15)",
" poisson16 = vec2( 0.14383161, -0.14100790 );",
"return poisson16;",
"}",
*/
"void main ()",
"{",
// Get position and normal vector for this fragment
" vec3 srcPosition = texture2D(tPosition, vUv).xyz;",
" float srcDepth = texture2D(tPosition, vUv).w;",
" vec3 srcNormal = texture2D(tNormal, vUv).xyz;",
/*
" float ao = 0.0;",
" float kernelRadius = samplingRadius * (1.0 - srcDepth);",
" for(int i =0; i < sampleCount; ++i)",
" {",
" ao += SamplePixels(srcPosition, srcNormal, vUv + getPoisson16(i) * kernelRadius);",
" }",
" ao /= 16.0;",
" ao = clamp(ao, 0.0, 1.0);",
" ao = 1.0 - ao;",
*/
" vec2 randVec = normalize(texture2D(tNoise, vUv).xy * 2.0 - 1.0);",
" float kernelRadius = samplingRadius * (1.0 - srcDepth);",
" vec2 kernel[4];",
" kernel[0] = vec2(0.0, 1.0);", // top",
" kernel[1] = vec2(1.0, 0.0);", // right
" kernel[2] = vec2(0.0, -1.0);", // bottom
" kernel[3] = vec2(-1.0, 0.0);", // left
" const float Sin45 = 0.707107;", // 45 degrees = sin(PI / 4)
" float ao = 0.0;",
" for (int i = 0; i < 4; ++i)",
" {",
" vec2 k1 = reflect(kernel[i], randVec);",
" vec2 k2 = vec2(k1.x * Sin45 - k1.y * Sin45,",
" k1.x * Sin45 + k1.y * Sin45);",
" k1 *= texelSize;",
" k2 *= texelSize;",
" ao += SamplePixels(srcPosition, srcNormal, vUv + k1 * kernelRadius);",
" ao += SamplePixels(srcPosition, srcNormal, vUv + k2 * kernelRadius * 0.75);",
" ao += SamplePixels(srcPosition, srcNormal, vUv + k1 * kernelRadius * 0.5);",
" ao += SamplePixels(srcPosition, srcNormal, vUv + k2 * kernelRadius * 0.25);",
" }",
" ao /= 16.0;",
" ao = clamp(ao, 0.0, 1.0);",
" ao = 1.0 - ao;",
" vec3 color = texture2D( tDiffuse, vUv ).rgb;",
"if ( onlyAo == 1.0 )",
" gl_FragColor.xyz = vec3( ao, ao, ao );",
"else if ( onlyAo == 2.0 )",
" gl_FragColor.xyz = vec3( srcNormal.x, srcNormal.y, srcNormal.z );",
"else if ( onlyAo == 3.0 )",
" gl_FragColor.xyz = vec3( srcDepth, srcDepth, srcDepth );",
"else if ( onlyAo == 4.0 )",
" gl_FragColor.xyz = vec3( srcPosition.x, srcPosition.y, srcPosition.z );",
"else if ( onlyAo == 5.0 )",
" gl_FragColor.xyz = color;",
"else",
"{",
" gl_FragColor.xyz = color * ao;",
"}",
"gl_FragColor.w = 1.0;",
"}"
].join("\n")
}

lighting problems after gldisable(gl_cull_face) in opengl es 2.0

I have been working in a skull with opengl es 2.0. The skull appeared without some faces:
After that I dedided to disable gl_cull_face. The problem with the faces was
solved but the the skull appears now without light and I havenĀ“t changed shader code:
I have tried with other lighting algorithms and the skull continues black. I can't understand what is the relationship between gldisable(gl_cull_face) and lighting. The shader code is this:
Vertex Shader:
uniform mediump mat4 MODELVIEWMATRIX;
uniform mediump mat4 PROJECTIONMATRIX;
uniform mediump mat3 NORMALMATRIX;
uniform mediump vec3 LIGHTPOSITION;
varying lowp vec3 lightcolor;
attribute mediump vec3 POSITION;
attribute lowp vec3 NORMAL;
lowp vec3 normal;
attribute mediump vec2 TEXCOORD0;
varying mediump vec2 texcoord0;
void main( void ) {
mediump vec3 position = vec3( MODELVIEWMATRIX * vec4( POSITION, 1.0 ) );
normal = normalize( NORMALMATRIX * NORMAL );
mediump vec3 lightdirection = normalize( LIGHTPOSITION - position );
lowp float ndotl = max( dot( normal, lightdirection ), 0.0 );
lightcolor = ndotl * vec3( 1.0 );
gl_Position = PROJECTIONMATRIX * vec4( position, 1.0 );
texcoord0 = TEXCOORD0;
}
Fragment Shader:
varying mediump vec2 texcoord0;
uniform sampler2D DIFFUSE;
varying lowp vec3 lightcolor;
void main( void ) {
gl_FragColor = texture2D( DIFFUSE, texcoord0 ) * vec4( lightcolor, 1.0 ) + vec4( 0.1);
}
Thank you.

Resources