| 128 | } |
| 129 | |
| 130 | bool Picking3DApp::performPicking( vec3 *pickedPoint, vec3 *pickedNormal ) |
| 131 | { |
| 132 | // Generate a ray from the camera into our world. Note that we have to |
| 133 | // flip the vertical coordinate. |
| 134 | float u = mMousePos.x / (float) getWindowWidth(); |
| 135 | float v = mMousePos.y / (float) getWindowHeight(); |
| 136 | Ray ray = mCamera.generateRay( u, 1.0f - v, mCamera.getAspectRatio() ); |
| 137 | |
| 138 | // The coordinates of the bounding box are in object space, not world space, |
| 139 | // so if the model was translated, rotated or scaled, the bounding box would not |
| 140 | // reflect that. One solution would be to pass the transformation to the calcBoundingBox() function: |
| 141 | AxisAlignedBox worldBoundsExact = mTriMesh->calcBoundingBox( mTransform ); // slow |
| 142 | |
| 143 | // But if you already have an object space bounding box, it's much faster to |
| 144 | // approximate the world space bounding box like this: |
| 145 | AxisAlignedBox worldBoundsApprox = mObjectBounds.transformed( mTransform ); // fast |
| 146 | |
| 147 | // Draw the object space bounding box in yellow. It will not animate, |
| 148 | // because animation is done in world space. |
| 149 | drawCube( mObjectBounds, Color( 1, 1, 0 ) ); |
| 150 | |
| 151 | // Draw the exact bounding box in orange. |
| 152 | drawCube( worldBoundsExact, Color( 1, 0.5f, 0 ) ); |
| 153 | |
| 154 | // Draw the approximated bounding box in cyan. |
| 155 | drawCube( worldBoundsApprox, Color( 0, 1, 1 ) ); |
| 156 | |
| 157 | // Perform fast detection first - test against the bounding box itself. |
| 158 | if( ! worldBoundsExact.intersects( ray ) ) |
| 159 | return false; |
| 160 | |
| 161 | // Set initial distance to something far, far away. |
| 162 | float result = FLT_MAX; |
| 163 | |
| 164 | // Traverse triangle list and find the closest intersecting triangle. |
| 165 | const size_t polycount = mTriMesh->getNumTriangles(); |
| 166 | |
| 167 | float distance = 0.0f; |
| 168 | for( size_t i = 0; i < polycount; ++i ) { |
| 169 | // Get a single triangle from the mesh. |
| 170 | vec3 v0, v1, v2; |
| 171 | mTriMesh->getTriangleVertices( i, &v0, &v1, &v2 ); |
| 172 | |
| 173 | // Transform triangle to world space. |
| 174 | v0 = vec3( mTransform * vec4( v0, 1.0 ) ); |
| 175 | v1 = vec3( mTransform * vec4( v1, 1.0 ) ); |
| 176 | v2 = vec3( mTransform * vec4( v2, 1.0 ) ); |
| 177 | |
| 178 | // Test to see if the ray intersects this triangle. |
| 179 | if( ray.calcTriangleIntersection( v0, v1, v2, &distance ) ) { |
| 180 | // Keep the result if it's closer than any intersection we've had so far. |
| 181 | if( distance < result ) { |
| 182 | result = distance; |
| 183 | |
| 184 | // Assuming this is the closest triangle, we'll calculate our normal |
| 185 | // while we've got all the points handy. |
| 186 | *pickedNormal = normalize( cross( v1 - v0, v2 - v0 ) ); |
| 187 | } |
nothing calls this directly
no test coverage detected