artifacts when rendering both sides of a transparent object with three.js
Asked Answered
P

5

19

I try to render both sides of a transparent object with three.js. Other objects located within the transparent object should show too. Sadly I get artifacts I don't know too handle. Here is a test page: https://dl.dropbox.com/u/3778149/webgl_translucency/test.html

Here is an image of the said artifact. They seem to stem from the underlying sphere geometry. artifacts with blending mode: THREE.AdditiveBlending = 1

Interestingly the artifacts are not visible for blending mode THREE.SubtractiveBlending = 2. enter image description here

Any help appreciated!

Alex

Pademelon answered 4/11, 2012 at 18:4 Comment(1)
See this thread: github.com/mrdoob/three.js/issues/2476 .Bloated
B
18

Self-transparency is particularly difficult in WebGL and three.js. You just have to really understand the issues, and then adapt your code to achieve the effect you want.

You can achieve the look of a double-sided, transparent sphere in three.js, with a trick: You need to render two transparent spheres -- one with material.side = THREE.BackSide, and one with material.side = THREE.FrontSide.

Using such methods is generally required if you want self-transparency without artifacts -- especially if you allow the camera or object to move.

three.js r.143

Bloated answered 5/11, 2012 at 17:6 Comment(2)
You can get a different type of artefact if you intersect two transparent objects as well (demo here, and explanation from @mrdoob here)Prepared
Thanks for the example, that's great. I'll have to see whether I can afford to disable sorting of all objects in my scene. Regarding my changes -- which fiddle were you referring to? Now you've updated your fiddle to r59, feel free to remove the link to the one I posted as it doesn't add anything any more.Prepared
R
5

Generally to do transparent objects you need to sort them front to back (I'm guessing three.js already does this). If your object is convex (like both of those are) then you can sometimes get by by rendering each object twice, once with gl.cullFace(gl.CCW) and again with gl.cullFace(gl.CW). So for example if the cube is inside the sphere you'd effectively do

gl.enable(gl.CULL_FACE);
gl.cullFace(gl.CW);
drawSphere();  // draws the back of the sphere
drawCube();    // draws the back of the cube
gl.cullFace(gl.CCW);
drawCube();    // draws the front of the cube.
drawSphere();  // draws the front of the sphere.

I have no idea how to do that in three.js

This only handles objects that are convex and not intersecting (one object is contained entirely inside the other).

Remodel answered 5/11, 2012 at 4:49 Comment(1)
Yes, three.js does sort objects accordingly and - as you explained - by making the front and back separate objects they can profit from the sorting. Thanks for pointing out the limitation to convex and non intersecting objects.Pademelon
S
0

To render that scene correctly with alpha blending, the triangles would have to be rendered from back to front each frame. Your scene is particularly challenging since you have one object inside another, and rendering both sides, which would require rendering part of the sphere, then the cube, then the rest of the sphere. I doubt three.js (or any other scene graph library) can handle this case.

Additive or subtractive blending will work without sorting, but doesn't look as nice.

Sexlimited answered 4/11, 2012 at 20:58 Comment(0)
V
0

Make a clon of the original mesh and flip its normals; then make two identical "one sided" material for each with different name. Not the most classy approach but it worked just fine. I struggled with the same problem, this is what I did :P

The .json file looks like this:

    {
"materials":[
    { "name":"ext", "texture":"f_03.jpg", "ambient":[255.0,255.0,255.0], "diffuse":[255.0,255.0,255.0], "specular":[255.0,255.0,255.0], "opacity":0.7 },
    { "name":"int", "texture":"f_03.jpg", "ambient":[255.0,255.0,255.0], "diffuse":[255.0,255.0,255.0], "specular":[255.0,255.0,255.0], "opacity":0.7 }
],
"meshes":[
    {
        "name":"Cylinder001",
        "material":"ext", ...

    {
        "name":"Cylinder002",
        "material":"int", ...
Vite answered 14/6, 2016 at 14:33 Comment(0)
D
0

i found this answer and it helped me: https://discourse.threejs.org/t/transparent-faces-not-rendering-when-looking-through-another-transparent-face/53306/6

this worked for me:

mat.transparent = true;
mat.alphaTest = 0.001;
Daynadays answered 28/2, 2024 at 7:8 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.