Web3D programming Summary-A Preliminary Study on 3D Collision Detection and web3d Collision Detection
It is much more difficult to write a method by yourself than to analyze others' writing methods. Further understanding of the program is also difficult to analyze others' code.
I. A few first:
1. There are two sphere with a radius of 1 in the scenario. The Blue Line Segment points to the "Forward" of the sphere from the ball's heart"
2. After an object is selected, the texture image and transparency are changed, you can use "w, s, a, d, space, ctrl" to control the forward movement of an object relative to the object "front, back, left, right, top, bottom, the longer the button is, the faster the movement is. The longer the Green Line Segment is directed by the ball center to the object's moving direction. The faster the movement, the longer the part of the object's surface. Press "g" to stop all movements, click Cancel again.
3. You can select multiple objects to move at the same time.
4. After the collision between the two objects, the Movement stops. The red line segment points the ball to the first other object in the direction of motion.
Ii. Collision Detection principle:
THREE. Raycaster is used for collision detection, because Raycaster cannot detect the "inner surface" of an object, so reflection is used.
3. Program Implementation:
The complete program code can be found.
1. Draw a line segment indicating the motion of an object
1 this. line1; // self-owned line 2 this. line2; // Motion Direction Line 3 this. line3; // Collision Detection Line 4 var vector2 = this. v0.clone (). multiplyScalar (2 ). add (this. object3D. position); // calculate the end point of a line segment through a vector 5 this. line1 = this. createLine2 (this. object3D. position, vector2, 0x0000ff, this. planetGroup, "line1"); // orientation of the object in the horizontal direction 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 ");
The point vector2 is obtained by multiplying the vector v0 by 2 with this. object3D. position, and serves as the end point of line1. Note that if ". clone ()" after v0 is removed, v0 will also apply these changes and eventually become the same as vector2.
Line2 and line3 are initialized to a vertex.
The "line" object created here does not have the collision detection function, which is purely for viewing.
1 if (this. speedw! = 0 | this. speeda! = 0 | this. speedc! = 0) 2 {// if the object has a speed of 3 var vector4 = new THREE in a certain direction. 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 (vector4); 5 var vector5 = vector3.clone (). normalize (). multiplyScalar (this. size); 6 this. vector3 = vector3.clone (). add (vector5); 7 this. updateLine2 (this. line2.uuid, new THREE. vector3 (0, 0), this. vector3, 0x00 Ff00); // from the center of the object to the direction of the object movement, make a line segment that is proportional to the length and speed 8 // line2 is the child element of the planetGroup, it will and this. object3D. position is moved together. If you add this. object3D. position is repeated. 9 // this is also the "relative motion" 10 this in a sense. testCollision (); // collision detection 11 // after the detection is correct, the next frame location will be determined 12 if (this. flag_coll = 0) // no collision occurs 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. objec T3D. position. y + = this. speedc; // if you use the equal sign directly, the setting fails !! 17} 18 else19 {20 this. speeda = 0; 21 this. speedc = 0; 22 this. speedw = 0; 23 this. flag_coll = 0; // reset to status 24 currentlyPressedKeys [65] = false; 25 currentlyPressedKeys [68] = false; 26 currentlyPressedKeys [87] = false; 27 currentlyPressedKeys [83] = false; 28 currentlyPressedKeys [32] = false; 29 currentlyPressedKeys [17] = false; 30} 31}
Update the direction and length of line2 Based on the motion of the object. Vector3 is composed of the velocity components of an object in all directions. vector5 is responsible for adjusting vector3 to the length suitable for display. this. vector3 and vector3 are different objects, indicating the displacement of an endpoint of line2.
UpdateLine2 updates the line2 endpoint, showing a speed change. We can see that its two endpoint location parameters are (0, 0, 0) and a vector, instead of the ball center position in the preceding figure and the point obtained by adding a vector To The Ball center position ", this shows Three. the relativity between js parent and child objects. (In simple collision examples, subobjects are not required. Do I have to handle it myself ?)
This example is based on the solar system model in the previous article. The relationships between objects are as follows:
PlanetOrbitGroup and planetGroup are "Object3D" objects. These "objects" have no size, color attributes, only location and pose attributes (the default is the origin of the parent object ), "Mesh" and "Line" inherit from Object3D with geometry and material attributes.
PlanetOrbitGroup is a child of Scene located at the origin of the world coordinate system, and planetGroup is a child of planetOrbitGroup positioned forcibly at x = 3 of the world coordinate system, globeMesh and line2 are the child objects of the planetGroup, which are located at the origin of the planetGroup by default.
When planetOrbitGroup is moved (change this. object3D. position), the moving effect will be inherited by all its descendant objects, so we set a vertex of line2 to (0, 0) it will automatically inherit the moving effect of all its ancestor elements (this. object3D. position + (3, 0, 0 )).
2. Ray-based collision testing
1 var raycaster = new THREE. raycaster (this. planetGroup. position. clone (). add (this. object3D. position), this. vector3.clone (). normalize (); // emits a ray 2 raycaster from the center of the object to the actual direction of movement. far = this. object3D. inter_length; // Ray "length" 3 var intersects = raycaster. intersectObjects (scene. children, true );
Building the first ray is different from the previous line segment. Here the Ray is a mathematical Ray, and it is not an object and cannot be rendered. Because it is not a sub-object of any object, the endpoint position of raycaster takes the world coordinates rather than the relative coordinates. Note that it is different from the line segment endpoint at the same position.
Because we use a subobject, the second parameter of intersectObjects must be set to true to forcibly check each subobject, otherwise, raycaster will only check the objects at the first parameter level and ignore globeMesh.
1 if (intersects. length> 0) {2 var flag_safe = 0; // you can save this variable. 3. Run the following loop description, no other objects in the collision zone 4 for (var I = 0; I <intersects. length; I ++) 5 {6 // specifies that the collision object must be visible, have a surface, and be not the original object, must be within the range of collision detection (In fact, because of the uncertainty of the result of Ray passing through the Child object) 7 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. clone (). sub (this. planetGroup. position. clone (). add (this. object3D. position), 0xff0000); // Collision Detection Line
As mentioned above, raycaster cannot detect the inner surface of an object. However, when detecting a child object, this proposition becomes uncertain, therefore, we need to add more judgment conditions (whether this is self-defeating itself ...)
1 var raycaster2 = new THREE. raycaster (intersected. point, this. vector3.clone (). negate (). normalize (); // returns 2 raycaster2.far = this after the ray and the object intersect. object3D. inter_length; 3 var intersects2 = raycaster2.intersectObjects (scene. children, true); 4 // Since another object has been encountered, it must be reflected back to the original object to ensure no collision (the collision boundary value is excluded when the object is reflected back to the other side) 5 if (intersects2.length> 0) 6 {7 flag_safe = 1; 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) // returns the original object 13 {14 flag_safe = 0; // no collision 15} 16 break; 17} 18} 19 if (flag_safe = 1) 20 {21 this. flag_coll = 1; 22} 23}
The logic here is not elegant enough. Please adjust it next time.
Iv. Optimization Direction:
1. The current "3D Collision Detection" implements collision detection in the simplest case, but the algorithm still has great limitations. For example, in this case, collision Detection rays can never pass through other objects:
The solution I came up with is:
Extend raycaster to multiple parallel rays in the detection direction to detect the edge collision of an object. This requires the knowledge of linear algebra. You need to review it.
2. If no translucent image is set, objects may overlap but the collision is not judged. I suspect that Three is used for "first collision and then detection. js considers that the elements of the overlapping part do not need to be drawn to automatically discard it, resulting in no overlap of the ray detection part.
5. Expansion:
Yesterday, we found that the Three. js example of Lee Stemkoski, an American predecessor, shows another collision detection method, which has advantages and disadvantages compared with my method.
Demo address: http://stemkoski.github.io/Three.js/Collision-Detection.html
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 }
This method performs a collision detection Ray 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 smaller than the distance from the center of the object to the vertex, it is considered that a collision occurs.