00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "SO3RayCast.h"
00029 #include "../SO3Material/SO3Material.h"
00030 #include "../SO3SceneGraph/SO3Scene.h"
00031 #include "../SO3SceneGraph/SO3Camera.h"
00032
00033 namespace SO3
00034 {
00035
00040 SRaycastResult::SRaycastResult()
00041 {
00042 scene = 0;
00043 sceneName = "";
00044 viewport = 0;
00045 entity = 0;
00046 entityName = "";
00047 material = 0;
00048
00049 closestDistance = -1.0f;
00050 point = Ogre::Vector3::ZERO;
00051 indexFace = 0;
00052 v1 = Ogre::Vector3::ZERO;
00053 v2 = Ogre::Vector3::ZERO;
00054 v3 = Ogre::Vector3::ZERO;
00055 pReal1 = Ogre::Vector2::ZERO;
00056 pReal2 = Ogre::Vector2::ZERO;
00057 pReal3 = Ogre::Vector2::ZERO;
00058 uvResult = Ogre::Vector2(-1.0f, -1.0f);
00059 }
00060
00061 SRaycastResult::SRaycastResult(const SRaycastResult& copiedRaycast)
00062 {
00063 scene = copiedRaycast.scene;
00064 sceneName = copiedRaycast.sceneName;
00065 viewport = copiedRaycast.viewport;
00066 entity = copiedRaycast.entity;
00067 entityName = copiedRaycast.entityName;
00068 material = copiedRaycast.material;
00069
00070 closestDistance = copiedRaycast.closestDistance;
00071 point = copiedRaycast.point;
00072 indexFace = copiedRaycast.indexFace;
00073 v1 = copiedRaycast.v1;
00074 v2 = copiedRaycast.v2;
00075 v3 = copiedRaycast.v3;
00076 pReal1 = copiedRaycast.pReal1;
00077 pReal2 = copiedRaycast.pReal2;
00078 pReal3 = copiedRaycast.pReal3;
00079 uvResult = copiedRaycast.uvResult;
00080 }
00081
00082 SRaycast::SRaycast()
00083 {
00084
00085 }
00086
00087 SRaycastResult SRaycast::Cast(SCamera* camera, float relativePosX, float relativePosY, Ogre::SubEntity* subEntity, bool getUvCoordonate)
00088 {
00089
00090 SRaycastResult results;
00091
00092
00093 #if OGRE_VERSION < ((1 << 16) | (7 << 8) | 0)
00094 Ogre::Any bindedCustomEntity = subEntity->getUserAny();
00095 #else
00096 Ogre::Any bindedCustomEntity = subEntity->getUserObjectBindings().getUserAny("SEntity");
00097 #endif
00098
00099 assert(!bindedCustomEntity.isEmpty());
00100 results.entity = Ogre::any_cast<SEntity*> (bindedCustomEntity);
00101 results.entityName = results.entity->GetName();
00102 results.scene = results.entity->GetParentScene();
00103 results.sceneName = results.scene->GetName();
00104 results.viewport = camera->getCurrentViewPort();
00105 results.material = results.scene->GetMaterial(results.entity->GetGroupName(), subEntity->getMaterial()->getName());
00106
00107
00108 if(!getUvCoordonate && results.material)
00109 if(results.material->GetAssociatedWidget() != 0)
00110 getUvCoordonate = true;
00111
00112
00113 Ogre::Ray ray = camera->GetOgreCameraPointer()->getCameraToViewportRay(abs(relativePosX), abs(relativePosY));
00114
00115
00116 float closest_distance = -1.0f;
00117 size_t vertex_count;
00118 size_t index_count;
00119 Ogre::Vector3* vertices;
00120 unsigned long* indices;
00121 Ogre::SubMesh* submesh = subEntity->getSubMesh();
00122 GetSubEntityInformation(subEntity, vertex_count, vertices, index_count, indices);
00123
00124 Ogre::RenderOperation tmpRenderOperation;
00125 submesh->_getRenderOperation(tmpRenderOperation);
00126 if(tmpRenderOperation.operationType == Ogre::RenderOperation::OT_TRIANGLE_LIST)
00127 {
00128 int closestVerticeIndex = 0;
00129 for (int j = 0; j < static_cast<int>(index_count); j += 3)
00130 {
00131 std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, vertices[indices[j]], vertices[indices[j+1]], vertices[indices[j+2]], true, false);
00132 if(hit.first)
00133 {
00134 if((closest_distance < 0.0f) || (hit.second < closest_distance))
00135 {
00136
00137 closest_distance = hit.second;
00138 closestVerticeIndex = j;
00139
00140 results.indexFace = j/3;
00141 results.v1 = vertices[indices[j]];
00142 results.v2 = vertices[indices[j+1]];
00143 results.v3 = vertices[indices[j+2]];
00144 results.point = ray.getPoint(hit.second);
00145 }
00146 }
00147 }
00148 results.closestDistance = closest_distance;
00149
00150 if (getUvCoordonate)
00151 {
00152 Ogre::VertexData* vertex_data = submesh->useSharedVertices ? submesh->parent->sharedVertexData : submesh->vertexData;
00153 const Ogre::VertexElement* vertex_element1 = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES);
00154 if(vertex_data->vertexDeclaration->getElementCount()>2)
00155 {
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 float* pReal1;
00174 float* pReal2;
00175 float* pReal3;
00176
00177 Ogre::HardwareVertexBufferSharedPtr vbuf1 = vertex_data->vertexBufferBinding->getBuffer(vertex_element1->getSource());
00178 unsigned char* vertex1 = static_cast<unsigned char*>(vbuf1->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
00179 vertex1 += indices[closestVerticeIndex]*vbuf1->getVertexSize();
00180 vertex_element1->baseVertexPointerToElement(vertex1, &pReal1);
00181 vbuf1->unlock();
00182
00183 const Ogre::VertexElement* vertex_element2 = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES);
00184 Ogre::HardwareVertexBufferSharedPtr vbuf2 = vertex_data->vertexBufferBinding->getBuffer(vertex_element2->getSource());
00185 unsigned char* vertex2 = static_cast<unsigned char*>(vbuf2->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
00186 vertex2 += indices[closestVerticeIndex+1]*vbuf2->getVertexSize();
00187 vertex_element2->baseVertexPointerToElement(vertex2, &pReal2);
00188 vbuf2->unlock();
00189
00190 const Ogre::VertexElement* vertex_element3 = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES);
00191 Ogre::HardwareVertexBufferSharedPtr vbuf3 = vertex_data->vertexBufferBinding->getBuffer(vertex_element3->getSource());
00192 unsigned char* vertex3 = static_cast<unsigned char*>(vbuf3->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
00193 vertex3 += indices[closestVerticeIndex+2]*vbuf3->getVertexSize();
00194 vertex_element3->baseVertexPointerToElement(vertex3, &pReal3);
00195 vbuf3->unlock();
00196
00197 results.pReal1.x = pReal1[0];
00198 results.pReal1.y = pReal1[1];
00199 results.pReal2.x = pReal2[0];
00200 results.pReal2.y = pReal2[1];
00201 results.pReal3.x = pReal3[0];
00202 results.pReal3.y = pReal3[1];
00203
00204 Ogre::Vector3 B = GetBarycentricCoordinates(results.v1, results.v2, results.v3, results.point);
00205 Ogre::Vector2 T = results.pReal1*B.x + results.pReal2*B.y + results.pReal3*B.z;
00206
00207 results.uvResult.x = abs(T.x) - abs((int)T.x);
00208 results.uvResult.y = abs(T.y) - abs((int)T.y);
00209
00210 if(T.x<0)
00211 results.uvResult.x = 1 - results.uvResult.x;
00212 if(T.y<0)
00213 results.uvResult.y = 1 - results.uvResult.y;
00214 }
00215 }
00216 }
00217 delete[] vertices;
00218 delete[] indices;
00219
00220 return results;
00221 }
00222
00223 void SRaycast::GetSubEntityInformation(Ogre::SubEntity* subEntity, size_t &vertex_count, Ogre::Vector3* &vertices, size_t &index_count, unsigned long* &indices)
00224 {
00225 size_t current_offset = 0;
00226 size_t shared_offset = 0;
00227 size_t next_offset = 0;
00228 size_t index_offset = 0;
00229
00230 Ogre::SubMesh* submesh = subEntity->getSubMesh();
00231 Ogre::Entity* parentEntity = subEntity->getParent();
00232 bool useSoftwareBlendingVertices = parentEntity->hasSkeleton();
00233 bool useSoftwareMorphingVertices = parentEntity->hasVertexAnimation();
00234
00235 Ogre::SceneNode* attachedNode = parentEntity->getParentSceneNode();
00236 assert(attachedNode != 0);
00237 Ogre::Vector3 position = attachedNode->_getDerivedPosition();
00238 Ogre::Quaternion orient = attachedNode->_getDerivedOrientation();
00239 Ogre::Vector3 scale = attachedNode->_getDerivedScale();
00240
00241
00242 if(submesh->useSharedVertices)
00243 vertex_count = submesh->parent->sharedVertexData->vertexCount;
00244 else
00245 vertex_count = submesh->vertexData->vertexCount;
00246
00247
00248 index_count = submesh->indexData->indexCount;
00249
00250
00251 vertices = new Ogre::Vector3[vertex_count];
00252 indices = new unsigned long[index_count];
00253
00254
00255 Ogre::VertexData* vertex_data;
00256 if(useSoftwareBlendingVertices && parentEntity->_isAnimated())
00257 vertex_data = submesh->useSharedVertices ? parentEntity->_getSkelAnimVertexData() : subEntity->_getSkelAnimVertexData();
00258 else if(!useSoftwareBlendingVertices && useSoftwareMorphingVertices && parentEntity->_isAnimated() && parentEntity->getMesh()->getPoseCount()==0)
00259 vertex_data = submesh->useSharedVertices ? parentEntity->_getSoftwareVertexAnimVertexData() : subEntity->_getSoftwareVertexAnimVertexData();
00260 else
00261 vertex_data = submesh->useSharedVertices ? submesh->parent->sharedVertexData : submesh->vertexData;
00262
00263
00264 if((!submesh->useSharedVertices)||(submesh->useSharedVertices))
00265 {
00266 if(submesh->useSharedVertices)
00267 shared_offset = current_offset;
00268
00269 const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
00270 Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
00271 unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
00272
00273 float* pReal;
00274 for(size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
00275 {
00276 posElem->baseVertexPointerToElement(vertex, &pReal);
00277 Ogre::Vector3 pt(pReal[0], pReal[1], pReal[2]);
00278 vertices[current_offset + j] = (orient * (pt * scale)) + position;
00279 }
00280
00281 vbuf->unlock();
00282 next_offset += vertex_data->vertexCount;
00283 }
00284
00285
00286 Ogre::IndexData* index_data = submesh->indexData;
00287 size_t numTris = index_data->indexCount / 3;
00288 Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
00289 bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
00290 unsigned long* pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
00291 unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong);
00292 size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset;
00293
00294 if(use32bitindexes)
00295 for (size_t k = 0; k < numTris*3; ++k)
00296 indices[index_offset++] = pLong[k] + static_cast<unsigned long>(offset);
00297 else
00298 for (size_t k = 0; k < numTris*3; ++k)
00299 indices[index_offset++] = static_cast<unsigned long>(pShort[k]) + static_cast<unsigned long>(offset);
00300
00301 ibuf->unlock();
00302 current_offset = next_offset;
00303 }
00304
00305 Ogre::Vector3 SRaycast::GetBarycentricCoordinates(const Ogre::Vector3& P1, const Ogre::Vector3& P2, const Ogre::Vector3& P3, const Ogre::Vector3& P)
00306 {
00307 Ogre::Vector3 coordinates(0.0);
00308 Ogre::Real denom = (-P1.x * P3.y - P2.x * P1.y + P2.x * P3.y + P1.y * P3.x + P2.y * P1.x - P2.y * P3.x);
00309 if(fabs(denom) >= 1e-6)
00310 {
00311 coordinates.x = (P2.x * P3.y - P2.y * P3.x - P.x * P3.y + P3.x * P.y - P2.x * P.y + P2.y * P.x) / denom;
00312 coordinates.y = -(-P1.x * P.y + P1.x * P3.y + P1.y * P.x - P.x * P3.y + P3.x * P.y - P1.y * P3.x) / denom;
00313 }
00314 else
00315 {
00316 denom = (-P1.x * P3.z - P2.x * P1.z + P2.x * P3.z + P1.z * P3.x + P2.z * P1.x - P2.z * P3.x);
00317 if(fabs(denom) >= 1e-6)
00318 {
00319 coordinates.x = (P2.x * P3.z - P2.z * P3.x - P.x * P3.z + P3.x * P.z - P2.x * P.z + P2.z * P.x) / denom;
00320 coordinates.y = -(-P1.x * P.z + P1.x * P3.z + P1.z * P.x - P.x * P3.z + P3.x * P.z - P1.z * P3.x) / denom;
00321 }
00322 else
00323 {
00324 denom = (-P1.y * P3.z - P2.y * P1.z + P2.y * P3.z + P1.z * P3.y + P2.z * P1.y - P2.z * P3.y);
00325 if(fabs(denom) >= 1e-6)
00326 {
00327 coordinates.x = (P2.y * P3.z - P2.z * P3.y - P.y * P3.z + P3.y * P.z - P2.y * P.z + P2.z * P.y) / denom;
00328 coordinates.y = -(-P1.y * P.z + P1.y * P3.z + P1.z * P.y - P.y * P3.z + P3.y * P.z - P1.z * P3.y) / denom;
00329 }
00330 }
00331 }
00332 coordinates.z = 1 - coordinates.x - coordinates.y;
00333 return coordinates;
00334 }
00335
00336 }