Three.js - Clip plane if object intersects? - javascript

I'm using a PlaneGeometry as water, and have added a ship (gltf model) on it. Problem is, when the boat slightly rests into the water, the water is shown inside the boat, even though the boat is afloat. Is there a way to clip the water when a boat (or other models/objects) intersect with it with motion?

Every material in Three.js has an AlphaMap property that you can use to change the opacity of the mesh. So you could draw a black rectangle where the boat is to "cut out" that part of the water plane with an opacity of 0.
I presume your boat is going to be moving, so your texture would also need to move this black rectangle. To solve this, you could use an HTML <canvas> element to draw and move the black rectangle. Then you could use THREE.CanvasTexture to turn the <canvas> into a texture for your plane's alpha.
const drawingCanvas = document.getElementById( 'drawing-canvas' );
const canvasTexture = new THREE.CanvasTexture( drawingCanvas );
const waterMaterial = new THREE.MeshBasicMaterial({
transparent: true,
alphaMap: squareTexture
});
See this working demo for how to use a 2D canvas as a texture in your 3D scene. When you draw on the top-left square, you'll see it being applied to the cube. You could copy this approach, but instead of assigning it to material.map, you'd use it on material.alphaMap.

You could check for the position of the hull vertices of the ship each frame and, given enough points on the PlaneGeometry, you could displace all vertices of the surface inside the ship hull to the y coordinate of the nearest hull vertex. This could probably also be done by a custom shader, which is probably a more efficient solution.
#Marquizzo's idea with the alpha channel is probably a better solution, too, since you don't really want to simulate the displacement of the water, as I assume, but simply get rid of the display of water inside the ship. In this case, I would place an orthographic camera above the ship, set the near and far clipping planes as close as possible to the plane, and use the alpha channel or rather CanvasTexture inside the alpha channel as rendertarget. This way, you'll get a real time alpha map that also reacts to rolling, pitching and heave of the ship.

Effect of floating is made with sin function, applied to y-coordinate. You can use the same principle to make gltf model(ship) move on any coordinate axis.
Example:
position.y = Math.sin(ship.userData.initFloating + t) * 0.15;

Related

3D orienting particles using velocity and position vectors in p5js

I'm currently writting a 3D implementation of the boids algorithm in P5.js but I'm having trouble orienting my boids according to their direction (velocity). Rotations are limited to RotateX(), RotateY() and RotateZ(). The simplest solution that I feel should work goes along these lines :
push();
translate(this.pos);
rotateZ(createVector(this.vel.x, this.vel.y).heading());
rotateY(createVector(this.vel.x, this.vel.z).heading());
beginShape();
// Draw Boid Vertices..
endShape();
pop();
But it doesn't.
I've written a much smaller version of the program which contains only the orientation for randomly generated particles that go in a single direction. It is available here directly on the p5js website : https://editor.p5js.org/itsKaspar/sketches/JvypSPGGh
There is a default orbit control so you can zoom and drag the mouse to check the orientation of the particles.
Thanks so much, I've been stuck on this for half a day now
From your demo, the z component is flipped, and you can test this from only trying one of the rotations at a time. Second, chaining rotations in 3D this way will usually not do what you want, as rotating will change the "up" or "right" vector of the coordinate system attached to a certain object. For example, rotating about the up (-y for p5) vector, or the yaw angle, will rotate the right vector. The second rotation then needs to be about the rotated right vector (now pitch), so you can't just use rotateX/Y/Z as they are still in world space instead of object space. Note that I'm completely ignoring roll in this solution, but if you look at the boids from the front and top angles, it should be aligned with the velocities
var right = p5.Vector(this.vel.x, 0, this.vel.z);
rotate(atan(this.vel.y/ this.vel.x), right);
rotateY(atan2(-this.vel.z, this.vel.x));

How to get the position of object in Three.js relative to the camera to draw a trail?

I have an object (a pen) in my scene, which is rotating around its axis in the render loop.
groupPen.rotation.y += speed;
groupPen.rotation.x += speed;
and I have also a TrackballControls, which allows the user to rotate the whole scene.
What I now want is to get the "real" position of the pen (or its pick) and place small spheres to create a trail behind it.
This means I need to know where the camera is looking at and place the trail spheres behind the peak of the pen and exclude them from the animation and the TrackballControls.
What I tried is:
groupSphereTrail.lookAt(camera.position);
didn't work. Means no reaction at all.
camera.add(groupSphereTrail);
didn't work. groupSphereTrail is than not in the view area, couldn't make it visible - manipulating position.z didn't help.
Then I tried something like sending a tray with traycaster. The idea was to send a ray from the center of the camera through the peak of the pen and then draw the trail there. But then I still doesn't have the "real" position.
Another idea was to create a 2d vector of the current position of the pen peak and just draw an html element on top of the canvas:
var p = penPeak.position.clone();
var vector = p.project(camera);
vector.x = (vector.x + 1) / 2 * width;
vector.y = -(vector.y - 1) / 2 * height;
but this also doesn't work.
What could be another working solution?
Current progress:
https://zhaw.swissmade.xyz
(click on the cap of the pen to see the writing - this writing trail should stay at its place when you rotate the camera)
If i understood the question right, you want to show the trail as if it were draw on the screen itself (screen space)?
yourTrailParticle.position.project(camera)
camera.add(yourTrailParticle)
That's the basic idea, but it gets a bit tricky with PerspectiveCamera. You could set up a whole new THREE.Scene to hold the trail, and render it with a fixed size orthographic camera.
The point is .project() will give you a normalized screen space coordinate of a world space vector, and you need to keep it somehow in sync with that camera (since the screen is too). The perspective camera has distortion so you need to figure out the appropriate distance to map the coordinate to. With a separate scene, this may become easier.

Rotating around dodecahedron

I am trying to make a Three.js scene where I've got a dodecahedron. I want the camera to be zoomed in on one side of the dodecahedron and when a button is pressed I want it to zoom out, rotate until it is standing across another side and then zoom in again.
To make this clear:
If the camera would be fully zoomed in on side 1 and I pressed "5", I would want the camera to zoom out - showing the dodecahedron - then rotate towards 5 (or let the dodecahedron rotate side 5 facing the camera?) and zoom in again. It's important that the camera is always set parallel with the base of the pentagon it's facing, not the top or any other rotation.
I thought it would be smart to start off with just a cube, to not start too complicated. I added some tweens (when pressing G) to illustrate some basic movement, but that doesn't look too good anymore in the fiddle. jsfiddle
Because I feel like I should have a function that does all this movement and calculating for me I first tried to write down each position and rotation each side-view had from the cube so I might detect a pattern. I can see some pattern in the values I wrote down for the cube, but I do not know how to convert this into a working function, let alone for a dodecahedron. My noted values are
side1 (0, 0, 600) (0, 0, 0)
side2 (600, 0, 0) (0, pi/2, 0)
side3 (0, 0, -600) (0, pi, 0);
side4 (-600, 0, 0) (0, -pi/2, 0);
side5 (0, 600, 0) (-pi/2, 0, 0);
side6 (0, -600, 0) (pi/2, 0, 0);
I can see some sort of recurrence happening and some relationships, but I wouldn't see how to link them in a function. I think that would be a first step in getting to a function doing the same but for a more complex shape. Could anyone guide me into some direction I should be looking right now? Because I could of course work with a lot of if clauses, but that's not the correct way to go I feel.
To solve the problem, the first we would do is getting the center coordinate of each side of the dodecahedron.
as you know in three.js, a mesh consists of triangles, every triangle has three points, all the faces and vertices can be found in mesh.geometry.faces and mesh.geometry.vertices. in dodecahedron, each side has three faces and five vertices, and I use each face normal to divide them into 12 groups which have same normal and in the same plane. Then, we got 5 points of each side, calculate the average coordinate to get the center coordinate.
After getting coordinates we need to rotate, one way is rotating the dodecahedron and keep the camera, another way is keeping the dodecahedron and translate camera, in this case, I select the second one.
Now camera face to centerA, the green circle is the track of camera, because we need to keep the distance from camera to the dodecahedron center.
To get the target position, we just scale the centerB vector, cause the coordinate of the centerB is object system coordinate, we need to apply the matrix to change the coordinate to world system coordinate.
Then, we translate the camera in an animation, the camera needs to take an arc.
I use the parametric equation of a circle in 3D space to do that, about the equation you can see Parametric Equation of a Circle in 3D Space. With this formula, I got the parameter θ1 on camera position and θ2 on target position. I update the camera position with θ1 in every animation frame loop.
I add some comments on jsfiddle.(Still has some bugs, need to update.)
Here is another solution by keeping the camera and rotate the object.

Easeljs Using Bitmap for filling Rectangle

we are making a small Snake Browser game Using Easejs.
Now we want to use PNGs for the Snake Parts and not only a colour:
this.shape.graphics.beginFill("#e54d42");
this.shape.graphics.drawRect(this.x*this.grid.cell_width, this.y*this.grid.cell_height, this.grid.cell_width, this.grid.cell_height);
this.shape.graphics.endFill();
Does anyone know how to do it? Shall we use beginBitmapFill or how we have to do it?
Bitmap fill might do what you want, but you will need to consider the coordinates of the shape.
Here is a quick sample: http://jsfiddle.net/lannymcnie/ogy1qmxn/1/
shape.graphics.clear()
.beginBitmapFill(img)
.drawRect(0,0,800,600);
Note that my shape starts at [0,0]. If you start your shape at different coordinates, the bitmap will be cropped differently because it draws from [0,0] by default. Here is an example where the x/y coordinate of the bitmap is offset: http://jsfiddle.net/lannymcnie/ogy1qmxn/2/
You can fix this by either drawing at [0,0] and actually moving the shape, por using a matrix when you draw your shape.
var matrix = new createjs.Matrix2D();
matrix.translate(this.x*this.grid.cell_width, this.y*this.grid.cell_height);
shape.graphics.beginBitmapFill(img, "repeat", matrix);
Hope that helps!

How can I apply TrackballControls to a moving target?

I would like to apply the three.js script TrackballControls to a moving object in a way that preserves the ability to zoom and rotate the camera while the object moves through the scene. For example, I would like to be able to have the camera "follow" a moving planet, while the user retains the ability to zoom and rotate around the planet. Here is a basic jsfiddle:
http://jsfiddle.net/mareid/8egUM/3/
(The mouse control doesn't actually work on jsfiddle for some reason, but it does on my machine).
I would like to be able to attach the camera to the red sphere so that it moves along with it, but without losing the ability to zoom and rotate. I can get the camera to follow the sphere easily enough by adding lines like these to the render() function:
mouseControls.target = new THREE.Vector3(object.position);
camera.position.set(object.position.x,object.position.y,object.position.z+20);
But if I do that, the fixed camera.position line overrides the ability of TrackballControls to zoom, rotate, etc. Mathematically, I feel like it should be possible to shift the origin of all of the TrackballControls calculations to the centre of the red sphere, but I can't figure out how to do this. I've tried all sorts of vector additions of the position of the red sphere to the _this.target and _eye vectors in TrackballControls.js, to no avail.
Thanks for your help!
I'd recommend OrbitControls rather than TrackballControls. My answer here applies primarily to OrbitControls; the same principle might also work with TrackballControls (I have not looked at its code in a while).
If you look at how OrbitControls works you should notice it uses this.object for the camera, and this.target for where the camera is looking at, and it uses that vector (the difference between them) for some of its calculations. Movement is applied to both positions when panning; only the camera is moved when rotating. this.pan is set to shift the camera, but out of the box it only deals with a panning perpendicular to the this.object to this.target vector because of the way it sets the panning vector.
Anyway, if you subtract the vector from object.position to controls.target and set controls.pan to that vector, that should make it jump to that object:
Fixed example code:
Add a helper to OrbitControls.js which has access to its local pan variable:
function goTo( vector ) {
// Cloning given vector since it would be modified otherwise
pan.add( vector.clone().sub( this.target ) );
}
Your own code:
function animate() {
requestAnimationFrame(animate);
mouseControls.goTo( object.position ); // Call the new helper
mouseControls.update();
render();
}
You'll also probably want to set mouseControls.noPan to true.

Categories