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
Related
I have an A-Frame scene that contains, among others, a <canvas> element that is the material source for a 3D scene object. I can paint on the canvas programmatically, and it shows up as texture. So far, so good.
However, I'd now also like to enable the user to paint something on the canvas using the controllers. I have added two raycasters/controls:
<a-entity laser-controls="hand: left" raycaster="objects: table2"></a-entity>
<a-entity laser-controls="hand: right" raycaster="objects: table2"></a-entity>
And on the table2 object, I have added a raycaster-listen mixin as described in https://aframe.io/docs/1.3.0/components/raycaster.html#listening-for-raycaster-intersection-data-change.
This works in so far as I get the console log entries with the world coordinates of the intersection point, but I'm absolutely stuck at how to get from the world coordinates back to the canvas coordinates I need to actually paint in the right spot.
In addition, it seems no canvas draw commands I issue in the raycaster-listen tick callback actually have any visible effect (regardless of coordinates).
Any hints appreciated!
As usual, I figured it out the next day 😉
[...] I'm absolutely stuck at how to get from the world coordinates back to the canvas coordinates I need to actually paint in the right spot.
Solution found at https://discourse.threejs.org/t/convert-camera-frustrum-to-uv-coordinate-on-texture/16791/2 - just use intersection.uv which actually contains the normalized texture coordinates of the intersection point. Scale by canvas width/height and you're done.
[...] it seems no canvas draw commands I issue in the raycaster-listen tick callback actually have any visible effect.
Solution found at aframe not rendering lottie json texture mapped to canvas but works in three.js - set texture.needsUpdate = true; in the tick callback after drawing on the canvas.
I'm trying to use a Shader material to create an area of transparency around my camera.
To achieve that, I'm checking if a vertex is inside a given radius, if so, I set its color with a custom opacity value < 1, such as 0.4.
This is working fine, but sometimes some transparent geometries are blocking the elements behind it. I took a look into the docs and some other similar question and figured out that usually we set the depthWrite = false and transparent = true only to transparent materials.
My problem is that I have only one material representing all my geometries but I want to set depthWrite = false; transparent = true to all vertices inside the radius and depthWrite = true; transparent = false to the ones outside it. Does anyone knows if this is something achievable or if there is another possible solution?
Thanks in advance
answering my own question! Hope this can help someone
It looks like it was not possible the way I was doing because I had only one material for the visible and transparent part.
Then, I decided to have 2 different shader materials rendering the same geometries, the visible and transparent ones, to set the depthWrite and transparent properties accordingly.
Also I discarded, using the fragment shader, the visible portion inside my transparent area and discarded the invisible one in the visible area.
It looks like it's working fine now
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", ...
i am trying to cast an shadow on an totally transparent plane in SceneKit on OSX. I am struggling with this problem since several hours and do not come to any solution.
My Purpose is to generate an Screenshot of several objects with an transparent background and just the shadow on an invisible Plane.
Do you have any suggestions for me how i can make this with apples SceneKit?
Do i have to program my own shader, can i make this work with shadermodifiers or can i use built in functionallity?
UPDATE:
I find an alternative solution for anyone who needs:
create a white plane under 3D model, note that the color of plane must be pure white.
set blend mode of plane's material to SCNBlendModeMultiply.
set light model of plane's material to SCNLightingModelLambert.
This works because any color multiply white color (1, ,1, 1) return itself And lambert light model will not take account of directional light, So the plane will always be background color which look like transparent. Another benefit of this solution is you don't need change light‘s shadow rendering mode.
For people who used to inspector of Xcode.
According to SceneKit: What's New.
First, add a plane under you model. Then prevent it from writing to colorBuffer.
Second, change your light model's shadow rendering mode to deferred. Notice that you must use light which can cast shadows.
Oily Guo, your solution works. Here the solution is in code:
Configuration of the light source:
light.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
light.shadowMode = .deferred
And for the floor (ie. SCNFloor underneath your objects):
material.diffuse.contents = UIColor.white
material.colorBufferWriteMask = SCNColorMask(rawValue: 0)
I do not have an answer to your question, however I have a workaround:
Render your scene and keep the image in memory
Change all the materials in your object for pure black, no specular
Change the plane and the sky to a fully white material, lights to white
Render the scene to another image
On the second image, apply the CIColorInvertand CIMaskToAlpha Core Image filters
Using Core Image apply the Alpha Mask to the first render.
You'll get an image with a correct Alpha channel, and transparent shadows. You will need to tweak the materials and lights to get the results you want.
The shadow may become lighter on the edges, and the only way around that is rendering it as yet another image, and filling it with black after the Mask to Alpha step.
When I add to the scene two objects and set their transparency as true with some opacity and using TrackballControls I rotate the scene by mouse, the object which was initially further from camera loses its transparency.
I read that this is Z-buffer problem and further objects from camera will be displayed first. But when I rotate the scene using TrackballControls, camera changes its position, so transparent objects should be displayed correctly. But it is not like that.
Here in this picture - on the right is frontview, on the left is backview which is not displayed correctly:
http://www.foto-ondruskova.cz/Experiment/lenses.jpg
Please, any solutions?
I have come across this problem and setting alphaTest: 0.5 to the material as suggested here solved my problem. But it is hit and miss. Give it a try. Hopefully it works!