I have a simple shader in my Three.js application that colors the screen red. However, I want to color all pixels to the right of a given world position to to a different color.
I have seen some answers that suggest using varying vec4 worldCoord = gl_ModelViewMatrix * gl_Vertex;, but since WebGL using GLSLES, variables like gl_Vertex are not available to me.
Vertex Shader
<script type="x-shader/x-vertex" id="vertexshader">
#ifdef GL_ES
precision highp float;
#endif
void main()
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
</script>
Fragment Shader
<script type="x-shader/x-fragment" id="fragmentshader">
#ifdef GL_ES
precision highp float;
#endif
float worldX = 10.0; //Or some other position in the WebGL world
void main()
{
if(gl_FragCoord.x > worldX) //FragCoord gives me coordinates relative to the screen
{
gl_FragColor = vec4(0.0, 1.0, 0.0, 1);
}
else
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1);
}
}
</script>
Q: How do I convert the position of a pixel to it's world position in WebGL using Three.js?
Answer derived from WestLangley's Fiddle here: http://jsfiddle.net/ST4aM/2/.
Vertex Shader
<script type="x-shader/x-vertex" id="vertexshader">
#ifdef GL_ES
precision highp float;
#endif
varying float x;
varying float y;
void main()
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
x = position.x;
y = position.y;
}
</script>
Fragment Shader
<script type="x-shader/x-fragment" id="fragmentshader">
#ifdef GL_ES
precision highp float;
#endif
varying float x;
varying float y;
void main()
{
if(x > somePosition)
{
gl_FragColor = vec4(0.0, 1.0, 0.0, 1);
}
else
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1);
}
}
</script>
Related
I'm trying to use the shader from this post https://stackoverflow.com/a/27764539/6736544 with a ThreeJS geometry, so far without success.
This is the original shader code from #gman:
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script id="vs" type="foo">
attribute vec4 a_position;
attribute float a_v;
varying float v_v;
void main() {
// PS: In a real WebGL app you'd probably need to multiply a_position by
// a matrix at a minimum
gl_Position = a_position;
v_v = a_v;
}
</script>
<script id="fs" type="foo">
precision mediump float;
varying float v_v;
uniform float u_borderSize;
uniform vec4 u_baseColor;
uniform vec4 u_borderColor;
void main() {
float mixAmount = step(u_borderSize, v_v);
gl_FragColor = mix(u_baseColor,
u_borderColor,
mixAmount);
}
</script>
<canvas id="c" width="256" height="256"></canvas>
This is my attempt:
<script>
var vertexShader = `
varying vec2 vUv;
attribute float alpha;
varying float vAlpha;
attribute vec3 center;
varying vec3 vCenter;
void main() {
vUv = uv;
vAlpha = alpha;
vCenter = center;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
var fragmentShader = `
//precision mediump float;
uniform vec3 color1;
uniform float color1Alpha;
uniform vec3 borderColor;
uniform float borderThickness;
varying vec2 vUv;
varying float vAlpha;
varying vec3 vCenter;
void main() {
float u_borderSize = borderThickness;
vec4 u_baseColor = vec4(color1, color1Alpha);
vec4 u_borderColor = vec4(borderColor, 1.0);
// This is where I get stuck. No idea how to get a correct 'v_v' value.
float v_v = vUv.y;
float mixAmount = step(u_borderSize, v_v);
gl_FragColor = mix(u_baseColor,
u_borderColor,
mixAmount);
}
`;
</script>
See the jsfiddle here: https://jsfiddle.net/vuqarejz/
This is what I'm trying to achieve:
Questions:
Not sure what I'm missing, nor where the 'v_a' attribute is coming from.
Maybe it is the way UVs are unwrapped?
Maybe this is not the correct shader to use for my purpose?
Solved by tfoller in ThreeJS forum:
https://discourse.threejs.org/t/unwrapping-a-custom-shapebuffergeometry/39565/4
I have the following shader with two passes and scene blend but I see those faces marked in black..
how would I maintain transparency and not see these faces in the picture ?
The material does two passes on cull faces anticlockwise and the other pass cull faces clockwise.
The shader does a dot product between the normal and the camera position and then modulate the transparency based on that result.
#version 100
precision highp int;
precision highp float;
uniform float time;
uniform float touchX;
uniform float touchY;
uniform float touchZ;
uniform float line;
varying float lightDiffuse;
void main()
{
float rampLight =lightDiffuse;
float light = (1.0 - rampLight) * 1.0;
vec4 lightColor = vec4(1.0,1.0,1.0, 1.0);
vec4 diffuseColor = lightColor * light;
vec4 c;
if(rampLight < 0.0 )
{
discard;
}
diffuseColor = smoothstep(vec4(0.0, 0.0, 0.0, 0.0), vec4(0.8, 0.8, 0.8, 0.8), vec4(diffuseColor));
gl_FragColor = diffuseColor;
}
material Router
{
technique
{
pass
{
scene_blend alpha_blend
depth_write on
depth_check on
cull_hardware anticlockwise
vertex_program_ref movingline_101_vs
{
}
fragment_program_ref movingline_101_fs
{
}
}
pass
{
scene_blend alpha_blend
cull_hardware clockwise
depth_write on
depth_check on
vertex_program_ref movingline_101_vs
{
}
fragment_program_ref movingline_101_fs
{
}
}
}
}
Update:
material Router
{
technique
{
pass
{
depth_write on
vertex_program_ref pass_101_vs
{
}
fragment_program_ref pass_101_fs
{
}
}
pass
{
depth_write off
depth_fun equal
scene_blend add
vertex_program_ref movingline_101_vs
{
}
fragment_program_ref movingline_101_fs
{
}
}
}
}
pass shader
void main()
{
gl_FragColor = vec4(0.0,0.0,0.0,0.0);
}
main shader:
#version 120
precision highp int;
precision highp float;
uniform float time;
uniform float touchX;
uniform float touchY;
uniform float touchZ;
uniform float line;
varying float lightDiffuse;
void main()
{
float rampLight =lightDiffuse;
float light = (1.0 - rampLight) * 1.0;
vec4 lightColor = vec4(1.0,1.0,1.0, 1.0);
vec4 diffuseColor = lightColor * light;
diffuseColor = smoothstep(vec4(0.0, 0.0, 0.0, 0.0), vec4(0.9, 0.9, 0.9, 0.9), vec4(diffuseColor));
gl_FragColor = diffuseColor;
}
If you're just trying to render something with transparency, but without being able to see the faces which would be occluded if it was opaque, then a common simple technique is to prime the depth buffer first.
Pass 1: Write to just the depth buffer. Easiest way to achieve this is by rendering with blending on and a shader that just outputs vec4(0.0, 0.0, 0.0, 0.0) for every fragment. There may be more efficient ways to prime the depth buffer (e.g. using glColorMask instead of blending), but this approach is simple and probably good enough.
Pass 2: Render with a depth test of GL_EQUAL. Use whatever shader you like.
Performance note: discard is often slower than just outputting vec4(0.0, 0.0, 0.0, 0.0) for pixels you want to be transparent on mobile hardware, so avoid discard unless you really need it - in this case you don't need it.
How do I make each particle animate and cycle through all the tiles in the sprite sheet?
Here's my shader program:
<script type="x-shader/x-vertex" id="vertexshader">
attribute vec2 offset;
varying vec2 vOffset;
void main()
{
vOffset = offset;
gl_PointSize = 25.0;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform sampler2D texture;
uniform vec2 repeat;
varying vec2 vOffset;
void main()
{
vec2 uv = vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y );
vec4 tex = texture2D( texture, uv * repeat + vOffset );
if ( tex.a < 0.5 ) discard;
gl_FragColor = tex;
}
</script>
Basically an example from here: http://jsfiddle.net/myy7x4zd/4/
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.
So far, I have successfully display a cube with a fix color. However, I want the color of the cube to be changeable. So I tried to replace this code:
var cBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(vertexColors1), gl.STATIC_DRAW );
var vColor = gl.getAttribLocation( program, "vColor" );
gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vColor );
with:
vColor = gl.getUniformLocation(program, "vColor");
gl.uniformMatrix4fv(vColor,false,flatten(vertexColors1));
And I also change the type of vColor in my vertex-shader from attribute to uniform. in the fragment shader, I use varying. However, these method is not working. The color of the cube become white instead of the color that I have assigned in vertexColors1. any suggestion?
Shader code:
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
uniform vec4 vColor;
//attribute vec4 vColor;
varying vec4 fColor;
uniform mat4 modelViewMatrix;
void main()
{
fColor = vColor;
gl_Position = modelViewMatrix * vPosition;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void
main()
{
gl_FragColor = fColor;
}
</script>