I'm trying to do a partially applied texture with shaders on a teapot in ThreeJS. Currently it looks like this:
I need it to look like this:
But I'm not sure how I should approach this, do I do that clipping with shader itself, or threejs code? I can't figgure out the basic idea of how to do this.
In your fragment shader (it would have been nice if you posted it) you can do something like:
if( vUv.y > 0.4 && vUv.y < 0.6 )
gl_FragColor = vec4( texture_color, 1.0 );
else
gl_FragColor = vec4( background_color, 1.0 );
Take a look at fiddle http://jsfiddle.net/bpatofd4/
Related
I'm trying to make FBO-particle system by calculating positions in separate pass. Using code from this post now http://barradeau.com/blog/?p=621.
I render sphere of particles, without any movement:
The only thing i'm adding so far is a texture in simulation fragment shader:
void main() {
vec3 pos = texture2D( texture, vUv ).xyz;
//THIS LINE, pos is approx in -200..200 range
float map = texture2D(texture1, abs(pos.xy/200.)).r;
...
// save map value in ping-pong texture as alpha
gl_FragColor = vec4( pos, map );
texture1 is: half black half white.
Then in render vertex shader i read this map parameter:
map = texture2D( positions, position.xy ).a;
and use it in render fragment shader to see the color:
vec3 finalColor = mix(vec3(1.,0.,0.),vec3(0.,1.,0.),map);
gl_FragColor = vec4( finalColor, .2 );
So what i hope to see is: (made by setting same texture in render shaders)
But what i really see is: (by setting texture in simulation shaders)
Colors are mixed up, though mostly you can see more red ones where they should be, but there are a lot of green particles in between.
Also tried to make my own demo with simplified texture and same idea and i got this:
Also mixed up, but you can still guess image.
Same error.
I think i am missing something obvious. But i was struggling with this a couple of days now, not able to find a mistake by myself.
Would be very grateful for someone to point me in the right direction. Thank you in advance!
Demo with error: http://cssing.org.ua/examples/fbo-error/
Full code i'm referring: https://github.com/akella/fbo-test
You should disable texture filtering by using GL_NEAREST min/mag filters.
My guess is that THREE.TextureLoader() loads texture with mipmaps and texture2D call in vertex shader uses the lowest-res mipmap. In vertex shaders you should use texture2DLod(texture, texCoord, 0.0) - note the 3rd param, lod, which specifies 0 mipmap level.
This is somewhat a follow-up on this ThreeJS material with shadows but no lights
The question is really simple. I have foliage in my scene that is made up of a couple of planes in a cross, and I need both sides of the plane lit equally, but still being affected by shadow.
With an unmodified shader, the scene looks like this:
As you can see, the front and back side of the planes are not equally lit, causing the "hard edges" to show.
Based on the answer from #WestLangely in the SO question mentioned above, I was able to create the desired effect like so:
THREE.ShaderLib[ 'lambert' ].fragmentShader = THREE.ShaderLib[ 'lambert' ].fragmentShader.replace(
`vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;`,
`
#ifdef DOUBLE_SIDED
reflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );
reflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );
reflectedLight.directDiffuse = diffuseColor.rgb;
reflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();
vec3 outgoingLight = (reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance).rgb * ( 1.0 - 0.45 * ( 1.0 - getShadowMask() ) );
#else
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;
#endif
`
);
Which produced the following result:
As you can see, the "hard edges" are gone, and the foliage looks a lot better now.
However, something is causing them not to be properly affected by lights anymore. Making the environment dark and adding a simple PointLight, gives the following result:
The dark foliage meshes shown above should be properly lit as a whole.
I'm sure there is a better way to go about this, but my knowledge of GLSL only goes so far, especially when it comes to modifying Three.js shaders.
TL;DR: How can I make a material be equally lit on both sides, providing THREE.DoubleSide is set as side on the material, while the entire mesh is still affected by shadows?
Thanks in advance!
I have an extremely simple PNG texture: a grey circle with a transparent background.
I use it as a uniform map for a THREE.ShaderMaterial:
var uniforms = THREE.UniformsUtils.merge( [basicShader.uniforms] );
uniforms['map'].value = THREE.ImageUtils.loadTexture( "img/particle.png" );
uniforms['size'].value = 100;
uniforms['opacity'].value = 0.5;
uniforms['psColor'].value = new THREE.Color( 0xffffff );
Here is my fragment shader (just part of it):
gl_FragColor = vec4( psColor, vOpacity );
gl_FragColor = gl_FragColor * texture2D( map,vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );
gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );
I applied the material to some particles (THREE.PointCloud mesh) and it works quite well:
But if i turn the camera of more than 180 degrees I see this:
I understand that the fragment shader is not correctly taking into account the alpha value of the PNG texture.
What is the best approach in this case, to get the right color and opacity (from custom attributes) and still get the alpha right from the PNG?
And why is it behaving correctly on one side?
Transparent objects must be rendered from back to front -- from furthest to closest. This is because of the depth buffer.
But PointCloud particles are not sorted based on distance from the camera. That would be too inefficient. The particles are always rendered in the same order, regardless of the camera position.
You have several work-arounds.
The first is to discard fragments for which the alpha is low. You can use a pattern like so:
if ( textureColor.a < 0.5 ) discard;
Another option is to set material.depthTest = false or material.depthWrite = false. You might not like the side effects, however, if you have other objects in the scene.
three.js r.71
So I spent quite a bit of time writing my own simple Phong shader before figuring that there must be some way to modify the existing three.js Phong shaders to suit my needs. What I ended up doing looked like this
var phongShader = THREE.ShaderLib.phong;
var phongMatUniforms = THREE.UniformsUtils.clone(phongShader.uniforms);
var uniforms = phongMatUniforms;
uniforms.currentTime = {
type : "f",
value : 1.0
};
uniforms.hourlyValues = {
type : "fv1",
value : hourlyValuesArray
}
Now that I had access to the Phong vertex and fragment shader, I went poking through the shader and modified the section that I thought would achieve what I was looking for :
//original Three.js phong shader line
mvPosition = modelViewMatrix * vec4( position, 1.0 );
//my edited / updated line
mvPosition = modelViewMatrix * vec4( position.x, position.y, position.z + interpolatedValue, 1.0 );
Great! Everything worked just like I thought it should. Then I decided to try and add shadows with a spotlight. The good news was that shadows worked but they didn't work with the geometry that the shader had modified. Here's a screenshot example:
http://imgur.com/8Sdxq60
So I figured that there must be somewhere else in the Phong vertex shader that needs another simple update. The problem is, I can't find it. It looked to me like this:
#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )
//original shader code
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
//updated to account for distorted geometry
worldPosition = modelMatrix * vec4( position.x, position.y, position.z + interpolatedValue, 1.0 );
#endif
Should do the trick but all it did was produce the screenshot above.
I'm kind of at a loss here as to what / where in the shader I should be modifying to take into account my distorted geometry. It looks like this bit at the end:
#ifdef USE_SHADOWMAP
for( int i = 0; i < MAX_SHADOWS; i ++ ) {
vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;
}
#endif
Sets the shadow varyings that I need, but updating "worldPosition" like I did should fix that, no?
Ok, so I found the relavant shaders for the shadow casting. They do reside in THREE.ShadowMapPlugin. Specifically there is a line :
if ( object.customDepthMaterial ) {
material = object.customDepthMaterial;
}
So you assign a material to the objects.customDepthMaterial.
I used:
var depthShader = THREE.ShaderLib[ "depthRGBA" ];
var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );
depthUniforms.currentTime = {
type : "f",
value : 1.0
};
depthUniforms.hourlyValues = {
type : "fv1",
value : hourlyValuesArray
}
As the basis for the depthmaterial and then assigned it to the object thusly:
extrudedMesh.customDepthMaterial = depthMaterial;
Worked like a charm. You can then update the uniforms for the depth material just like you would for any other material.
I have a problem completely alluding me. I am trying to mix two cube textures together. But for some reason I cannot seem to mix one texture with the other based on the alpha. The function looks like this:
vec4 baseColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );
vec4 atmosphereColor = textureCube( tAtmosphere, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );
vec4 texelColor = mix( atmosphereColor, baseColor, atmosphereColor.a );
gl_FragColor = texelColor;
All the materials concerned have depthWrite: true, depthTest: true and transparent: true. One is a texture with 6 images and the other is a WebGLRenderTarget. The WebGLRenderTarget is created with an alpha channel.
format: THREE.RGBAFormat
Individually they both work as expected. For example if I use gl_FragColor = atmosphereColor;, the alpha is visible. But as soon as I try to mix one with the other, no alpha is applied. So for example when I do this:
gl_FragColor = vec4( baseColor.r, baseColor.g, baseColor.b, atmosphereColor.a );
It still will not use the alpha variable provided (it just sets it to 1.0) - even though I know the value is present and varying as I just set gl_FragColor to atmosphereColor and could see it varying D:>
Any ideas? :(
I was able to find the source of the problem. It was related to to the clearAlpha parameter of the renderer. This needed to be set to 0 instead of 1 for my case.