Add opacity to chromakey shader in aframe - three.js

I'm using this shader to chromakey a video. I would like to add opacity to the same video. I've been trying to add the opacity component to the shader but something more must be missing (don't know what).
I've added opacity in the schema:
opacity: {type: 'number', is: 'uniform', default: 0.5}
And in the update function:
this.material.uniforms.opacity = data.opacity
Here's all the shader code:
AFRAME.registerShader('chromakey', {
schema: {
src: {type: 'map'},
color: {default: {x: 0.1, y: 0.9, z: 0.2}, type: 'vec3', is: 'uniform'},
transparent: {default: true, is: 'uniform'},
opacity: {type: 'number', is: 'uniform', default: 0.5}
},
init: function (data) {
var videoTexture = new THREE.VideoTexture(data.src)
videoTexture.minFilter = THREE.LinearFilter
this.material = new THREE.ShaderMaterial({
uniforms: {
color: {
type: 'c',
value: data.color
},
texture: {
type: 't',
value: videoTexture
}
},
vertexShader: this.vertexShader,
fragmentShader: this.fragmentShader
})
},
update: function (data) {
this.material.color = data.color
this.material.src = data.src
this.material.transparent = data.transparent
this.material.uniforms.opacity = data.opacity
},
vertexShader: [
'varying vec2 vUv;',
'void main(void)',
'{',
'vUv = uv;',
'vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
'gl_Position = projectionMatrix * mvPosition;',
'}'
].join('\n'),
fragmentShader: [
'uniform sampler2D texture;',
'uniform vec3 color;',
'varying vec2 vUv;',
'void main(void)',
'{',
'vec3 tColor = texture2D( texture, vUv ).rgb;',
'float a = (length(tColor - color) - 0.5) * 7.0;',
'gl_FragColor = vec4(tColor, a);',
'}'
].join('\n')
})

When you update the value of the uniform (function update), the you have to set the value property and you have to set the notification, that the uniforms of the material needs to be updated (needsUpdate):
this.material.uniforms.opacity.value = data.opacity
this.material.needsUpdate = true
Further you have to add the uniform opacity to the fragment shader. See the following fragment shader which multiplies the opacity uniform to the alpha channel:
uniform float opacity;
uniform sampler2D texture;
uniform vec3 color;
varying vec2 vUv;
void main(void)
{
vec3 tColor = texture2D( texture, vUv ).rgb;
float a = (length(tColor - color) - 0.5) * 7.0;
gl_FragColor = vec4(tColor, a * opacity);
}
Note, if opacity is set to 0.0, the output will disappear completely.

You would need to add an opacity uniform to the shader in order for it to support what you want.
Try the following code (I haven't tested it) and see if it behaves how you want
fragmentShader: [
'uniform sampler2D texture;',
'uniform vec3 color;',
'uniform float opacity;', // add the uniform to the shader
'varying vec2 vUv;',
'void main(void)',
'{',
'vec3 tColor = texture2D( texture, vUv ).rgb;',
'float a = (length(tColor - color) - 0.5) * 7.0;',
'gl_FragColor = vec4(tColor, a*opacity);', // add the opacity multiplier to the alpha channel
'}'
].join('\n')

Related

Three js shader, how to use alpha map texture with opacity and gradient

Need help to make opacity work on shader with gradient and alpha map texture.
With code below results are next: gradient is working but opacity is not.
This is my alpha texture
and this is a geometry and material
const geometry = new THREE.BoxGeometry(32, 32);
const material = new THREE.ShaderMaterial({
uniforms: {
transparent: true,
alphaMap: { value: alphaTexture },
color1: {
value: new THREE.Color("purple")
},
color2: {
value: new THREE.Color("red")
}
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform vec3 color1;
uniform vec3 color2;
uniform sampler2D alphaMap;
varying vec2 vUv;
void main() {
float alpha = texture2D(alphaMap, vUv).r;
vec3 color = mix(color1, color2, vUv.y);
gl_FragColor = vec4(color, alpha);
}
`,
});
as you can see, the black part of the texture is becoming white, but has to be transparent.
Make sure the transparent: true property is outside your uniforms object:
uniforms: {
// alphamap, color1, color2
},
transparent: true,

threejs radial gradient effect on a sphere

I want to do a sort of "inner glow", where a partially transparent color is more intense towards the outside of a sphere, as the user looks at it.
In plain ol' CSS it would be pretty simple:
.gradient{
height: 500px;
width: 500px;
border-radius: 50%;
box-shadow:0 0 50px 1px inset rgba(0,225,255,0.8);
background: rgba(0,225,255,0.1);
}
<div class="gradient"></div>
This tutorial has this effect, and I have a separate question here about an issue I ran into implementing if anyone else has trouble.
Some custom GL shaders: this is GL code that lives in a string to get compiled later:
const vertexShader = `
uniform vec3 viewVector;
uniform float c;
uniform float p;
varying float intensity;
void main()
{
vec3 vNormal = normalize( normalMatrix * normal );
vec3 vNormel = normalize( normalMatrix * viewVector );
intensity = pow( c - dot(vNormal, vNormel), p );
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`;
const fragmentShader = `
uniform vec3 glowColor;
varying float intensity;
void main()
{
vec3 glow = glowColor * intensity;
gl_FragColor = vec4( glow, 1.0 );
}`;
This is the material to create the effect. Play with c and p values for intensity/depth of the "gradient".
const customMaterial = new THREE.ShaderMaterial({
uniforms: {
"c": { type: "f", value: 1.5 },
"p": { type: "f", value: 2 },
glowColor: { type: "c", value: new THREE.Color(0x00e1ff) },
viewVector: { type: "v3", value: camera.position }
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.FrontSide,
blending: THREE.AdditiveBlending,
transparent: true
});
You'll want to apply it to your geometry, and scalar your geometry up to the size of "shell" you desire.
const moonGlow = new THREE.Mesh( Orb, customMaterial);
moonGlow.position = moon.position;
moonGlow.scale.multiplyScalar(1.2);
scene.add( moonGlow );
Finally, facing is important. In you're changing up positions, like in an animation loop with motion controls, add this:
customMaterial.uniforms.viewVector.value = camera.position;

Any way to render fog on top of SSAO in three.js?

I'm using Fog and SSAO in my project, and the SSAO is emphasize stuff that needed to be faded, like the horizon line and buildings.
Is there any way the render the fog on top of the SSAO effect?
thanks.
I tried to write a shader, but it not working…
( function () {
var FogShader = {
uniforms: {
'tDiffuse': { value: null },
'fogColor': { value: new THREE.Vector3( 1.0, 0, 0 ) },
'fogNear': { value: 1.0 },
'fogFar': { value: 10.0 }
},
vertexShader:
varying vec2 vUv;
varying float fogDepth;
void main() {
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
fogDepth = - mvPosition.z;
}`,
fragmentShader:
`
uniform vec3 fogColor;
uniform float fogNear;
uniform float fogFar;
varying float fogDepth;
uniform sampler2D tDiffuse;
varying vec2 vUv;
void main() {
vec4 texel = texture2D( tDiffuse, vUv );
gl_FragColor = texel ;
float fogFactor = smoothstep( fogNear, fogFar, fogDepth );
gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );
}`
};
THREE.FogShader = FogShader;
} )();
I’m using it like this:
var fogpass = new THREE.ShaderPass( THREE.FogShader );
composer.addPass( fogpass );
If I manually change the fogFactor to 1 - all output is red, so I think I have something wrong with the fogDepth…
You can replicate your fog formula in the SSAO shader. Then mix AO with fog:
float final = fog * multiplier * AO;
vec3 result = mix(scene, fognearcol * (1-fog), final);

Three.js Shader material how get (map) texture?

I have one problem here)
I decided to use my shader for (scene.overrideMaterial) and I need to somehow get the map texture.
MaterialsShader = {
uniforms: {
time: { type: 'f', value: 0.0 },
},
vertexShader:
"varying vec2 vUv; \n\
void main(){\n\
vUv = uv;\n\
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );\n\
gl_Position = projectionMatrix * mvPosition;\n\
}",
fragmentShader: [
'varying vec2 vUv;',
'uniform float opacity;',
'#ifdef USE_MAP',
'uniform sampler2D map;',
'#endif',
'void main(){',
'vec3 color = vec3(1.0,0.0,0.0) * opacity;',
'#ifdef USE_MAP',
'vec4 mapTexel = texture2D( map, vUv.xy );',
'gl_FragColor = mapTexel;',
'#endif',
//'gl_FragColor.rgb = color;',
'}'].join("\n")
}
But for some reason the texture itself does not exist, I get black material.
var uniforms = THREE.UniformsUtils.clone( MaterialsShader.uniforms );
uniforms = THREE.UniformsUtils.merge( [uniforms, THREE.UniformsLib['common'],THREE.UniformsLib['lights']] );
var material = new THREE.ShaderMaterial({
uniforms : uniforms,
vertexShader : MaterialsShader.vertexShader,
fragmentShader : MaterialsShader.fragmentShader,
});
How can I get a (map) texture?
1) You need to actually define your map uniform...
MaterialsShader = {
uniforms: {
time: { type: 'f', value: 0.0 },
map: { type: 't', value: yourLoadedTexture },
},
2) You need to define USE_MAP in order to enter that code segment of your shader. Either add this to the top of your shader code:
#define USE_MAP true
Or you can set a defines property for your shader:
var material = new THREE.ShaderMaterial({
uniforms : uniforms,
vertexShader : MaterialsShader.vertexShader,
fragmentShader : MaterialsShader.fragmentShader,
map : yourLoadedTexture,
defines : {
USE_MAP: true
}
});
These have the same effect.

How to add fog to texture in shader (THREE.JS R76)

So firstly, I am aware of this post: ShaderMaterial fog parameter does not work
My question is a bit different...
I am trying to apply the fog in my three.js scene to a shader thats using a TEXTURE and I can't figure it out. My best guess as to what is supposed to go into the frag was:
resultingColor = mix(texture2D(glowTexture, vUv), fogColor, fogFactor);
This works when the texture2D part is just a normal color but as a texture it doesn't render.
THREE.glowShader = {
vertexShader: [
`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`
].join("\n"),
fragmentShader: [
"uniform sampler2D glowTexture;",
"varying vec2 vUv;",
"uniform vec3 fogColor;",
"uniform float fogNear;",
"uniform float fogFar;",
"void main() {",
`
vec4 resultingColor = texture2D(glowTexture, vUv);
`,
`#ifdef USE_FOG
#ifdef USE_LOGDEPTHBUF_EXT
float depth = gl_FragDepthEXT / gl_FragCoord.w;
#else
float depth = gl_FragCoord.z / gl_FragCoord.w;
#endif
#ifdef FOG_EXP2
float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );
#else
float fogFactor = smoothstep( fogNear, fogFar, depth );
#endif`,
// resultingColor = mix(texture2D(glowTexture, vUv), fogColor, fogFactor);
`#endif`,
"gl_FragColor = resultingColor;",
"}"
].join("\n")
}
Here is a fiddle that shows a ShaderMaterial with a texture and red fog
<script id="vertexShader" type="x-shader/x-vertex">
varying vec2 vUv;
varying vec3 vPosition;
void main( void ) {
vUv = uv;
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
varying vec2 vUv;
uniform sampler2D texture;
uniform vec3 fogColor;
uniform float fogNear;
uniform float fogFar;
void main() {
gl_FragColor = texture2D(texture, vUv);
#ifdef USE_FOG
#ifdef USE_LOGDEPTHBUF_EXT
float depth = gl_FragDepthEXT / gl_FragCoord.w;
#else
float depth = gl_FragCoord.z / gl_FragCoord.w;
#endif
float fogFactor = smoothstep( fogNear, fogFar, depth );
gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );
#endif
}
</script>
Here is a bit of how to create the material
var uniforms = {
texture: { type: "t", value: texture},
fogColor: { type: "c", value: scene.fog.color },
fogNear: { type: "f", value: scene.fog.near },
fogFar: { type: "f", value: scene.fog.far }
};
var vertexShader = document.getElementById('vertexShader').text;
var fragmentShader = document.getElementById('fragmentShader').text;
material = new THREE.ShaderMaterial(
{
uniforms : uniforms,
vertexShader : vertexShader,
fragmentShader : fragmentShader,
fog: true
}
);

Resources