Is there a way to draw directly onto a model/texture in threejs? - three.js

I've been looking for a solution to this problem for a project I'm working on. I'd like to know if there is a way to click on a plane geometry and draw onto it, paint style, and have the texture update as you draw on it.
After this, is there a way to save that texture while in the browser now that you've edited it?

You could use raycasting to determine the UV texture position where the mouse intersection takes place. Raycaster.intersectObject returns an array of objects, one of its properties is .uv. You can see it in action in this demo.
You can use a 2D <canvas> as the source of the texture. Once you have the UVs from the intersection, you could use that position to draw on the canvas as demonstrated in this other demo

Related

User painting on a canvas within A-Frame

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.

Dragging 3D objects on walls using mouse in three.js

I am trying to achieve movement of an object on walls, instead of only one plane. In this example, an object dragged on walls by using:
intersects = raycaster.intersectObjects([walls]);
object.position.copy(intersects[0].point);
However, with this method, the object jumps because the object's center moves to the mouse. There is a related question and helpful JSFiddle for dragging on one plane without jumpin Would you please help me to modify it for multiples planes (walls)? Thanks
After reading your comment, I think what you're looking for is you want the object to animate to the position. You can do this a few ways. The "threejs" way is to move it each frame (within the animate/update loop). You could do this with Vector3.lerp by storing intersects[0].point as your target location and lerping your object.position to it each frame. Another option is to use an animation library like animejs or gsap.

three.js: Render 2d projection

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

Creating a magnifying-glass effect in three.js WebGL

I'm working with an orthographic view in three.js/WebGL renderer, and I want a magnifying glass that tracks with the user mouse. I'm looking for the best way of doing this that's efficient.
When working with html5 canvas raw commands, this was easy: I simply defined a circular clip region, zoomed my coordinates, and re-drew the whole scene. With 3d objects, it's less obvious how do to it.
The method I've found so far is to do the following:
Define a second camera that looks into the zoomed region. Set the orthographic clip coordinates to be small so that it doesn't need to do much work
Create a THREE.WebGLRenderTarget
Tell the renderer and all my line textures that the resolution is about to change
Render the scene into the RenderTarget
Add a CircleGeometry as a MeshObject at the spot at the mouse position (in world coordinate but above the rest of the scene, close to the camera). Call this the lens.
Give the lens the WebGLRenderTarget as a texture.
Go back to my default camera, reset all my resolution parameters, and redraw the scene with the 'lens' object added.
This works (see image below) but I'm worried about parts of it:
I have to render twice per frame
Lines don't draw well, because the resolution problems. I have to keep track of all materials that need to know screen resolution and update all of them twice per screen render.
Related problems:
I want to overlay some plot axes on top of this, and possibly gridlines. These would change as the view pans. I'm not sure if I should make these 3d objects, or do it in a 2d canvas context I lay overtop.
I want to overlay some plot lines, and have them show up sensibly in the zoomed view. "Sensible" here is hard to figure out: I don't want them too fat in the zoomed view, but I also don't want to scale them up as much as the image detail (which is being rendered as a texture onto Plane objects behind).
This is a long post, but I'm still new to three.js and looking for good ideas.

Can I draw 2D shapes onto on a flat three.js face?

I would like to play around with testing a 3D map, of sorts. At it's simplest, one flat pane, with map lines etc. drawn onto it, flat (as if I was drawing onto an HTML canvas). But I want that pane to be movable in 3D space.
I know that I can make a flat pane in three.js very simply, but is it possible to implement some sort of 'custom texture' that would allow me to programmatically draw onto this pane?
It is called render-to-texture in webGL.
Three.js provides WebGLRenderTarget which can be used as image source for further textures. You render your scene to WebGLRenderTarget instead of main WebGL screen. Then you use this WebGLRenderTarget as image source for the texture.
A lot of 2D post-processing works like this. They render the world to 2D texture, then use fragment shaders to apply per-pixel postprocessing code, like blurring.
For examples, see e.g. http://mrdoob.github.com/three.js/examples/webgl_postprocessing.html
It renders the scene for 2D postprocessing, but the theory is the same.
Here is the WebGLRenderTarget setup code:
https://github.com/mrdoob/three.js/blob/master/examples/js/postprocessing/EffectComposer.js#L14

Resources