Updating the position attribute directly of a Shape geometry breaks the texture on the Mesh. How do I fix the textures? - three.js

I try to make a wall with a window in it. I draw the corners of the wall and the corners of the window after, from the bottom left, counter clockwise. Then I manipulate the 4 vertex of the window via javascript and update the position attribute of the geometry accordingly. The window moves correctly but the textures are not. Any help would be appreciated.
Here is what I do after calculating the new positions array:
this.geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
Here is the full demo: https://jsfiddle.net/wg1phnz6/45/

Related

Raycasting to intersect objects that have been displaced by vertex shader

Let's say I have a vertical list of meshes created from PlaneBufferGeometry with ShaderMaterial. The meshes are distributed vertically and evenly spaced.
The list will have two states:
Displaying the meshes as they are
Displaying meshes with each object's vertices transformed by the vertex shader to the same arbitrary value, let's say z = -50. This gives a zoomed out effect and the user can scroll through this list (in the code we do this by moving the camera y position)
In my app I'm trying to make my mouseover events work for the second state but it's tricky since the GPU transforms the vertices so the updated vertices are not reflected in the attributes on the JS side.
*Note I've looked into GPU picking and do not want to use it because I believe there should be a simpler way to do this without render targets
Attempted Solution
My current approach is to manually change the boundingBox of each plane when we are in the second state like so:
var box = new THREE.Box3().setFromObject(plane);
box.min.z = -50;
box.max.z = -50;
plane.geometry.boundingBox = box;
And then to change the boundingSphere's center to have the same z position of -50 after computing it.
I did this approach because I looked into the Raycaster and Mesh code for THREE.js and it seems like they check both boundingSphere and boundingBox for object intersections. So I thought if I modified both of them to reflect the transforms done by the GPU, the raycaster would work fine but it doesn't seem to be working for me.
The relevant raycaster code is here:
// mouse being vec2 of normalized coordinates and camera being a perspective camera
raycaster.setFromCamera( mouse, camera );
const intersects = raycaster.intersectObjects( planes );
Possible Theories
The only thing I can think of that's wrong about this approach is maybe I'm not projecting the mouse coords right? Since all the objects now lie on the plane z = -50 would I need to project those mouse coordinates to that plane?
Inspired by the link posted by #prisoner849 I found a working solution to just create additional transparent planes equal to the number of planes in the scene. In these planes, I set the z position to -50 and just intersect with these when in state #2.
A bit hacky, but works for now.

How to offset target position in ThreeJS controls

I am using ThreeJS's OrbitControls so that when an object in my scene is clicked, the camera travels close to it and and starts orbiting around it. I'm just moving the controls.target position, camera position and setting controls.autoRotate = true.
The clicked object gets centered on screen, which is nice, but sometimes I need to show a text covering up to 50% of the bottom area of the screen, and then the selected objects gets hidden by it. So, I'd need to somehow offset the rotation center up a bit.
Perhaps another way of asking this is that I need to change the center of rotation so that it is NOT the center of the screen (or the center of the renderer canvas)
I've tried moving the target up but, of course, then the camera doesn't orbit around the selected 3D object but around an empty space close to it. Any idea on how to proceed?
Many thanks!
I finally got the desired results following the comments in this other thread:
by using camera.setViewOffset

three.js delay in updating local clipping planes

For realising a scrollable text container (using own bitmap fonts that are basically small sprite meshes) I am using local clipping planes.
When my text container moves the clipping planes are updated according to the global boundaries of my container.
This works perfectly except for fast movements. In this case the clipping planes are slightly delayed behind the container making the text shine through where it shouldn't.
My first thought was that the necessary code for updating the clipping planes might cause the delay.. but when I use apply this order:
1. update the text box position
2. update the clipping planes
3. render()
the delay still exists
Is the reason maybe located in the threejs framework in how the actual clipping is applied?
Here's a small code snippet that shows how I compute my upper clippin plane using two helper meshes. The one is a plane that is positioned orthogonally on my text object (red plane in the picture). The other one is a THREE.Object3D that is positioned in the middle of the upper edge for computing the right plane constant.
// get the world direction of a helper plane mesh that is located orthogonally on my text plane
var upperClippingPlaneRotationProxyMeshWordDirection = _this.upperClippingPlaneRotationProxyMesh.getWorldDirection();
// get the world position of a helper 3d object that is located in the middle of the upper edge of my text plane
var upperClippingPlanePositionProxyObjPosition = _this.upperClippingPlanePositionProxyObj.getWorldPosition();
// a plane through origin which makes it easier for computing the plane constant
var upperPlaneInOrigin = new THREE.Plane(upperClippingPlaneRotationProxyMeshWordDirection, 0);
var dist = upperPlaneInOrigin.distanceToPoint(upperClippingPlanePositionProxyObjPosition);
var upperClippingPlane = new THREE.Plane(upperClippingPlaneRotationProxyMeshWordDirection, dist*-1);
// clipping plane update
_this.myUpperClippingPlane.copy(upperClippingPlane);
picture showing the text object with clipping plane helpers
I found the reason for the delay. In my matrix updating code I only used updateMatrix() on the text object when it moves. To make sure that its child objects including the helper meshes update instantly I had to call updateMatrixWorld(true), this makes sure that the clipping planes are computed correctly

Unproject Webgl

So I am trying to create a 2d drawing program in WebGL and I can draw everything fine but I am having a lot of difficulty detecting the location of mouse clicks.
I have a 4x4 projection matrix set up as follows:
mat4.perspective(45, this.gl.viewportWidth / this.gl.viewportHeight, 0.1, 100.0, projectionMatrix);
I then have a 4x4 view matrix which holds the camera position as follows:
mat4.translate(viewMatrix, [camera.getX(), camera.getY(), camera.getZoom()]);
I can get a 2d vector of the position of the mouse click on the screen ranging from [-1,-1] in the top left to [1,1] in the bottom right.
What I want to be able to do is take the current position of the camera, get the frustum bounds on the z-plane and then use my relative mouse click positions to get the actual world space position on the z-plane.
Note:
The camera does not rotate, only pan and zoom.
Everything is drawn on the model matrix which is on the z=0 plane.

Update plane texture offset from movement on a sphere

I'm working on a driving simulation in Three.js using height map data from the planet Venus.
GitHub repo here: https://github.com/hypothete/venus-walk
Here's how the simulation works so far:
In a hidden scene, a camera called the globeCamera moves at a fixed height over a sphere textured with the Venus height map. You can see this happening in the lower left viewport in my picture. The globeCamera renders its view to a WebGLRenderTarget to be used as a local height map. The result is in the second viewport in the middle left.
In the visible scene, a plane mesh called the terrainMesh has its vertices displaced up and down in correspondence with the values from the local height map. This gives the illusion that a vehicle placed in the center of the plane is moving across a surface when actually we're just updating the plane's vertices from the movement of the globeCamera.
Since I know the rotation of the globeCamera, I can pass that value to my fragment shader to rotate the terrainMesh's rock texture with the height map.
How can I offset the rock texture's position so that texture units translate with the terrain as well? I've tried tracking the globeCamera's offset as a 2D vector and adding that to the rotated UV in the fragment shader, but my results were inconsistent. Thanks for your help.

Resources