I have gltf CUP model with texture and PBR effect. I want to apply reflection of the environment(Cubereflection). Facing issue while applying reflection.Color and texture changed and only env reflection is coming. I am unable to solve this issue. Where is my shader is wrong or some other issue. I don't have much knowledge on shader program. How should I get the proper color(as like first image) with reflection. I have attached two images without reflection and with reflection. Reflection is working fine but don't have any clue why this this proper color is not comming. Kindly help?
my shader programme.
var meshlambert_vert =
varying vec3 vReflect;
varying vec3 vRefract[3];
varying float vReflectionFactor;
attribute vec3 a_normal;
varying vec3 v_normal;
varying vec3 v_position;
uniform mat3 u_normalMatrix;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
v_position = mvPosition.xyz;
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
vec3 I = worldPosition.xyz - cameraPosition;
vReflect = reflect( I, worldNormal );
v_normal = u_normalMatrix * a_normal;
vRefract[0] = refract( normalize( I ), worldNormal, 0.02 );
vRefract[1] = refract( normalize( I ), worldNormal, 0.02 * 0.2);
vRefract[2] = refract( normalize( I ), worldNormal, 0.02 * 0.2 );
vReflectionFactor = 0.1 + 1.0 * pow( 1.0 + dot( normalize( I ), worldNormal ), 0.2 );
gl_Position = projectionMatrix * mvPosition;
};
var meshlambert_frag =
uniform samplerCube tCube;
varying vec3 vReflect;
varying vec3 vRefract[3];
varying float vReflectionFactor;
uniform vec4 u_ambient;
uniform vec4 u_emission;
uniform vec4 u_specular;
uniform vec4 u_diffuse;
varying vec3 v_normal;
varying vec3 v_position;
void main() {
vec4 color = vec4(0., 0.29411,0.47843, 1.0);
vec3 diffuseLight = vec3(0., 0., 0.);
vec3 u_light2Color = vec3(1.0,1.0,1.0);
vec4 diffuse = vec4(0.0, 0.0, 0.0, 1.0);
vec3 specularLight = vec3(0.5, 0.5,0.5);
float specularIntensity = 0.5;
float attenuation = 0.5;
vec3 l = vec3(0.0,0.5,0.5);
vec3 u_light0Color = vec3(1.0,1.0,1.0);
vec4 emission;
vec4 ambient;
vec4 specular;
ambient = u_ambient;
diffuse = u_diffuse;
emission = u_emission;
specular = u_specular;
vec3 ambientLight = vec3(0., 0., 0.);
ambientLight += u_light2Color;
ambient.xyz *= ambientLight;
color.xyz += ambient.xyz;
specularLight += u_light0Color * specularIntensity;
specular.xyz *= specularLight;
color.xyz += specular.xyz;
vec3 normal = normalize(v_normal);
if ( dot( normal, v_position ) > 0.0 ) {
normal *= -1.0;
}
diffuseLight += u_light0Color * max(dot(normal,l), 0.) * attenuation;
diffuse.xyz *= diffuseLight;
color.xyz += diffuse.xyz;
color.xyz += emission.xyz;
vec4 reflectedColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );
vec4 refractedColor = vec4( 0.0 );
refractedColor.r = textureCube( tCube, vec3( -vRefract[0].x, vRefract[0].yz ) ).r;
refractedColor.g = textureCube( tCube, vec3( -vRefract[1].x, vRefract[1].yz ) ).g;
refractedColor.b = textureCube( tCube, vec3( -vRefract[2].x, vRefract[2].yz ) ).b;
gl_FragColor = mix( color, reflectedColor, clamp( 0.98, 0.0, 1.0 ) );
}";
cubmaping code with reflection:
var loader = new THREE.CubeTextureLoader();
loader.setPath( 'textures/env1/' );
var textureCube = loader.load( [
'posx.jpg', 'negx.jpg',
'posy.jpg', 'negy.jpg',
'posz.jpg', 'negz.jpg'
] );
textureCube.mapping = THREE.CubeReflectionMapping;
var cubeShader = THREE.ShaderLib[ "cube" ];
var cubeMaterial = new THREE.ShaderMaterial( {
fragmentShader: cubeShader.fragmentShader,
vertexShader: cubeShader.vertexShader,
uniforms: cubeShader.uniforms,
depthWrite: false,
side: THREE.BackSide
} );
cubeMaterial.uniforms[ "tCube" ].value = textureCube;
cubeMesh = new THREE.Mesh( new THREE.BoxBufferGeometry( 100, 100, 100 ), cubeMaterial );
scene.add( cubeMesh );
var sphereMaterial=new THREE.MeshLambertMaterial( {envMap: textureCube } );
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = sphereMaterial;
}
} );
You mix the reflection color and the color of the material by a constant ratio of 98:2
gl_FragColor = mix( color, reflectedColor, clamp( 0.98, 0.0, 1.0 ) );
The color component of the material is to weak to "see" it.
Try a ration of 50:50 for debug reasons:
gl_FragColor = mix( color, reflectedColor, 0.5 );
But probably you want to us vReflectionFactor for the ratio:
gl_FragColor = mix( color, reflectedColor, clamp( vReflectionFactor, 0.0, 1.0 ) );
Further note, if you use vReflectionFactor, then you will see the reflection only, because the result of
vReflectionFactor = 0.1 + 1.0 * pow( 1.0 + dot( normalize( I ), worldNormal ), 0.2 );
is always greater than 1.0. This is caused, because 1.0 + dot( normalize( I ), worldNormal is grater than 1.0.
I don't know what you want to achieve, but you can use
vReflectionFactor = 0.1 + pow( dot(normalize(I), worldNormal), 0.2 );
or
vReflectionFactor = 0.1 + pow( 1.0 - dot(normalize(I), worldNormal), 0.2 );
Related
I have written a simple three.js of using a height map. This is the relevant code that creates the shader material:
function loadHeightMap() {
// fake a lookup table
var lut = [];
for ( var n=0; n<256; n++ ) {
lut.push(new THREE.Vector3(0.5, 0.4, 0.3));
}
var loader = new THREE.TextureLoader();
var zScale = 10;
var mapLoc = "https://s22.postimg.org/8n93ehmep/Terrain128.png";
loader.load(mapLoc, function ( texture ) {
// use "this." to create global object
this.customUniforms = {
zTexture: { type: "t", value: texture },
zScale: { type: "f", value: zScale },
zLut: { type: "v3v", value: lut }
};
var customMaterial = new THREE.ShaderMaterial({
uniforms: customUniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
side: THREE.DoubleSide
});
var planeGeo = new THREE.PlaneGeometry( 20, 20, 129, 129 );
var plane = new THREE.Mesh( planeGeo, customMaterial );
plane.rotation.x = -Math.PI / 2;
plane.position.y = 0;
scene.add(plane);
});
}
And here are the shaders:
<script id="vertexShader" type="x-shader/x-vertex">
uniform sampler2D zTexture;
uniform float zScale;
uniform vec3 zLut[ 256 ];
varying float vAmount;
void main() {
vec4 heightData = texture2D( zTexture, uv );
vAmount = heightData.r;
// move the position along the normal
vec3 newPosition = position + normal * zScale * vAmount;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
uniform vec3 zLut[ 256 ];
varying float vAmount;
void main() {
int index = int(vAmount) * 255;
vec3 vColor = vec3(vAmount, vAmount, vAmount);
//gl_FragColor = vec4(zLut[index], 1.0);
gl_FragColor = vec4(vColor, 1.0);
}
The shaders and the height map part works fine. But I want to pass the lookup table (zLut). The above code works fine if I don't try to use the lookup table. A working example is here. I created a fiddle as well here but it fails because of CORS issues.
Any suggestions are welcome.
OK, solved this (mostly). The trick was to fetch the lookup color in the vertex shader, where one CAN index into an array with a non-const value. The pass the resulting color to the fragmentShader as a varying. So the two shaders end up being:
<script id="vertexShader" type="x-shader/x-vertex">
uniform sampler2D vTexture;
uniform float vScale;
uniform vec3 vLut[ 256 ];
varying vec3 vColor;
void main() {
vec4 heightData = texture2D( vTexture, uv );
// assuming map is grayscale it doesn't matter if you use r, g, or b.
float vAmount = heightData.r;
// fetch the color from the lookup table so it gets passed to the fragshader
int index = int(heightData.r * 255.0);
vColor = vLut[index];
// move the position along the normal
vec3 newPosition = position + normal * vScale * vAmount;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 1.0);
}
</script>
The remaining problem I have is that when rendered the colors are all flat. I tried forcing an update on the vertices in the animate function but didn't work. Still researching but the question here is solved (AFAIK).
You can see the result here
I'm trying to make a shader for my dashed line; but only I can get is white line from origin to .. +x direction(maybe)
If I render this curve (Ellipse.curve), they do just fine. And with shader don't..
..of course, I don't know why.. please help me;;
<script type="x-shader/x-vertex" id="vs-orbit">
uniform float time;
attribute float sovereign;
varying vec3 vColor;
vec3 setColorBySovereign() {
vec3 color;
color.r = 0.5 - ( 0.5 * sovereign );
color.g = 0.25 + ( 0.25 * sovereign );
color.b = 0.5 + ( 0.25 * sovereign );
return _color;
};
void main() {
vColor = setColorBySovereign();
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
};
</script>
<script type="x-shader/x-fragment" id="fs-orbit">
attribute vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 1.0);
};
</script>
// ... Below is where use shader above;
Ellipse.prototype.createOrbit = function( soveregin ) {
var shape, mater;
var sov = soveregin || 0.0;
shape = new THREE.Geometry();
var v2;
for(var i=0; i<721; i++) {
v2 = this.curve.getPoint(i);
shape.vertices.push(new THREE.Vector3(v2.x, v2.y, 0));
};
shape.computeLineDistances();
mater = new THREE.ShaderMaterial({
attribute: { soveregin: sov },
vertexShader: document.getElementById('vs-orbit'),
fragmentShader: document.getElementById('fs-orbit')
});
this.orbit = new THREE.Line( shape, mater, THREE.LineStrip );
return;
}
I solve this problem; after main(){} I shouldn't use ';' and other syntax errors too.
in fragment shader, I have to declare vColor with operator 'varying', just like vertex shader. In fragment shader; from GLSL Reference; varying is equal to in operator.
I'm trying to implement the Cook-Torrance shading algorithm in three.js I have a mostly working solution, however it doesn't show the effects of the ambient light. The sides of the cube not illuminated by the light are completely black. If I remove the "Beckmann term" then I can indeed see the ambient light effect:
While, replacing Beckmann with the function that always return 0.0 I get:
It seems like the cause of the wrong behaviour is the division in:
vec3 Specular = (Beckmann(NdotH) * G(NdotH, NdotV, VdotH, NdotL) * R_F(VdotH)) / ( NdotL* NdotV);
If I modify NdotL * NdotV to NdotV and change the computation for gl_FragColor to:
gl_FragColor = vec4(beta * NdotL * (1.0-s)*Kd + beta * s*Specular + ambient*Kd, 1.0);
Everything seems to work correctly.
What I don't understand is: why? This problem with the division isn't mentioned anywhere, and I'm not 100% sure that even the remaining division wont cause problems in other situations.
Here's the full MWE:
<html>
<head>
<title>Cook-Torrance BRDF computed by shader</title>
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
}
</style>
<script src="lib/three.min.js"></script>
<script src="lib/OrbitControls.js"></script>
</head>
<body>
<script type="text/x-glsl" id="vertex">
varying vec3 transformedNormal;
varying vec3 pointPosition;
varying vec3 lightVector;
uniform vec3 pointLightPosition;
void main()
{
transformedNormal = normalMatrix * normal;
pointPosition = (modelViewMatrix * vec4( position, 1.0 )).xyz;
vec4 lPosition = viewMatrix * vec4( pointLightPosition, 1.0 );
lightVector = lPosition.xyz - pointPosition;
gl_Position = projectionMatrix * vec4(pointPosition,1.0);
}
</script>
<script type="text/x-glsl" id="ct-fragment">
uniform vec3 lightPower;
uniform vec3 ambient;
uniform vec3 Kd; // surface diffuse color
uniform vec3 Ks; // surface specular color: equal to R_F(0)
uniform float m; // material roughness (average slope of microfacets)
uniform float s; // percentage of incoming light which is specularly reflected
varying vec3 transformedNormal;
varying vec3 pointPosition;
varying vec3 lightVector;
#define PI 3.14159265
float G(float NdotH, float NdotV, float VdotH, float NdotL)
{
float G1 = 2.0 * NdotH * NdotV / VdotH;
float G2 = 2.0 * NdotH * NdotL / VdotH;
return min( 1.0, min( G1, G2 ));
}
vec3 R_F(float VdotH) {
return Ks + (1.0 - Ks)*pow(1.0-VdotH, 5.0);
}
float Beckmann(float NdotH){
float A = 1.0 / (pow(m,2.0)+pow(NdotH,4.0)*PI);
float B = exp( - pow( tan(acos(NdotH)) , 2.0) / pow(m,2.0));
return A*B;
}
void main()
{
vec3 n = normalize( transformedNormal );
vec3 v = normalize( -pointPosition );
vec3 l = normalize( lightVector );
vec3 h = normalize( v+l );
float NdotH = max(0.0, dot( n, h ));
float VdotH = max(0.0, dot( v, h ));
float NdotV = max(0.0, dot( n, v ));
float NdotL = max(0.0, dot( n, l ));
// specular BRDF
vec3 Specular = (Beckmann(NdotH) * G(NdotH, NdotV, VdotH, NdotL) * R_F(VdotH)) / ( NdotL* NdotV);
vec3 beta = lightPower / ( 4.0 * PI * pow( length(lightVector),2.0) );
gl_FragColor = vec4(beta * NdotL * ((1.0-s)*Kd + s*Specular) + ambient*Kd, 1.0);
}
</script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position = new THREE.Vector3(0,0,5);
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xf0f0f0 );
document.body.appendChild( renderer.domElement );
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
var uniforms = {
Ks: { type: "v3", value: new THREE.Vector3() },
Kd: { type: "v3", value: new THREE.Vector3() },
ambient: { type: "v3", value: new THREE.Vector3() },
pointLightPosition: { type: "v3", value: new THREE.Vector3() },
lightPower: { type: "v3", value: new THREE.Vector3() },
s: {type: "f", value: 0},
m: {type: "f", value: 0}
};
var vs = document.getElementById("vertex").textContent;
var fs = document.getElementById("ct-fragment").textContent;
var material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: vs, fragmentShader: fs });
var geometry = new THREE.CubeGeometry(1, 1, 1);
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
light = new THREE.Mesh( new THREE.SphereGeometry( 1, 16, 16), new THREE.MeshBasicMaterial ({color: 0xffff00, wireframe:true}));
light.position = new THREE.Vector3( 10.0, 10.0, 10.0 );
scene.add( light );
uniforms.Ks.value = new THREE.Vector3( 0.95, 0.93, 0.88 );
uniforms.Kd.value = (new THREE.Vector3( 0.50754, 0.50754, 0.50754 ));
uniforms.ambient.value = (new THREE.Vector3( 0.5, 0.5, 0.5 ));
uniforms.pointLightPosition.value = new THREE.Vector3(light.position.x, light.position.y, light.position.z);
uniforms.lightPower.value = new THREE.Vector3( 7000.0, 7000.0, 7000.0 );
uniforms.s.value = 0.5;
uniforms.m.value = 0.1;
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
controls.update();
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
The shading equation is a mathematical description of the Cook-Torrance shading model.
Writing an actual shader is a different thing that should take into account the fact that not all operations between floats have the same properties of the real mathematical operations in the equation.
In this case diving by 0 causes problems. In fact the problem is that the definition of Specular is diving by 0, but when assigning to gl_FragColor I'm multiplying again by NdotL obtaining 0 * inf = NaN, and it seems like NaN is interpreted as a zero/negative number by the GPU (thus displaying black).
As a reference, the correct main() is:
void main()
{
vec3 n = normalize( transformedNormal );
vec3 v = normalize( -pointPosition );
vec3 l = normalize( lightVector );
vec3 h = normalize( v+l );
vec3 specular = vec(0.0, 0.0, 0.0);
float NdotH = max(0.0, dot( n, h ));
float VdotH = max(0.0, dot( v, h ));
float NdotV = max(0.0, dot( n, v ));
float NdotL = max(0.0, dot( n, l ));
if (NdotL > 0 && NdotV > 0)
{
specular = (Beckmann(NdotH) * G(NdotH, NdotV, VdotH, NdotL) * R_F(VdotH)) / ( NdotL* NdotV);
}
vec3 beta = lightPower / ( 4.0 * PI * pow( length(lightVector),2.0) );
gl_FragColor = vec4(beta * NdotL * ((1.0-s)*Kd + s*specular) + ambient*Kd, 1.0);
}
I'm using Three.js and I have a ParticleSystem where every particle may have a different transparency and color.
Code:
var shaderMaterial = new THREE.ShaderMaterial({
uniforms: customUniforms,
attributes: customAttributes,
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
transparent: true,
alphaTest: 0.5
});
particles = new THREE.ParticleSystem(geometry, shaderMaterial);
particles.dynamic = true;
Vertex shader:
attribute float size;
attribute vec3 color;
varying vec3 vColor;
void main() {
vColor = color;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
//gl_PointSize = size;
gl_PointSize = size * ( 300.0 / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
Fragment shader:
uniform sampler2D texture;
uniform float alpha;
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 100);
vec4 textureColor = texture2D( texture, gl_PointCoord );
gl_FragColor = gl_FragColor * textureColor;
gl_FragColor.a = alpha;
}
Texture is a circle but when I set alpha, like this: gl_FragColor.a = alpha, my texture become a circle in a black square, alpha level is okay, but I don't need the square, only the circle if I don't set the alpha, square doesn't appear.
So how to set alpha correctly for provided texture?
Take a look at this: three.js - Adjusting opacity of individual particles
You can find jsfiddle somewhere in the page that uses ShaderMaterial for ParticleSystem with variable alpha: http://jsfiddle.net/yfSwK/27/
Also, at least change fragment shader a bit, gl_FragColor should be write-only variable, it's not usual to have it as a read-from variable:
vec4 col = vec4(vColor, 100);
vec4 tex = texture2D( texture, gl_PointCoord );
gl_FragColor = vec4( (col*tex).rgb, alpha );
...or in one line:
gl_FragColor = vec4( (vec4(vColor, 100) * texture2D( texture, gl_PointCoord )).rgb, alpha);
i'm using http://stemkoski.github.io/Three.js/ for animated sprite,
for the shadow, i'm using this shader
<script type="x-shader/x-fragment" id="fragmentShaderDepth">
uniform sampler2D texture;
varying vec2 vUV;
vec4 pack_depth( const in float depth ) {
const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );
const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );
vec4 res = fract( depth * bit_shift );
res -= res.xxyz * bit_mask;
return res;
}
void main() {
vec4 pixel = texture2D( texture, vUV );
if ( pixel.a < 0.5 ) discard;
gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );
}
</script>
<script type="x-shader/x-vertex" id="vertexShaderDepth">
varying vec2 vUV;
void main() {
vUV = 0.75 * uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
</script>
to get juste one sprite
vec2 tailleA = vec2( taillex , tailley); // 1/22 num sprite horiz & 1/3 Vert
vUV = vec2( tailleA[0] * uv[0] , (tailleA[1] * uv[1]) );
How can i get the offset forthe texture from the shader automatic generated from three.js ?
How to get animated shadow ?
thanks in advance for your help.