OPC_Picking.cpp
Go to the documentation of this file.
00001 
00002 /*
00003  *      OPCODE - Optimized Collision Detection
00004  *      Copyright (C) 2001 Pierre Terdiman
00005  *      Homepage: http://www.codercorner.com/Opcode.htm
00006  */
00008 
00010 
00016 
00017 
00019 // Precompiled Header
00020 #include "Stdafx.h"
00021 
00022 using namespace Opcode;
00023 
00024 #ifdef OPC_RAYHIT_CALLBACK
00025 
00026 /*
00027         Possible RayCollider usages:
00028         - boolean query (shadow feeler)
00029         - closest hit
00030         - all hits
00031         - number of intersection (boolean)
00032 
00033 */
00034 
00035 bool Opcode::SetupAllHits(RayCollider& collider, CollisionFaces& contacts)
00036 {
00037         struct Local
00038         {
00039                 static void AllContacts(const CollisionFace& hit, void* user_data)
00040                 {
00041                         CollisionFaces* CF = (CollisionFaces*)user_data;
00042                         CF->AddFace(hit);
00043                 }
00044         };
00045 
00046         collider.SetFirstContact(false);
00047         collider.SetHitCallback(Local::AllContacts);
00048         collider.SetUserData(&contacts);
00049         return true;
00050 }
00051 
00052 bool Opcode::SetupClosestHit(RayCollider& collider, CollisionFace& closest_contact)
00053 {
00054         struct Local
00055         {
00056                 static void ClosestContact(const CollisionFace& hit, void* user_data)
00057                 {
00058                         CollisionFace* CF = (CollisionFace*)user_data;
00059                         if(hit.mDistance<CF->mDistance) *CF = hit;
00060                 }
00061         };
00062 
00063         collider.SetFirstContact(false);
00064         collider.SetHitCallback(Local::ClosestContact);
00065         collider.SetUserData(&closest_contact);
00066         closest_contact.mDistance = MAX_FLOAT;
00067         return true;
00068 }
00069 
00070 bool Opcode::SetupShadowFeeler(RayCollider& collider)
00071 {
00072         collider.SetFirstContact(true);
00073         collider.SetHitCallback(null);
00074         return true;
00075 }
00076 
00077 bool Opcode::SetupInOutTest(RayCollider& collider)
00078 {
00079         collider.SetFirstContact(false);
00080         collider.SetHitCallback(null);
00081         // Results with collider.GetNbIntersections()
00082         return true;
00083 }
00084 
00085 bool Opcode::Picking(
00086 CollisionFace& picked_face,
00087 const Ray& world_ray, const Model& model, const Matrix4x4* world,
00088 float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data)
00089 {
00090         struct Local
00091         {
00092                 struct CullData
00093                 {
00094                         CollisionFace*                  Closest;
00095                         float                                   MinLimit;
00096                         CullModeCallback                Callback;
00097                         void*                                   UserData;
00098                         Point                                   ViewPoint;
00099                         const MeshInterface*    IMesh;
00100                 };
00101 
00102                 // Called for each stabbed face
00103                 static void RenderCullingCallback(const CollisionFace& hit, void* user_data)
00104                 {
00105                         CullData* Data = (CullData*)user_data;
00106 
00107                         // Discard face if we already have a closer hit
00108                         if(hit.mDistance>=Data->Closest->mDistance)     return;
00109 
00110                         // Discard face if hit point is smaller than min limit. This mainly happens when the face is in front
00111                         // of the near clip plane (or straddles it). If we keep the face nonetheless, the user can select an
00112                         // object that he may not even be able to see, which is very annoying.
00113                         if(hit.mDistance<=Data->MinLimit)       return;
00114 
00115                         // This is the index of currently stabbed triangle.
00116                         udword StabbedFaceIndex = hit.mFaceID;
00117 
00118                         // We may keep it or not, depending on backface culling
00119                         bool KeepIt = true;
00120 
00121                         // Catch *render* cull mode for this face
00122                         CullMode CM = (Data->Callback)(StabbedFaceIndex, Data->UserData);
00123 
00124                         if(CM!=CULLMODE_NONE)   // Don't even compute culling for double-sided triangles
00125                         {
00126                                 // Compute backface culling for current face
00127 
00128                                 VertexPointers VP;
00129                                 Data->IMesh->GetTriangle(VP, StabbedFaceIndex);
00130                                 if(VP.BackfaceCulling(Data->ViewPoint))
00131                                 {
00132                                         if(CM==CULLMODE_CW)             KeepIt = false;
00133                                 }
00134                                 else
00135                                 {
00136                                         if(CM==CULLMODE_CCW)    KeepIt = false;
00137                                 }
00138                         }
00139 
00140                         if(KeepIt)      *Data->Closest = hit;
00141                 }
00142         };
00143 
00144         RayCollider RC;
00145         RC.SetMaxDist(max_dist);
00146         RC.SetTemporalCoherence(false);
00147         RC.SetCulling(false);           // We need all faces since some of them can be double-sided
00148         RC.SetFirstContact(false);
00149         RC.SetHitCallback(Local::RenderCullingCallback);
00150 
00151         picked_face.mFaceID             = INVALID_ID;
00152         picked_face.mDistance   = MAX_FLOAT;
00153         picked_face.mU                  = 0.0f;
00154         picked_face.mV                  = 0.0f;
00155 
00156         Local::CullData Data;
00157         Data.Closest                    = &picked_face;
00158         Data.MinLimit                   = min_dist;
00159         Data.Callback                   = callback;
00160         Data.UserData                   = user_data;
00161         Data.ViewPoint                  = view_point;
00162         Data.IMesh                              = model.GetMeshInterface();
00163 
00164         if(world)
00165         {
00166                 // Get matrices
00167                 Matrix4x4 InvWorld;
00168                 InvertPRMatrix(InvWorld, *world);
00169 
00170                 // Compute camera position in mesh space
00171                 Data.ViewPoint *= InvWorld;
00172         }
00173 
00174         RC.SetUserData(&Data);
00175         if(RC.Collide(world_ray, model, world))
00176         {
00177                 return picked_face.mFaceID!=INVALID_ID;
00178         }
00179         return false;
00180 }
00181 
00182 #endif


openhrp3
Author(s): AIST, General Robotix Inc., Nakamura Lab of Dept. of Mechano Informatics at University of Tokyo
autogenerated on Sun Apr 2 2017 03:43:55