Writing your own method is much more difficult than analyzing someone else’s method, and as a result, further understanding of the program is much harder to achieve by analyzing someone else’s code.

First, a few renderings:

1. There are two spheres with radius 1 in the scene, and the blue line segment points to the “positive direction” of the sphere from the center of the sphere.

2, the objects to be selected after change texture images and transparency, you can use the “w, s, a, d, Spaces, CTRL” control object relative to the positive “before and after, left, right, up, down,” move, the faster the longer you hold down the button’s movement speed, green line by pointing in the direction the object movement, its the faster the longer the part on the surface of the object, Press “G” to stop all movement and click the object again to deselect it.

3. Multiple objects can be selected to move at the same time.

4. After the two objects collide, they stop moving, and the red line segment points from the center of the object to the first other object encountered in the direction of motion

Ii. Collision detection Principle:

Collision detection is carried out by borrowing from THREE.Raycaster, because Raycaster cannot detect the “inner surface” of the object, the reflection method is used.

Three, program implementation:

Complete the program code can be downloaded at http://files.cnblogs.com/files/ljzc002/App2.zip to view, including detailed annotations, explain a few of the more important sections here.

1. Draw a line segment indicating the motion of the object

1 this.line1; // this. Line2; // this. Line3; Var vector2=this.v0.clone().multiplyScalar(2).add(this.object3d.position); / / by vector to calculate the end of the line segment point 5 enclosing, line1 = this. CreateLine2 (this) object3D) position, vector2, 0 x0000ff, enclosing planetGroup, ", line1 "); // The object is horizontal towards line 6 this.line2=this.createLine2(this.object3D.position,this.object3D.position,0x00ff00,this.planetGroup,"line2"); 7 this.line3=this.createLine2(this.object3D.position,this.object3D.position,0xff0000,this.planetGroup,"line3");Copy the code

The point vector2 is obtained by multiplying the vector v0 by 2 plus this.object3d. position as the end point of line1. Note that if the “.clone() “after v0 is removed, v0 itself applies these changes and becomes the same as Vector2.

Line2 and line3 are initialized to a point.

The “line” object created here has no collision detection and is purely visual.

1 if (this.speedw ! = 0 || this.speeda ! = 0||this.speedc! Var vector4=new THREE.Vector3(0,this.speedc*1000,0); 4 var vector3=(this.v1.clone().multiplyScalar(this.speeda*1000)).add(this.v0.clone().multiplyScalar(this.speedw*1000)).add(vec tor4); 5 var vector5=vector3.clone().normalize().multiplyScalar(this.size); 6 this.vector3=vector3.clone().add(vector5); 7 this. UpdateLine2 (this) line2) uuid, the new THREE, Vector3 (0, 0), enclosing Vector3, 0 x00ff00); //line2 is a child of the planetGroup, which itself will move with this.object3d. position. TestCollision (); this.object3d. position (); // If no error is found, If (this.flag_coll==0) // No collision 13 {14 this.object3D.position.add(this.v0.clone().multiplyScalar(this.speedw)); 15 this.object3D.position.add(this.v1.clone().multiplyScalar(this.speeda)); 16 this.object3D.position.y += this.speedc; // Use equal sign directly to set failure!! 17 } 18 else 19 { 20 this.speeda=0; 21 this.speedc=0; 22 this.speedw=0; 23 this.flag_coll=0; CurrentlyPressedKeys [65]=false; 25 currentlyPressedKeys[68]=false; 26 currentlyPressedKeys[87]=false; 27 currentlyPressedKeys[83]=false; 28 currentlyPressedKeys[32]=false; 29 currentlyPressedKeys[17]=false; 30}} 31Copy the code

Update the direction and length of line2 based on the object’s motion. Here, vector3 is composed of the velocity components of the object in each direction, and Vector5 is responsible for adjusting vector3 to the length suitable for display. This. vector3 and Vector3 are different objects, representing the displacement of an endpoint of line2.

UpdateLine2 updates the endpoint of line2, showing a change in speed. We can see that its two endpoint position parameters are (0,0,0) and a vector instead of the spherical center position and “the point obtained by spherical center position plus vector” in the previous figure, which reflects the relativity between Three. Js father-son objects. (The simple collision example does not require child objects; am I asking for trouble?)

This example continues from the solar system model in the previous article. The relationship between objects is shown as follows:

PlanetOrbitGroup and planetGroup are “Object3D” objects, which have no size or color attributes but only position and attitude attributes (default at the origin of the parent object). Object3D has multiple inheritance of “Mesh” and “Line”, which have vertex geometry and material properties.

The planetOrbitGroup is the subobject of the Scene at the origin of the world coordinate system, the planetOrbitGroup is the subobject of the planetOrbitGroup at the world coordinate system x equals 3, GlobeMesh and line2 are children of the planetGroup that default to the origin of the planetGroup.

When the planetOrbitGroup moves (changing this.object3d. position), the move is inherited by all of its descendants, So setting a vertex on line2 to (0,0,0) automatically inherits all of its ancestors’ movement effects (this.object3d.position + (3,0,0)).

2. Ray-based crash testing

1 var raycaster= new THREE.Raycaster(this.planetGroup.position.clone().add(this.object3D.position),this.vector3.clone().normalize()); 2 raycaster. Far = this.object3d.inter_length; / / ray "length" 3 var intersects = raycaster. IntersectObjects (scene. Children, true);Copy the code

Create the first ray. Unlike the previous line segment, the ray here is a ray in the mathematical sense, it is not an object and cannot be rendered. Because it is not a child of anything, raycaster’s endpoints are placed in world coordinates rather than relative coordinates. Note the difference between the endpoints of the previous segment in the same position.

Since we are using sub-objects, the second parameter of intersectObjects must be set to true to force the inspection of each sub-object, otherwise RayCaster will only inspect objects in the layer of the first parameter and ignore the globeMesh.

1 if ( intersects.length > 0 ) { 2 var flag_safe=0; For (var I =0; var I =0; var I =0; i<intersects.length; // Specifies that the colliding object must be visible, must have a face, must not be the original object, If (intersects[I].object.visible && Intersects [I].face&&(this.object3d.inter_group! =intersects[i].object.inter_group)&&intersects[i].distance<this.object3D.inter_length) { 8 9 var intersected = intersects[i]; 10 this.updateLine2(this.line3.uuid,new THREE. Vector3 (0, 0), intersected point. The clone (), sub (this) planetGroup) position. The clone (). The add (this) object3D) position)), 0 xff00 00); // Collision detection lineCopy the code

Raycaster cannot detect the inner surfaces of objects mentioned earlier, but when it comes to sub-object detection, this proposition becomes uncertain, so there is more to it than that.

1 var raycaster2= new THREE.Raycaster(intersected.point,this.vector3.clone().negate().normalize()); 2 rayCaster2.far = this.object3d.inter_length; 3 raycaster2.far= this.object3d.inter_length; 3 var intersects2 = raycaster2.intersectObjects(scene.children,true); 5 if (intersects2.length > 0) 6 {7 flag_safe=1; if (intersects2.length > 0) 5 {7 intersects2. 8 for(var j=0; j<intersects2.length; j++) 9 { 10 if (intersects2[j].object.visible && intersects2[j].face&&(intersected.object.inter_group! =intersects2[j].object.inter_group)&&intersects2[j].distance<this.object3D.inter_length) 11 { 12 If (intersects2[j].object.inter_group== this.object3d.inter_group)// Inter_group attribute same, return original object 13 {14 flag_safe=0; // No collision occurred 15} 16 break; 17 } 18 } 19 if(flag_safe==1) 20 { 21 this.flag_coll = 1; 23 22}}Copy the code

The logic here is not elegant enough, I will adjust it next time

Iv. Optimization Direction:

1. The current “3D collision detection” achieves collision detection in the simplest case, but the algorithm still has great limitations. For example, in this case, the collision detection ray can never pass through other objects:

The solution I’ve come up with is this:

Raycaster is extended to detect multiple parallel rays in the direction of the object to detect edge collision, which requires some knowledge of linear algebra, need a review.

2. When running without setting translucency, object overlap may occur but collision is not judged. I suspect that it is because I adopt the method of “collision first and detection later”.

Five, expansion:

Yesterday, I found that the example of Three. Js by American predecessor Lee Stemkoski shows another collision detection method, which has advantages and disadvantages compared to my method

Demo address: stemkoski. Making. IO/Three js/Co…

Core code:

1 for (var vertexIndex = 0; vertexIndex < MovingCube.geometry.vertices.length; vertexIndex++) 2 { 3 var localVertex = MovingCube.geometry.vertices[vertexIndex].clone(); 4 var globalVertex = localVertex.applyMatrix4( MovingCube.matrix ); 5 var directionVector = globalVertex.sub( MovingCube.position ); 6 7 var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() ); 8 var collisionResults = ray.intersectObjects( collidableMeshList ); 9 if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() ) 10 appendText(" Hit "); 11}Copy the code

In this method, a collision detection ray is sent from the center of the object to each vertex of the object. If the distance between the collision point of the first object and the center of the object is less than the distance between the center of the object and the vertex, the collision is considered to have occurred.