Weird effects with AddEquation - three.js

I'm trying to render multiple radial gradients, with the goal of their colors adding up where they overlap. I'm doing a very simple three.js code for that, see fiddle here.
However, I'm getting an unexpected effect - the borders of overlapping gradients seem to be making the other gradients darker, see the dark lines in this screenshot:
I don't understand why this is happening. If I understand the OpenGL documentation correctly, GL_FUNC_ADD should simply add the component values (and, I assume, clamp to 1.0). I'm using GL_SRC_ALPHA and GL_ONE (or rather, their equivalents in three.js) for source/destination factors, e.g.
const mat = new THREE.MeshBasicMaterial({
alphaMap: grad2,
blending: THREE.CustomBlending, // Similar with THREE.AdditiveBlending
blendEquation: THREE.AddEquation,
blendSrc: THREE.SrcAlphaFactor,
blendDst: THREE.OneFactor,
});
What am I missing?

It is doing what you want, I think. The borders are not darker, it is other areas that are brighter.

Related

Why won't "dithering" on three.js material actually do dithering?

I have a simple material on my object like:
THREE.MeshPhysicalMaterial({
roughness:1,
color: 0xffffff,
dithering:true
})
and one simple directional light. Now, i thought the "dithering" would do something like this with the shadows:
However, it doesn't seem to do anything. What does the dithering attribute actually do? Or did i forget to configure something?
Dithering in the material is a very subtle effect that helps prevent banding when colors aren’t blending smoothly. The effect you’re showing in your screenshot is much more pronounced, black and white, and largely pixelated. The default materials don’t have this functionality.
The effect you want can be achieved as a post-process pass. Threejs has a demo on how to do it here: https://threejs.org/examples/?q=post#webgl_postprocessing
Here’s the source code for that demo. Notice that it uses the DotScreenShader shader pass.

Black background for three.js sprites with depthTest true

I have been experimenting with converting the custom attribute BufferGeometry example (https://threejs.org/examples/webgl_buffergeometry_custom_attributes_particles.html) into a fly through animation and I find that the sprites have dark backgrounds (and those that I create myself as well) if depthTest is set to true. See the image.
The sprite in the custom attribute example has a transparent background but this appears to be ignored when it is rendered if depthTest is set to true.
I have tried numerous custom blending rules but cannot find a way to remove the background, only to reduce the effect a bit. The background disappears if depthTest is set to false.
Is this a known limitation? Is there a work around?
I am modifying this question to add clearer images with a different ball sprite (also with a transparent background). This image has depthTest set to true for the custom ShaderMaterial used in the https://threejs.org/examples/webgl_buffergeometry_custom_attributes_particles.html three.js example.
By comparison, this uses multiple PointsMaterials from a different three.js example (https://threejs.org/examples/webgl_points_sprites.html), also with depthTest set to true and using the PointsMaterial map parameter for the sprite.
As you can see, the second PointsMaterial example works as expected. Because PointsMaterial only accepts one fixed size and color, I need to create 36 different point geometries to render this image.
I would prefer to use the custom shader in the first example (which has custom size and color attributes and requires only one geometry). Is there a way to define a custom shader to support depthTest like the PointsMaterial does?
WebGL has a depth buffer that's used to find out which pixels are hiding behind other pixels. If a pixel is hiding behind another, it doesn't get rendered. Typically that's what you would want, why would you waste GPU time rendering pixels you're never going to see? Consider the example depthbuffer below, white squares are closer to the camera, while darker squares are further away:
If there was a square hiding behind another one, you wouldn't see it in the depthBuffer, you'd only see the closest one. The depthBuffer doesn't know that your squares have partial transparency and you want some parts to be see-through. This is an issue in other realtime engines too, this is an example from Unity:
The squares that are closer are blocking part of the squares that are further away in the depthBuffer, so the occluded pixels don't get rendered. That's why setting depthTest to false is useful. You're basically telling the renderer to stop testing which pixels are behind others, and just render all of them. Here it is again with depthTest = false:
If you must set depthTest on, (for instance, if you want the sprites to hide behind a solid wall) you could set depthWrite to false on the sprite material. It would still check which pixels are behind others, but the pixels from the sprites wouldn't get written to the depthBuffer, so no sprite could block another sprite.
depthTest: true; // Tests pixel depth
depthTest: false; // Does not test pixel depth
depthWrite: true; // Writes pixel depth to depthBuffer
depthWrite: false; // Does not write pixel depth to depthBuffer
As far as blending mode, I prefer THREE.AdditiveBlending because it gives the particles a nice glowing effect when they accumulate one on top of the other. But that's up to you.

Workaround of disabling depth testing for transparent objects?

In the scene I've got only transparent objects, thus with enabled depth testing it causes objects hiding each other. I know depth testing doesn't consider any transparency, it just writes to the depth buffer looking at values of z. Then how to render correctly two transparent objects ?
I did this renderer.context.disable(renderer.context.DEPTH_TEST); but nothing changed
illustration of my concrete problem:
the cube is MeshLambertMaterial({color: ..., transparent: true, opacity: 0.6})
and the plane is MeshLambertMaterial({color: ..., transparent: true, opacity: 0.4})
cube is rendered after plane, but if the cube is opaque then whole of it will be rendered correctly without any discarding (also look at the points they are also opaque hence are visible).
So how to get it consider transparency and don't care about the order of rendering as well so two transparent objects don't hide each other ?
In three.js, you can turn off depth testing by setting
material.depthTest = false;
Don't be surprised if you have artifacts when the camera position is changed.
You might also want to read this answer.
three.js r.80

How can I light emission per vertex and per vertex lighting in ThreeJS?

I want to see a chart with color specified per vertex and to get little bit of shading too.
But if I use MeshBasicMaterial I only get VertexColor with no dynamic shading.
On the other hand, if I use MeshPhongMaterial I just get shading but without emissiveness from my vertex colors.
As the THREE.JS PhongMaterial supports vertexColors, giving you a nice combination of dynamic lighting and vertex colors, I'm not quite sure I understand your question. Perhaps that is something you should investigate more?
However, as an alternative to writing a custom shader you could try rendering your model in multiple passes.
This will not give you as much control over the way the vertex colors and phong lighting are combined as a shader would, but often a simple add/multiply blend can give pretty decent results.
Algorithm:
- create two meshes for the BufferGeometry, one with the BasicMaterial and one with the PhongMaterial
- for the PhongMaterial, set
depthFunc = THREE.EqualDepth
transparent = true;
blending = THREE.AdditiveBlending(or MultiplyBlending)
- render the first mesh
- render the second mesh at the exact same spot

Three.js: Casting a Shadow onto a Webpage

Is it possible in three.js to create transparent/invisible plane, which can receive shadows? My aim is to draw some object on 3d canvas without background (so I can see webpage behind the canvas element). I want the object to cast shadows on the background and I thought, if I could make an invisble plane, then webpage background is still visible. Shadows are casted on the plane and it seems like shadows are on the webpage.
Right now I can make a white plane with opacity 0.5 (or similar), but this way the plane is visible. Ideally the plane should be completely invisble (except for shadows).
EDIT: I created an exampled (based on this): http://jsfiddle.net/s5YGu/2/
Here I have opacity 0.5, but you can see the plane. If I set opacity to 0, then the whole plane and the shadows disappear.
I made this work by hacking on basic shader, here is working shader code http://pastie.org/5088640
It has no drawbacks AFAIK, like opacity: 0.1
Yes, you can achieve the effect you want, and it looks pretty good on my machine at least. :-)
Here is a fiddle: http://jsfiddle.net/ZXdV3/25/
There are a couple of issues. First, you will have to set alpha: true in the renderer constructor args.
Second, although I assume you'd like the plane to be completely transparent, you'll have to settle for material.opacity = 0.1, or so.
Third, if you are placing a canvas over the webpage, and you want the web page to be interactive, you are going to have to suppress pointer events in the canvas (I'm not sure if IE supports this, though): container.style.pointerEvents = 'none';
three.js r.67

Resources