btScalar TRACK::RayTestProcessor::addSingleResult( btCollisionWorld::LocalRayResult & rayResult, bool normalInWorldSpace) { // We only support static mesh collision shapes if (!(rayResult.m_collisionObject->getCollisionFlags() & btCollisionObject::CF_STATIC_OBJECT) && (rayResult.m_collisionObject->getCollisionShape()->getShapeType() != TRIANGLE_MESH_SHAPE_PROXYTYPE)) { return 1.0; } //std::cerr << rayResult.m_hitFraction << " "; // Road bezier patch ray test assert(m_ray); btVector3 rayFrom = m_ray->m_rayFrom; btVector3 rayTo = m_ray->m_rayTo; btScalar rayLen = m_ray->m_rayLen; btVector3 rayVec = rayTo - rayFrom; // patch space MATHVECTOR<float, 3> from(rayFrom[1], rayFrom[2], rayFrom[0]); MATHVECTOR<float, 3> to(rayTo[1], rayTo[2], rayTo[0]); MATHVECTOR<float, 3> dir(rayVec[1], rayVec[2], rayVec[0]); dir = dir / rayLen; int patchId = m_ray->m_patchid; const BEZIER * colBez = 0; MATHVECTOR<float, 3> colPoint; MATHVECTOR<float, 3> colNormal; for (std::list<ROADSTRIP>::const_iterator i = m_data.roads.begin(); i != m_data.roads.end(); ++i) { const BEZIER * bez(0); MATHVECTOR<float, 3> norm; MATHVECTOR<float, 3> point(to); if (i->Collide(from, dir, rayLen, patchId, point, bez, norm) && ((point - from).MagnitudeSquared() < (colPoint - from).MagnitudeSquared())) { colPoint = point; colNormal = norm; colBez = bez; } } if (colBez) { btVector3 hitPoint(colPoint[2], colPoint[0], colPoint[1]); btVector3 hitNormal(colNormal[2], colNormal[0], colNormal[1]); btScalar dist_p = hitNormal.dot(hitPoint); btScalar dist_a = hitNormal.dot(rayFrom); btScalar dist_b = hitNormal.dot(rayTo); btScalar fraction = (dist_a - dist_p) / (dist_a - dist_b); rayResult.m_hitFraction = fraction; rayResult.m_hitNormalLocal = hitNormal; m_ray->m_patch = colBez; m_ray->m_patchid = patchId; } //std::cerr << rayResult.m_hitFraction << " "; return m_ray->addSingleResult(rayResult, true); }
void pxBroadphase_Simple::TraceBox( const TraceBoxInput& input, TraceBoxOutput &output ) { if( input.start == input.end ) { output.hitPosition = input.start; output.hitNormal.SetZero(); output.hitFraction = 0.0f; return; } ShapePMTraceInput shapeTraceInput; { shapeTraceInput.start = input.start; shapeTraceInput.end = input.end; shapeTraceInput.size = input.size; shapeTraceInput.UpdateCachedData(); } F4 minHitFraction = 1.0f; UINT hitObjectId = INDEX_NONE; Vec3D hitNormal(0); for( UINT i=0; i < mHandles.Num(); i++ ) { pxSimpleBroadphaseProxy& proxy = mHandles[i]; if( !proxy.bounds.IntersectsBounds( shapeTraceInput.fullTraceBounds ) ) { continue; } ShapePMTraceOutput shapeTraceOutput; proxy.o->GetShape()->TraceBox( shapeTraceInput, shapeTraceOutput ); if( shapeTraceOutput.fraction < minHitFraction ) { minHitFraction = shapeTraceOutput.fraction; hitObjectId = i; hitNormal = shapeTraceOutput.normal; } } //DBGOUT("fraction = %f\n",minHitFraction); output.hitPosition = input.start + (input.end - input.start) * minHitFraction; output.hitNormal = hitNormal; output.hitFraction = minHitFraction; }
// return true if position ok and decal should be added // false, if position NOT ok and decal should NOT be added bool DecalPositionCalculator::calculateDecalPosition( game::GameScene *gameScene, const VC3 &origin, const VC3 &velocity, DECAL_POSITIONING positioning, int positionRandom, VC3 *resultPosition, QUAT *resultRotation) { assert(positioning != DecalPositionCalculator::DECAL_POSITIONING_INVALID); game::GameMap *gameMap = gameScene->getGameMap(); bool hitWall = false; *resultPosition = origin; *resultRotation = QUAT((-3.1415926f / 2.0f),0,0); // if velocity positioning... if (positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY) { VC3 velocityRandomized; if (positionRandom > 0) { velocityRandomized = velocity * GAME_TICKS_PER_SECOND; // TEMP //char buf[64]; //sprintf(buf, "%f,%f,%f", velocity.x, velocity.y, velocity.z); //Logger::getInstance()->error(buf); // TODO: add positionRandom to velocity _angle_... // (or maybe just do a quick hack and add it to xz-coordinates?) velocityRandomized.x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; velocityRandomized.z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; // add to y too? maybe should add downward only? // NOTE: biased downward velocityRandomized.y += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; velocityRandomized.y -= float(positionRandom) / 100.0f * 0.5f; } else { velocityRandomized = velocity; } velocityRandomized *= 2.0f; IStorm3D_Scene *scene = gameScene->getStormScene(); VC3 dir = velocityRandomized.GetNormalized(); VC3 rayOrigin = origin; float rayLen = velocityRandomized.GetLength(); Storm3D_CollisionInfo sceneColl; sceneColl.includeTerrainObjects = false; scene->RayTrace(rayOrigin, dir, rayLen, sceneColl, true); /* if (sceneColl.hit) { VC3 hitNormal = sceneColl.plane_normal; // make a "wall" hit if normal-y is not nearly 1 //if (fabs(hitNormal.y) < 0.8f) { hitWall = true; VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f); x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); assert(fabsf(x.GetDotWith(y)) < 0.0001f); assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f); MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, hitNormal.x); tm.Set(9, hitNormal.y); tm.Set(10, hitNormal.z); *resultRotation = tm.GetRotation(); } *resultPosition = sceneColl.position; } else { *resultPosition += velocityRandomized; } */ // New version { VC3 hitNormal(0, 1.f, 0); if(sceneColl.hit) { hitNormal = sceneColl.plane_normal; *resultPosition = sceneColl.position; } else { *resultPosition += velocityRandomized; VC2 p2(resultPosition->x, resultPosition->z); hitNormal = gameScene->getTerrain()->getFaceNormal(p2); } { if(sceneColl.hit) hitWall = true; /* VC3 y = dir; VC3 z = hitNormal; y -= hitNormal * y.GetDotWith(hitNormal); VC3 x = z.GetCrossWith(y); */ VC3 x = dir; x.y = 0.f; x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); VC3 z = hitNormal; MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, z.x); tm.Set(9, z.y); tm.Set(10, z.z); resultRotation->MakeFromAngles(0.f, 0.f, -PI*0.5f); *resultRotation = (*resultRotation) * tm.GetRotation(); /* VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f); x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); assert(fabsf(x.GetDotWith(y)) < 0.0001f); assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f); MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, hitNormal.x); tm.Set(9, hitNormal.y); tm.Set(10, hitNormal.z); *resultRotation = tm.GetRotation(); */ } } // TODO: some kind of terrain raytrace maybe...? // should collide to walls, etc. } // if downward positioning... if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD) { if (positionRandom > 0) { // TODO: add a random xz-offset to result position //*resultPosition += randomizedOffset; resultPosition->x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; resultPosition->z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; } /* // psd { VC2 p2(resultPosition->x, resultPosition->z); VC3 hitNormal = gameScene->getTerrain()->getFaceNormal(p2); VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f); x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); assert(fabsf(x.GetDotWith(y)) < 0.0001f); assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f); MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, hitNormal.x); tm.Set(9, hitNormal.y); tm.Set(10, hitNormal.z); *resultRotation = tm.GetRotation(); } */ VC3 fooNormal; calculateDecalRotation(gameScene, *resultPosition, *resultRotation, 0.f, fooNormal); } // now check that we're still inside map boundaries if (!gameMap->isWellInScaledBoundaries(resultPosition->x, resultPosition->z)) { // out of map. return false; } // then fix decal height to ground height if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD || positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY) { if (!hitWall) { resultPosition->y = gameMap->getScaledHeightAt(resultPosition->x, resultPosition->z); } } // check that not on top of metal grid area... if (game::MaterialManager::isMaterialUnderPosition(gameMap, *resultPosition, MATERIAL_METAL_GRATE)) { // on top of grid, no decal here. return false; } // TODO: check that not inside a wall, terrainobject, etc. // if so, return false return true; }