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.
Interestingly the artifacts are not visible for blending mode THREE.SubtractiveBlending = 2.
Any help appreciated!
Alex
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
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).
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.
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", ...
Related
I want to render a cube similar to .
My problem is how to render the face projections.
I tried using Reflector, but it is tricky to size and position so it captures just the face that I want, and also shows the sides.
I also saw I can use a separate canvas to render (I imagine using an orthographic camera), but I wish for everything to be in the same canvas. I saw an example with multiple views, but it seems that they can't be positioned behind.
So, is there a way to achieve this?
One possible approach to solve the issue:
Setup an orthographic camera such that its frustum encloses the cube. You can then position the camera in front of each side of the cube, use lookAt( cube.position ) to orient it properly and then render the scene into a render target. You need one render target per side. You can then use it as a texture for the respective plane mesh.
There is an official live example that demonstrates how RTT (render-to-texture) is done with three.js. Try to use it as a code template for your own app.
https://threejs.org/examples/#webgl_rtt
I'm trying to render a fairly complex lamp using Three.js: https://sayduck.com/3d/xhcn
The product is split up in multiple meshes similar to this one:
The main issue is that I also need to use transparent PNG textures (in order to achieve the complex shape while keeping polygon counts low) like this:
As you can see from the live demo, this gives really weird results, especially when rotating the camera around the lamp - I believe due to z-ordering of the meshes.
I've been reading answers to similar questions on SO, like https://stackoverflow.com/a/15995475/5974754 or https://stackoverflow.com/a/37651610/5974754 to get an understanding of the underlying mechanism of how transparency is handled in Three.js and WebGL.
I think that in theory, what I need to do is, each frame, explicitly define a renderOrder for each mesh with a transparent texture (because the order based on distance to camera changes when moving around), so that Three.js knows which pixel is currently closest to the camera.
However, even ignoring for the moment that explicitly setting the order each frame seems far from trivial, I am not sure I understand how to set this order theoretically.
My meshes have fairly complex shapes and are quite intertwined, which means that from a given camera angle, some part of mesh A can be closer to the camera than some part of mesh B, while somewhere else, part of mesh B are closer.
In this situation, it seems impossible to define a closer mesh, and thus a proper renderOrder.
Have I understood correctly, and this is basically reaching the limits of what WebGL can handle?
Otherwise, if this is doable, is the approach with two render scenes (one for opaque meshes first, then one for transparent ones ordered back to front) the right one? How should I go about defining the back to front renderOrder the way that Three.js expects?
Thanks a lot for your help!
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.
Interestingly the artifacts are not visible for blending mode THREE.SubtractiveBlending = 2.
Any help appreciated!
Alex
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
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).
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.
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", ...
This is an effect I was able to get working relatively easy in Unity5, and I'm wondering how I could go about doing the same thing in three.js.
Bascially, I am projecting a particular shape (an "asteroids ship" or triangle) onto a curved surface. The main technique is you insert what's called a "cookie" (technical term is cucoloris) between the projector light and the screen and thus project that shape onto the (typically curved) surface.
A picture is worth a thousand words, so here's a screen print of the scene from unity 5:
I'm just looking for some general guidelines on where to start, not a detailed description. For instance, I see Projector and RayCaster. Would either of these work? Unfortunately, the term "cookie" is overloaded with other meanings, so I can't find any relevant references on searches for "three js cookie".
The cookie itself is regarded as a texture in Unity, as the following screen print shows:
Any advice would be greatly appreciated.
Many Thanks.
While I was never able to figure out how to use cookies with three.js, I ultimately came up with a much better solution using off-screen rendering. This method does not replace the usage of cookies in general, but if you're attempting to use a cookie to project a shape onto an irregularly shaped target surface, then you can instead render your projection scene to an off-screen buffer, and then apply that to the surface of the target object as a dynamic texture.
Here's a screen shot demonstrating what I did:
At the bottom, I am showing the contents of the offscreen buffer where I render the source scene (you do not have to display this buffer, I'm just showing it for illustration purposes). It's simply a flat plane. I move the objects about on that the scene in a simple linear fashion, not having to account for the curvature of the target geometry. You can basically think of this as "wrapping paper".
Then you assign this buffer as a texture to the target object, which in this case is the green cylinder in the upper portion of the screen:
this.cylMaterial = new THREE.MeshBasicMaterial()
this.bufferGamePlaneTexture = new THREE.WebGLRenderTarget(
window.innerWidth,
window.innerHeight,
{minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter}
)
...
this.cylMaterial.map = this.bufferGamePlaneTexture.texture
var projCylGeom = new THREE.CylinderGeometry(3, 3, 12, 50)
this.projCyl = new THREE.Mesh(projCylGeom, this.cylMaterial)
...
//render to offscreen buffer in your animation loop
bufferRenderer.render(
this.bufferGamePlaneScene,
this.bufferSceneCamera,
this.bufferGamePlaneTexture
)
As you can see, the source shapes end up as molded to fit the target geometry and curves as necessary, just as if the the shapes were directly drawn on the target surface.
In effect, you're wrapping your target object with the custom-generated "gift wrapping paper" you generated earlier. The game engine takes care of all the necessary transformations, so you can render your source scene with simple "linear" semantics, independent of the target geometry. This also allows you to easily apply it to a different surfaces (e.g. a sphere) without having to make any changes to source scene logic.
Every technique that I've found or tried to render outline in OpenGL uses some function that is not avaliable on OpenGL ES...
Actually what I could do is set depthMask to false, draw the object as a 3 pixels wide line wireframe, reenable the depthMask and then drawing my object. It doesnt work for me because it outline only the external parts of my object, not the internals.
The following image shows two outlines, the left one is a correct outline, the right one is what I got.
So, can someone direct me to a technique that doesn't is avaliable on OpenGL ES?
Haven't done one of these for a while, but I think you're almost there! What I would recommend is this:
Keep depthMask enabled, but flip your backface culling to only render the "inside" of the object.
Draw the mesh with that shader that pushes all the verts out along their normals slightly and as a solid color (your outline color, probably black). Make sure that you're drawing solid triangles and not just GL_LINES.
Flip the backface culling back to normal again and re-render the mesh like usual.
The result is that the outlines will only be visible around the points on your mesh where the triangles start to turn away from the camera. This gives you some nice, simple outlines around things like noses, chins, lips, and other internal details.