Physics::CRay* CPhysicsServer::CreateRay(const vector3& Origin, const vector3& Dir) const { CRay* R = CRay::Create(); R->SetOrigin(Origin); R->SetDirection(Dir); return R; }
/* It all boils down to this. Here is the portion of code that determines collision between a plane and a ray. Lets rexamin the equations of plane and ray: Plane: p * n = -d Where p == point on plane, n == unit normal to plane, d == signed distance to plane Ray: O + tD Where O == origin of ray, t == "time" traveled along ray, D == Direction vector of the ray If we replace 'p' with the equation of ray we get: (O + tD) * n = -d And with a little algerbra for a final answer we get: t = -((n * O) + d) / (n * D) If we treat our ray like a parametric line, we know that when 't' is between 0.0f and 1.0f, then there is a collision with the ray, otherwise, the ray does not collide */ bool CPlane::intersect(const CRay &ray) { // Calculate the denominator // **NOTE** Our ray's direction vector is always normalized, so we must // multiply by the ray's length so we correctly check collision against // the desired portion of the ray float denominator = mNormal * ray.getDir() * ray.getLength(); // If the denominator is greater than or equal to 0.0f, the ray intersects on the backside of // the plane or is collinear to the plane // **NOTE** The "backside" of a plane is defined to be the side of the plane the // plane's normal points away from if(denominator >= 0.0f) return false; // Calculate the numerator float numerator = -((mNormal * ray.getOrigin()) + mDist); // Calculate 't' float t = numerator / denominator; // This return statement reads like: // // if(t < 0.0f || t > 1.0f) // return false; // else // return true; // // We use this shorter notation because it gets rid of the if statement. Branching // is usually a speed hit on x86 architecture which Windows 2000 and XP run on. return (t >= 0.0f && t <= 1.0f); }
bool CDynamics3DEntity::CheckIntersectionWithRay(Real& f_t_on_ray, const CRay& c_ray) const { /* Create an ODE ray from ARGoS ray */ Real fRayLength = c_ray.GetLength(); dGeomID tRay = dCreateRay(m_cEngine.GetSpaceID(), fRayLength); CVector3 cDirection; c_ray.GetDirection(cDirection); dGeomRaySet(tRay, c_ray.GetStart().GetX(), c_ray.GetStart().GetY(), c_ray.GetStart().GetZ(), cDirection.GetX(), cDirection.GetY(), cDirection.GetZ()); /* Create the structure to contain info about the possible ray/geom intersection */ dContactGeom tIntersection; /* Check for intersection between the ray and the object local space */ if(dCollide(tRay, reinterpret_cast<dGeomID>(m_tEntitySpace), 1, &tIntersection, sizeof(dContactGeom)) > 0) { /* There is an intersecton */ f_t_on_ray = tIntersection.depth / fRayLength; return true; } else { /* No intersection detected */ return false; } }
bool CheckRay(const CRay& ray, const CPlane& plane, Vector3* hitPoint) { //This algorithm is based on the plane equation we saw in the CheckPlane methods float planeRayDirection = plane.GetNormal().Dot(ray.GetDirection()); if (planeRayDirection == 0) { return false; } //The equation is between the plane normal and the ray origin. It is also divided by the dot product of the plane normal and ray direction float t = -(plane.GetNormal().Dot(ray.GetOrigin()) + plane.GetDistance()) / planeRayDirection; //If the result of the equation is negative then there is no hit if (t < 0) { return false; } if (hitPoint) { //Here we calculate the point where the ray hits the plane Vector3 pointOnPlane = (ray.GetDirection() * t) + ray.GetOrigin(); hitPoint->x = pointOnPlane.x; hitPoint->y = pointOnPlane.y; hitPoint->z = pointOnPlane.z; } return true; }
bool CKinematics2DCollisionCircle::CheckIntersectionWithRay(Real& f_distance, const CRay& c_ray) const { CSegment c_segment = c_ray.ProjectOntoXY(); CVector2 c_closest_point, c_closest_segment_point; c_segment.GetMinimumDistancePoints( m_cPosition, c_closest_point, c_closest_segment_point ); Real f_min_segment_distance = Distance(m_cPosition,c_closest_segment_point); if( f_min_segment_distance > m_fRadius ) { return false; } // see http://local.wasp.uwa.edu.au/~pbourke/geometry/sphereline/ CVector2 dp = c_segment.GetEnd() - c_segment.GetStart(); Real a = dp.SquareLength(); Real b = 2 * dp.DotProduct(c_segment.GetStart() - m_cPosition); Real c = (m_cPosition.SquareLength() + c_segment.GetStart().SquareLength() - 2 * m_cPosition.DotProduct(c_segment.GetStart()) - m_fRadius*m_fRadius); Real bb4ac = b*b - 4*a*c; Real mu1 = (-b + sqrt(bb4ac)) / (2 * a); Real mu2 = (-b - sqrt(bb4ac)) / (2 * a); Real mu = Min(mu1,mu2); if( mu < 0 || mu > 1 ) mu = Max(mu1,mu2); f_distance = mu * c_ray.GetLength(); return true; }
// Do a ray check starting from position `pos' along direction `dir'. // Make resulting intersection points available in `GetIntersectionPoints()'. bool CPhysicsServer::RayCheck(const vector3& Pos, const vector3& Dir, const CFilterSet* ExcludeSet) { Contacts.Clear(); CRay R; R.SetOrigin(Pos); R.SetDirection(Dir); if (ExcludeSet) R.SetExcludeFilterSet(*ExcludeSet); R.DoRayCheckAllContacts(matrix44::identity, Contacts); return Contacts.Size() > 0; }
axelynx::RaySystem::Ray* CRaySystem::AddInstance() { CRay *piv = new CRay; piv->SetColor(1.0f,1.0f,1.0f,1.0f); piv->SetWidth(1.0f); piv->SetLenght(128.0f); instances_.push_back(piv); return piv; }
bool CPolygon::Intersect(CRay &ray, bool cull, float *dist) { if(!ray.Intersect(m_vertexList[0], m_vertexList[1], m_vertexList[2], false, dist)) return false; if(!cull) { if(!ray.Intersect(m_vertexList[2], m_vertexList[1], m_vertexList[0], false, dist)) return false; } return true; }
bool CSphere::Intersect(const CRay& clRay, RealType t0, RealType t1, TTracingContext& tContext ) const { /* Implement ray-sphere intersection. You must set the following member of the TTracingContext struct: t - ray parameter of intersection point v3Normal - Normal of surface at intersection point v3HitPoint - Coordinate of intersection point v2TexCoord - 2D-Texture coordinate of intersection point (use polar coordinates (method Cartesian2Polar), not needed currently) pclShader - Material of sphere */ VectorType3 vecDiff(m_v3Center - clRay.GetOrigin()); RealType t_ca = vecDiff | clRay.GetDir(); if (t_ca < 0) return false; RealType d2 = (vecDiff | vecDiff) - t_ca * t_ca; RealType r2 = m_rRadius * m_rRadius ; if (d2 > r2) { return false; } RealType desc = sqrt(r2 - d2); RealType t = (t_ca - desc) ; if (t < 0.0) { t = (t_ca + desc); } if (t > tContext.t) { return false; } tContext.t = t; tContext.v3HitPoint = clRay.Evaluate(tContext.t); tContext.v3Normal = (tContext.v3HitPoint - m_v3Center).normalize(); tContext.pclShader = GetShader(); return true; }
bool intersect(CRay& _ray, float* _thit, CLocalGeo* _local, int& _id) { if (_ray.m_id == m_id) return false; V3f E1 = m_V0 - m_V1; V3f E2 = m_V0 - m_V2; V3f S = m_V0 - _ray.m_pos; float d = det(_ray.m_dir, E1, E2); if (d < EPS && d > -EPS) return false; float d1 = det(S, E1, E2); float t = d1 / d; if (t < _ray.m_t_min || t > _ray.m_t_max) return false; float d2 = det(_ray.m_dir, S, E2); float beta = d2 / d; if (beta < -EPS || beta - 1 > EPS) return false; float d3 = det(_ray.m_dir, E1, S); float gamma = d3 / d; if (gamma < -EPS || gamma - 1 > EPS || beta + gamma - 1 > EPS) return false; *_thit = t; _id = m_id; _local->m_pos = _ray.Ray_t(t); _local->m_n = (m_V0-m_V1).cross(m_V0-m_V2); _local->m_n = _local->m_n / _local->m_n.norm(); return true; }
// --[ Method ]--------------------------------------------------------------- // // - Class : CVector3 // - Prototype : float Angle(const CRay& ray) // // - Purpose : Returns the angle between the vector and a ray. // // --------------------------------------------------------------------------- float CVector3::Angle(const CRay& ray) const { float fAngle = Angle(ray.Direction()); if(fAngle > 90.0f) fAngle = 180.0f - fAngle; return fAngle; }
// WinProc LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { // Constant amounts to move the origin of the ray by const CVector kXAxisMoveAmt(0.05f, 0.0f, 0.0f); const CVector kYAxisMoveAmt(0.0f, 0.05f, 0.0f); switch(message) { case WM_SYSKEYDOWN: // Toggle on ALT + ENTER if(wparam == VK_RETURN && (lparam & (1 << 29))) { g3D->toggleFullScreen(); g3D->setViewMatrix(CPos(0,1,-3.0f), CPos(0,0,0)); // Reset the view of our scene return 0; } break; // Allow other system keys to be handled by DefWindowProc() case WM_KEYDOWN: // If we get a key down message, do stuff switch(wparam) { case VK_ESCAPE: // If they push ESC, close the app SendMessage(hwnd, WM_CLOSE, 0, 0); break; case VK_LEFT: // Move the origin of the ray to the left (-X axis) gRay.setOrigin(gRay.getOrigin() - kXAxisMoveAmt); break; case VK_RIGHT: // Move the origin of the ray to the right (+X axis) gRay.setOrigin(gRay.getOrigin() + kXAxisMoveAmt); break; case VK_DOWN: // Move the origin of the ray down (-Y axis) gRay.setOrigin(gRay.getOrigin() - kYAxisMoveAmt); break; case VK_UP: // Move the origin of the ray up (+Y axis) gRay.setOrigin(gRay.getOrigin() + kYAxisMoveAmt); break; } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wparam, lparam); }
bool CheckRay(const CRay& ray, const CBoundingSphere& sphere, Vector3* hitPoint) { //This algorithm is adatped from: http://www.cosinekitty.com/raytrace/chapter06_sphere.html //It breaks the problem down into the plane equations needed to find the hit points between the ray and sphere //To solve this correctly it makes use of a quadratic equation. Vector3 displacement = ray.GetOrigin() - sphere.GetCenter(); float a = ray.GetDirection().LengthSquared(); float b = 2.0f * displacement.Dot(ray.GetDirection()); float c = displacement.LengthSquared() - sphere.GetRadius() * sphere.GetRadius(); float randicand = b*b - 4.0f * a * c; //If the quadratic equation comes back as a negitive then there is no hit. if (randicand < 0.0f) { return false; } float root = sqrt(randicand); float denom = 2.0 * a; //Here we calculate the distance between ray origin and the two hit points (where the ray enters the sphere and where it exits) float hit1 = (-b + root) / denom; float hit2 = (-b - root) / denom; //If both of the hits are negitive then it means that the sphere is behind the origin of the ray so there is no hit if (hit1 < 0 && hit2 < 0) { return false; } if (hitPoint) { //If we need to know the first hit point on the sphere then we should use hit1, unless it's negative then we use hit2. //This would come up in situations where the origin of the ray is within the sphere. float firstHitDistance = hit1 < 0 ? hit2 : hit1; Vector3 pointOnSphere = (ray.GetDirection() * firstHitDistance) + ray.GetOrigin(); hitPoint->x = pointOnSphere.x; hitPoint->y = pointOnSphere.y; hitPoint->z = pointOnSphere.z; } return true; }
static void RepWireBondRender(RepWireBond * I, RenderInfo * info) { PyMOLGlobals *G = I->R.G; CRay *ray = info->ray; auto pick = info->pick; int ok = true; if(ray) { #ifndef _PYMOL_NO_RAY CGORenderRay(I->primitiveCGO, ray, info, NULL, NULL, I->R.cs->Setting, I->R.cs->Obj->Obj.Setting); ray->transparentf(0.0); #endif } else if(G->HaveGUI && G->ValidContext) { bool use_shader = SettingGetGlobal_b(G, cSetting_line_use_shader) && SettingGetGlobal_b(G, cSetting_use_shaders); if(pick) { CGORenderGLPicking(use_shader ? I->shaderCGO : I->primitiveCGO, info, &I->R.context, NULL, NULL, &I->R); } else { /* else not pick i.e., when rendering */ short line_as_cylinders ; line_as_cylinders = SettingGetGlobal_b(G, cSetting_render_as_cylinders) && SettingGetGlobal_b(G, cSetting_line_as_cylinders); if (I->shaderCGO && (!use_shader || (line_as_cylinders ^ I->shaderCGO_has_cylinders))){ CGOFree(I->shaderCGO); I->shaderCGO_has_cylinders = 0; } if (ok){ if (use_shader) { if (!I->shaderCGO) ok &= RepWireBondCGOGenerate(I, info); CGORenderGL(I->shaderCGO, NULL, NULL, NULL, info, &I->R); } else { CGORenderGL(I->primitiveCGO, NULL, NULL, NULL, info, &I->R); } } } } if (!ok){ CGOFree(I->shaderCGO); I->R.fInvalidate(&I->R, I->R.cs, cRepInvPurge); I->R.cs->Active[cRepLine] = false; } }
bool CPlane::Hit(const CRay &ray, SRayIntersection &intersection) const { // Величина, меньше которой модуль скалярного произведения вектора направления луча и // нормали плоскости означает параллельность луча и плоскости const float EPSILON = std::numeric_limits<float>::epsilon(); // Нормаль к плоскости в системе координат объекта const glm::vec3 normalInObjectSpace(m_planeEquation); // Скалярное произведение направления луча и нормали к плоскости const float normalDotDirection = glm::dot(ray.GetDirection(), normalInObjectSpace); // Если скалярное произведение близко к нулю, луч параллелен плоскости if (fabs(normalDotDirection) < EPSILON) { return false; } /* Находим время пересечения луча с плоскостью, подставляя в уравнение плоскости точку испускания луча и деление результата на ранее вычисленное сканярное произведение направления луча и нормали к плоскости */ const float hitTime = -glm::dot(glm::vec4(ray.GetStart(), 1), m_planeEquation) / normalDotDirection; // Нас интересует только пересечение луча с плоскостью в положительный момент времени, // поэтому находящуюся "позади" точки испускания луча точку пересечения мы за точку пересечения не считаем // Сравнение с величиной EPSILON, а не с 0 нужно для того, чтобы позволить // лучам, испущенным с плоскости, оторваться от нее. // Это необходимо при обработке вторичных лучей для построения теней и отражений и преломлений if (hitTime <= EPSILON) { return false; } // Вычисляем точку столкновения с лучом в системе координат сцены в момент столкновения const glm::vec3 hitPoint = ray.GetPointAtTime(hitTime); intersection.m_time = hitTime; intersection.m_point = hitPoint; return true; }
bool CDynamics2DCylinderEntity::CheckIntersectionWithRay(Real& f_t_on_ray, const CRay& c_ray) const { cpSegmentQueryInfo tInfo; if(cpShapeSegmentQuery(m_ptShape, cpv(c_ray.GetStart().GetX(), c_ray.GetStart().GetY()), cpv(c_ray.GetEnd().GetX() , c_ray.GetEnd().GetY() ), &tInfo)) { CVector3 cIntersectionPoint; c_ray.GetPoint(cIntersectionPoint, tInfo.t); if((cIntersectionPoint.GetZ() >= GetEmbodiedEntity().GetPosition().GetZ() - m_fHalfHeight) && (cIntersectionPoint.GetZ() <= GetEmbodiedEntity().GetPosition().GetZ() + m_fHalfHeight) ) { f_t_on_ray = tInfo.t; return true; } else { return false; } } else { return false; } }
bool CheckRay(const CRay& ray, const CBoundingBox& bb, Vector3* hitPoint) { //This algorithm is adapted from: http://tavianator.com/fast-branchless-raybounding-box-intersections/ //Its based on the "Slab Technique" which treats a bounding box as a series of 2 planes in each axis. //It finds where the ray lies on each of these planes and compares those values across each axis. float tmin = -INFINITY; float tmax = INFINITY; float tx1 = (bb.GetMin().x - ray.GetOrigin().x) / ray.GetDirection().x; float tx2 = (bb.GetMax().x - ray.GetOrigin().x) / ray.GetDirection().x; tmin = max(tmin, min(tx1, tx2)); tmax = min(tmax, max(tx1, tx2)); float ty1 = (bb.GetMin().y - ray.GetOrigin().y) / ray.GetDirection().y; float ty2 = (bb.GetMax().y - ray.GetOrigin().y) / ray.GetDirection().y; tmin = max(tmin, min(ty1, ty2)); tmax = min(tmax, max(ty1, ty2)); float tz1 = (bb.GetMin().z - ray.GetOrigin().z) / ray.GetDirection().z; float tz2 = (bb.GetMax().z - ray.GetOrigin().z) / ray.GetDirection().z; tmin = max(tmin, min(tz1, tz2)); tmax = min(tmax, max(tz1, tz2)); //We end up with two hit values just like the sphere, if the max hit is less than 0 then it all happened behind the ray origin if (tmax < 0) return false; //If the max hit value is greater than the min hit (as it should be) then we have a hit! if (tmax >= tmin) { if (hitPoint) { //If we need to know the first hit point on the box then we should use tmin, unless it's negative then we use tmax. //This would come up in situations where the origin of the ray is within the box. float firstHitDistance = tmin < 0 ? tmax : tmin; Vector3 pointOnBox = (ray.GetDirection() * firstHitDistance) + ray.GetOrigin(); hitPoint->x = pointOnBox.x; hitPoint->y = pointOnBox.y; hitPoint->z = pointOnBox.z; } return true; } return false; }
bool intersect(CRay& _ray, float* _thit, CLocalGeo* _local, int& _id) { if (_ray.m_id == m_id) return false; float t; V3f oc = _ray.m_pos - m_c; float a = _ray.m_dir.dot(_ray.m_dir); // dir should be unit float b = _ray.m_dir.dot(oc); float c = oc.dot(oc) - m_r2; float delta = b * b - a * c; if (delta < 0) // no solution return false; else if (delta > -EPS && delta < EPS) { // one solution t = - b / a; if (t > _ray.m_t_max || t < _ray.m_t_min) // out of range return false; } else { // two solutions float deltasqrt = sqrt(delta); float t1 = (- b - deltasqrt) / a; float t2 = (- b + deltasqrt) / a; bool flag = false; t = _ray.m_t_max; if (t1 <= _ray.m_t_max && t1 >= _ray.m_t_min) { flag = true; t = min(t, t1); } if (t2 <= _ray.m_t_max && t2 >= _ray.m_t_min) { flag = true; t = min(t, t2); } if (!flag) // both out of range return false; } // pass t, compute CLocalGeo *_thit = t; _id = m_id; _local->m_pos = _ray.Ray_t(t); _local->m_n = _local->m_pos - m_c; _local->m_n = _local->m_n / _local->m_n.norm(); return true; }
void CGuardRobot::process() { switch(state) { case LOOK: // animation if (animtimer > LOOK_ANIM_TIME) { frame ^= 1; animtimer = 0; } else animtimer++; sprite = LOOK_FRAME + frame; // when time is up go back to moving if (timer > LOOK_TOTALTIME) { timetillcanfire = (rnd()%(MAX_TIME_TILL_CAN_FIRE-MIN_TIME_TILL_CAN_FIRE))+MIN_TIME_TILL_CAN_FIRE; timetillcanfirecauseonsamelevel = TIME_BEFORE_FIRE_WHEN_SEE; firetimes = 0; state = WALK; frame = 0; animtimer = 0; timer = 0; dist_to_travel = TRAVELDIST; } else timer++; break; case WALK: // hover animation if (animtimer > WALK_ANIM_TIME) { if (frame>=3) frame=0; else frame++; animtimer = 0; } else animtimer++; if (movedir==LEFT) sprite = WALK_LEFT_FRAME + frame; else sprite = WALK_RIGHT_FRAME + frame; // if we're about to, or just did, fire a volley, don't move if (!hardmode) { if (pausetime) { pausetime--; return; } } else pausetime = 0; // are we firing a volley? if (firetimes) { // is it time to fire the next shot in the volley? if (!timetillnextshot) { CRay *newobject; if (onscreen) playSound(SOUND_TANK_FIRE); if (movedir==RIGHT) newobject = new CRay(mp_Map,getXRightPos()+(8<<STC), getYUpPos()+(5<<STC), RIGHT); else newobject = new CRay(mp_Map,getXPosition(), getYUpPos()+(5<<STC), LEFT); newobject->setOwner(OBJ_GUARDROBOT, m_index); newobject->sprite = ENEMYRAYEP2; m_ObjectVect.push_back(newobject); timetillnextshot = TIME_BETWEEN_SHOTS; if (!--firetimes) { pausetime = FIRE_PAUSE_TIME; } } else { timetillnextshot--; } // don't move when firing except on hard mode if (hardmode) return; } else { // not firing a volley if (!timetillcanfire) { guard_fire(); } else { timetillcanfire--; } } turnaroundtimer = 0; if (movedir==LEFT) { // move left if (!blockedl) { xinertia = -WALK_SPEED; dist_to_travel--; } else { frame = 0; timer = 0; animtimer = 0; state = LOOK; movedir = RIGHT; } } else { // move right sprite = WALK_RIGHT_FRAME + frame; if (!blockedr) { xinertia = WALK_SPEED; dist_to_travel--; } else { frame = 0; timer = 0; animtimer = 0; state = LOOK; movedir = LEFT; } } break; default : break; } }
void CTank::process() { switch(state) { case TANK_WALK: // Walk in a direction { // is keen on same level? if (movedir==LEFT) { // move left sprite = TANK_WALK_LEFT_FRAME + frame; xinertia = -TANK_WALK_SPEED; if( blockedl ) { movedir = RIGHT; frame = 0; timer = 0; animtimer = 0; state = TANK_TURN; } dist_to_travel--; } else { // move right sprite = TANK_WALK_RIGHT_FRAME + frame; xinertia = TANK_WALK_SPEED; if ( blockedr ) { movedir = LEFT; frame = 0; timer = 0; animtimer = 0; state = TANK_TURN; } dist_to_travel--; } // walk animation if (animtimer > TANK_WALK_ANIM_TIME) { if (frame>=3) frame=0; else frame++; animtimer = 0; } else animtimer++; if(dist_to_travel==0) { frame = 0; timer = 0; animtimer = 0; state = TANK_WAIT; } default: break; } break; case TANK_WAIT: if ( (timer > TANK_PREPAREFIRE_TIME) || (timer > TANK_PREPAREFIRE_TIME_FAST && hardmode) ) { timer = 0; state = TANK_FIRE; } else timer++; break; case TANK_TURN: // If it gets stuck somewhere turn around sprite = TANK_LOOK_FRAME + frame; // animation if (animtimer > TANK_LOOK_ANIM_TIME) { frame ^= 1; animtimer = 0; } else animtimer++; // when time is up go back to moving if (timer > TANK_LOOK_TOTALTIME) { // decide what direction to go state = TANK_WALK; animtimer = 0; timer = 0; } else timer++; break; case TANK_FIRE: { int height_top = g_pBehaviorEngine->getPhysicsSettings().tankbot.shot_height_from_top<<STC; if(height_top!=0) { CRay *newobject; if (onscreen) playSound(SOUND_TANK_FIRE); if (movedir==RIGHT) newobject = new CRay(mp_Map, getXMidPos(), getYUpPos()+height_top, RIGHT); else newobject = new CRay(mp_Map, getXMidPos(), getYUpPos()+height_top, LEFT); newobject->setOwner(OBJ_TANK, m_index); newobject->setSpeed(108); newobject->sprite = ENEMYRAY; newobject->canbezapped = true; m_Object.push_back(newobject); } state = TANK_WAIT_LOOK; frame = 0; timer = 0; animtimer = 0; dist_to_travel = TANK_MINTRAVELDIST + (rnd()%10)*(TANK_MAXTRAVELDIST-TANK_MINTRAVELDIST)/10; } break; case TANK_WAIT_LOOK: // Happens after Robot has fired if ( timer > TANK_WAITAFTER_FIRE ) { timer = 0; state = TANK_LOOK; } else timer++; break; case TANK_LOOK: sprite = TANK_LOOK_FRAME + frame; // animation if (animtimer > TANK_LOOK_ANIM_TIME) { frame ^= 1; animtimer = 0; } else animtimer++; // when time is up go back to moving if (timer > TANK_LOOK_TOTALTIME) { // decide what direction to go if(m_Player[0].getXMidPos() < getXMidPos()) { movedir = LEFT; sprite = TANK_WALK_LEFT_FRAME; } else if(m_Player[0].getXMidPos() > getXMidPos()) { movedir = RIGHT; sprite = TANK_WALK_RIGHT_FRAME; } state = TANK_WALK; animtimer = 0; timer = 0; } else timer++; break; } }
void CVorticonElite::process() { if (mHealthPoints <= 0 && state != VORTELITE_DYING) { animtimer = 0; frame = 0; state = VORTELITE_DYING; dying = true; if (onscreen) playSound(SOUND_VORT_DIE); } if(state == VORTELITE_CHARGE) { m_speed = CHARGE_SPEED; } else if(state == VORTELITE_WALK) { m_speed = WALK_SPEED; } reprocess: ; switch(state) { case VORTELITE_CHARGE: case VORTELITE_WALK: if (movedir==LEFT) { // move left sprite = VORTELITE_WALK_LEFT_FRAME + frame; if (!blockedl) { xinertia = -m_speed; } else { movedir = RIGHT; // if we only traveled a tiny amount before hitting a wall, we've // probably fallen into a small narrow area, and we need to try // to jump out of it if (dist_traveled < VORTELITE_TRAPPED_DIST && !mp_Map->m_Dark && blockedd) { initiatejump(); goto reprocess; } else if(mp_Map->m_Dark) { dist_traveled = 0; } } } else { // move right sprite = VORTELITE_WALK_RIGHT_FRAME + frame; if (!blockedr) { xinertia = m_speed; } else { movedir = LEFT; // if we only traveled a tiny amount before hitting a wall, we've // probably fallen into a small narrow area, and we need to try // to jump out of it if (dist_traveled < VORTELITE_TRAPPED_DIST && !mp_Map->m_Dark && blockedd) { initiatejump(); goto reprocess; } else if(mp_Map->m_Dark) { dist_traveled = 0; } } } // walk animation if (animtimer > VORTELITE_WALK_ANIM_TIME) { if (frame>=3) frame=0; else frame++; animtimer = 0; } else animtimer++; break; case VORTELITE_JUMP: if (movedir == RIGHT) { if (!blockedr) moveRight(m_speed); } else { if (!blockedl) moveLeft(m_speed); } if (blockedd && yinertia >= 0) { // The Vorticon Has landed after the jump! state = VORTELITE_WALK; goto reprocess; } break; case VORTELITE_ABOUTTOFIRE: if (movedir==RIGHT) { sprite = VORTELITE_FIRE_RIGHT_FRAME; } else { sprite = VORTELITE_FIRE_LEFT_FRAME; } if (timer > VORTELITE_HOLD_GUN_OUT_TIME) { timer = 0; state = VORTELITE_FIRED; CRay *newobject; if (movedir==RIGHT) newobject = new CRay(mp_Map, getXRightPos()+1, getYPosition()+(9<<STC), RIGHT, CENTER, getSpriteVariantId()); else newobject = new CRay(mp_Map, getXLeftPos()-1, getYPosition()+(9<<STC), LEFT, CENTER, getSpriteVariantId()); newobject->setOwner( m_type, m_index); newobject->sprite = ENEMYRAYEP2; // don't shoot other vorticon elite spawnObj(newobject); if (onscreen) playSound(SOUND_KEEN_FIRE); } else timer++; break; case VORTELITE_FIRED: if (movedir==RIGHT) { sprite = VORTELITE_FIRE_RIGHT_FRAME; } else { sprite = VORTELITE_FIRE_LEFT_FRAME; } if (timer > VORTELITE_HOLD_GUN_AFTER_FIRE_TIME) { timer = 0; frame = 0; timesincefire = 0; state = VORTELITE_WALK; } else timer++; break; case VORTELITE_DYING: sprite = VORTELITE_DYING_FRAME; if (animtimer > VORTELITE_DIE_ANIM_TIME) { sprite = VORTELITE_DEAD_FRAME; dead = true; } else { animtimer++; } break; default: break; } }
void CEPuckRangeAndBearingSensor::Update() { /* Clear the previous received packets */ ClearRABReceivedPackets(); /* Get robot position */ const CVector3& cRobotPosition = m_pcEmbodiedEntity->GetPosition(); /* Get robot orientation */ CRadians cTmp1, cTmp2, cOrientationZ; m_pcEmbodiedEntity->GetOrientation().ToEulerAngles(cOrientationZ, cTmp1, cTmp2); /* Buffer for calculating the message--robot distance */ CVector3 cVectorToMessage; CVector3 cVectorRobotToMessage; Real fMessageDistance; /* Buffer for the received packet */ TEPuckRangeAndBearingReceivedPacket tPacket; /* Initialize the occlusion check ray start to the position of the robot */ CRay cOcclusionCheckRay; cOcclusionCheckRay.SetStart(cRobotPosition); /* Buffer to store the intersection data */ CSpace::SEntityIntersectionItem<CEmbodiedEntity> sIntersectionData; /* Ignore the sensing robot when checking for occlusions */ TEmbodiedEntitySet tIgnoreEntities; tIgnoreEntities.insert(m_pcEmbodiedEntity); /* * 1. Go through all the CRABEquippedEntities<2> (those compatible with this sensor) * 2. For each of them * a) Check that the receiver is not out of range * b) Check if there is an occlusion * c) If there isn't, get the info and set reading for that robot */ CSpace::TAnyEntityMap& tEntityMap = m_cSpace.GetEntitiesByType("rab_equipped_entity<2>"); for(CSpace::TAnyEntityMap::iterator it = tEntityMap.begin(); it != tEntityMap.end(); ++it) { CRABEquippedEntity<2>& cRABEntity = *(any_cast<CRABEquippedEntity<2>*>(it->second)); /* Check the RAB equipped entity is not this robot (avoid self-messaging) */ if(&cRABEntity != m_pcRABEquippedEntity) { /* Get the position of the RAB equipped entity */ cVectorToMessage = cRABEntity.GetPosition(); cVectorRobotToMessage = (cVectorToMessage - cRobotPosition) * 100; // in cms /* Check that the distance is lower than the range */ fMessageDistance = cVectorRobotToMessage.Length(); if(fMessageDistance < cRABEntity.GetRange()) { /* Set the ray end */ cOcclusionCheckRay.SetEnd(cVectorToMessage); /* Check occlusion between robot and message location */ if(!m_bCheckOcclusions || (! m_cSpace.GetClosestEmbodiedEntityIntersectedByRay(sIntersectionData, cOcclusionCheckRay, tIgnoreEntities)) || sIntersectionData.IntersectedEntity->GetId() == cRABEntity.GetId()) { /* The message is not occluded */ if(m_bShowRays) m_pcControllableEntity->AddCheckedRay(false, cOcclusionCheckRay); /* Set the reading */ tPacket.Id = m_unLatestPacketId++; CRadians cVertical = CRadians::ZERO; cVectorRobotToMessage.ToSphericalCoordsHorizontal(tPacket.Range, cVertical, tPacket.BearingHorizontal); tPacket.BearingHorizontal -= cOrientationZ; tPacket.BearingHorizontal.SignedNormalize(); cRABEntity.GetData(tPacket.Data); m_tLastReceivedPackets.push_back(tPacket); } else { /* The message is occluded */ if(m_bShowRays) { m_pcControllableEntity->AddCheckedRay(true, cOcclusionCheckRay); m_pcControllableEntity->AddIntersectionPoint(cOcclusionCheckRay, sIntersectionData.TOnRay); } } } } } }
void CVorticonElite::process() { if (HealthPoints <= 0 && state != VORTELITE_DYING) { animtimer = 0; frame = 0; state = VORTELITE_DYING; dying = true; if (onscreen) playSound(SOUND_VORT_DIE); } if(state == VORTELITE_CHARGE) { m_speed = CHARGE_SPEED; } else if(state == VORTELITE_WALK) { m_speed = WALK_SPEED; } reprocess: ; switch(state) { case VORTELITE_CHARGE: case VORTELITE_WALK: dist_traveled++; state = VORTELITE_WALK; // If Player is nearby, make vorticon go faster if(getYDownPos() > m_Player[0].getYDownPos()-(1<<CSF) and getYDownPos() < m_Player[0].getYDownPos()+(1<<CSF) ) { int dist; if(getXMidPos() > m_Player[0].getXMidPos()) dist = getXMidPos()-m_Player[0].getXMidPos(); else dist = m_Player[0].getXMidPos()-getXMidPos(); if(dist < PLAYER_DISTANCE) state = VORTELITE_CHARGE; } if (getProbability(VORTELITE_JUMP_PROB) && !mp_Map->m_Dark && !blockedu) { // let's jump. initiatejump(); goto reprocess; } else { if (timesincefire > VORTELITE_MIN_TIME_BETWEEN_FIRE) { if (getProbability(VORTELITE_FIRE_PROB)) { // let's fire // usually shoot toward keen if (rand()%5 != 0) { if (getXPosition() < m_Player[0].getXPosition()) { movedir = RIGHT; } else { movedir = LEFT; } } timer = 0; state = VORTELITE_ABOUTTOFIRE; } } else timesincefire++; } if (movedir==LEFT) { // move left sprite = VORTELITE_WALK_LEFT_FRAME + frame; if (!blockedl) { xinertia = -m_speed; } else { movedir = RIGHT; // if we only traveled a tiny amount before hitting a wall, we've // probably fallen into a small narrow area, and we need to try // to jump out of it if (dist_traveled < VORTELITE_TRAPPED_DIST && !mp_Map->m_Dark && blockedd) { initiatejump(); goto reprocess; } else dist_traveled = 0; } } else { // move right sprite = VORTELITE_WALK_RIGHT_FRAME + frame; if (!blockedr) { xinertia = m_speed; } else { movedir = LEFT; // if we only traveled a tiny amount before hitting a wall, we've // probably fallen into a small narrow area, and we need to try // to jump out of it if (dist_traveled < VORTELITE_TRAPPED_DIST && !mp_Map->m_Dark && blockedd) { initiatejump(); goto reprocess; } else dist_traveled = 0; } } // walk animation if (animtimer > VORTELITE_WALK_ANIM_TIME) { if (frame>=3) frame=0; else frame++; animtimer = 0; } else animtimer++; break; case VORTELITE_JUMP: if (movedir == RIGHT) { if (!blockedr) moveRight(m_speed); } else { if (!blockedl) moveLeft(m_speed); } if (blockedd && yinertia >= 0) { // The Vorticon Has landed after the jump! state = VORTELITE_WALK; goto reprocess; } break; case VORTELITE_ABOUTTOFIRE: if (movedir==RIGHT) { sprite = VORTELITE_FIRE_RIGHT_FRAME; } else { sprite = VORTELITE_FIRE_LEFT_FRAME; } if (timer > VORTELITE_HOLD_GUN_OUT_TIME) { timer = 0; state = VORTELITE_FIRED; CRay *newobject; if (movedir==RIGHT) newobject = new CRay(mp_Map, getXRightPos()+1, getYPosition()+(9<<STC), RIGHT); else newobject = new CRay(mp_Map, getXLeftPos()-1, getYPosition()+(9<<STC), LEFT); newobject->setOwner( m_type, m_index); newobject->sprite = ENEMYRAYEP2; // don't shoot other vorticon elite m_Object.push_back(newobject); if (onscreen) playSound(SOUND_KEEN_FIRE); } else timer++; break; case VORTELITE_FIRED: if (movedir==RIGHT) { sprite = VORTELITE_FIRE_RIGHT_FRAME; } else { sprite = VORTELITE_FIRE_LEFT_FRAME; } if (timer > VORTELITE_HOLD_GUN_AFTER_FIRE_TIME) { timer = 0; frame = 0; timesincefire = 0; state = VORTELITE_WALK; // head toward keen if (getXPosition() < m_Player[0].getXPosition()) { movedir = RIGHT; } else { movedir = LEFT; } } else timer++; break; case VORTELITE_DYING: sprite = VORTELITE_DYING_FRAME; if (animtimer > VORTELITE_DIE_ANIM_TIME) { sprite = VORTELITE_DEAD_FRAME; dead = true; } else { animtimer++; } break; default: break; } }
void CEPuckLightSensor::Update() { /* Here we assume that the e-puck is rotated only wrt to the Z axis */ /* Erase readings */ for(size_t i = 0; i < m_tReadings.size(); ++i) { m_tReadings[i].Value = 0.0f; } /* Get e-puck position */ const CVector3& cEPuckPosition = GetEntity().GetEmbodiedEntity().GetPosition(); /* Get e-puck orientation */ CRadians cTmp1, cTmp2, cOrientationZ; GetEntity().GetEmbodiedEntity().GetOrientation().ToEulerAngles(cOrientationZ, cTmp1, cTmp2); /* Buffer for calculating the light--e-puck distance */ CVector3 cLightDistance; /* Buffer for the angle of the sensor wrt to the e-puck */ CRadians cLightAngle; /* Initialize the occlusion check ray start to the baseline of the e-puck */ CRay cOcclusionCheckRay; cOcclusionCheckRay.SetStart(cEPuckPosition); /* Buffer to store the intersection data */ CSpace::SEntityIntersectionItem<CEmbodiedEntity> sIntersectionData; /* Ignore the sensing ropuck when checking for occlusions */ TEmbodiedEntitySet tIgnoreEntities; tIgnoreEntities.insert(&GetEntity().GetEmbodiedEntity()); /* * 1. go through the list of light entities in the scene * 2. check if a light is occluded * 3. if it isn't, distribute the reading across the sensors * NOTE: the readings are additive * 4. go through the sensors and clamp their values */ try{ CSpace::TAnyEntityMap& tEntityMap = m_cSpace.GetEntitiesByType("light_entity"); for(CSpace::TAnyEntityMap::iterator it = tEntityMap.begin(); it != tEntityMap.end(); ++it) { /* Get a reference to the light */ CLightEntity& cLight = *(any_cast<CLightEntity*>(it->second)); /* Consider the light only if it has non zero intensity */ if(cLight.GetIntensity() > 0.0f) { /* Get the light position */ const CVector3& cLightPosition = cLight.GetPosition(); /* Set the ray end */ cOcclusionCheckRay.SetEnd(cLightPosition); /* Check occlusion between the e-puck and the light */ if(! m_cSpace.GetClosestEmbodiedEntityIntersectedByRay(sIntersectionData, cOcclusionCheckRay, tIgnoreEntities)) { /* The light is not occluded */ if(m_bShowRays) GetEntity().GetControllableEntity().AddCheckedRay(false, cOcclusionCheckRay); /* Get the distance between the light and the e-puck */ cOcclusionCheckRay.ToVector(cLightDistance); /* Linearly scale the distance with the light intensity The greater the intensity, the smaller the distance */ cLightDistance /= cLight.GetIntensity(); /* Get the angle wrt to e-puck rotation */ cLightAngle = cLightDistance.GetZAngle(); cLightAngle -= cOrientationZ; /* Transform it into counter-clockwise rotation */ cLightAngle.Negate().UnsignedNormalize(); /* Find reading corresponding to the sensor */ SInt16 nMin = 0; for(SInt16 i = 1; i < NUM_READINGS; ++i){ if((cLightAngle - m_tReadings[i].Angle).GetAbsoluteValue() < (cLightAngle - m_tReadings[nMin].Angle).GetAbsoluteValue()) nMin = i; } /* Set the actual readings */ Real fReading = cLightDistance.Length(); m_tReadings[Modulo((SInt16)(nMin-1), NUM_READINGS)].Value += ComputeReading(fReading * Cos(cLightAngle - m_tReadings[Modulo(nMin-1, NUM_READINGS)].Angle)); m_tReadings[ nMin ].Value += ComputeReading(fReading); m_tReadings[Modulo((SInt16)(nMin+1), NUM_READINGS)].Value += ComputeReading(fReading * Cos(cLightAngle - m_tReadings[Modulo(nMin+1, NUM_READINGS)].Angle)); } else { /* The ray is occluded */ if(m_bShowRays) { GetEntity().GetControllableEntity().AddCheckedRay(true, cOcclusionCheckRay); GetEntity().GetControllableEntity().AddIntersectionPoint(cOcclusionCheckRay, sIntersectionData.TOnRay); } } } } } catch(argos::CARGoSException& e){ } /* Now go through the sensors, add noise and clamp their values if above 1024 or under 1024 */ for(size_t i = 0; i < m_tReadings.size(); ++i) { if(m_fNoiseLevel>0.0f) AddNoise(i); if(m_tReadings[i].Value > 1024.0f) m_tReadings[i].Value = 1024.0f; if(m_tReadings[i].Value < 0.0f) m_tReadings[i].Value = 0.0f; } }
bool CUtils::IntersectTriangle(const CRay &i_Ray, CIntersactionInfo &io_IntersectionInfo, const CVector3DF &i_vA, const CVector3DF &i_vB, const CVector3DF &i_vC) { //intersect stuff double lambda2; double lambda3; double closestdist = io_IntersectionInfo.m_fDistance; const CVector3DF a = i_vB - i_vA; const CVector3DF b = i_vC - i_vA; CVector3DF c = - (i_Ray.Direction()); CVector3DF h = i_Ray.StartPoint() - i_vA; /* 2. Solve the equation: * * A + lambda2 * AB + lambda3 * AC = ray.start + gamma * ray.dir * * which can be rearranged as: * lambda2 * AB + lambda3 * AC - gamma * ray.dir = ray.start - A * * Which is a linear system of three rows and three unknowns, which we solve using Carmer's rule */ // // Find the determinant of the left part of the equation const float Dcr = CVector3DF::Triple(a, b, c); // check for zero; if it is zero, then the triangle and the ray are parallel if (fabs(Dcr) < k_fSMALL) { return false; } // find the reciprocal of the determinant. We would use this quantity later in order // to multiply by rDcr instead of divide by Dcr (division is much slower) double rDcr = 1.0 / Dcr; // calculate `gamma' by substituting the right part of the equation in the third column of the matrix, // getting the determinant, and dividing by Dcr) const double gamma = CVector3DF::Triple(a, b, h) * rDcr; // Is the intersection point behind us? Is the intersection point worse than what we currently have? if (gamma <= 0 || gamma > closestdist) { return false; } lambda2 = CVector3DF::Triple(h, b, c) * rDcr; // Check if it is in range (barycentric coordinates) if (lambda2 < 0 || lambda2 > 1) { return false; } lambda3 = CVector3DF::Triple(a, h, c) * rDcr; // Calculate lambda3 and check if it is in range as well if (lambda3 < 0 || lambda3 > 1) { return false; } if (lambda2 + lambda3 > 1) { return false; } closestdist = gamma; io_IntersectionInfo.m_fDistance = closestdist; io_IntersectionInfo.m_vIntersectionPoint = i_Ray.GetPointAtDistance(closestdist); io_IntersectionInfo.m_vBarCoordsLocal.SetX(1.0f - lambda2 - lambda3); io_IntersectionInfo.m_vBarCoordsLocal.SetY(lambda2); io_IntersectionInfo.m_vBarCoordsLocal.SetZ(lambda3); //Normal to the surface io_IntersectionInfo.m_vNormal = CVector3DF::Normal(a, b); return true; }
bool CBezierPatch::intersect(const CRay &ray, CIntersactionInfo &info, CVector3DF barCoord, unsigned int iterations, bool bDebug) const { //Planes along ray CVector3DF N1 = ray.Direction().Cross(CVector3DF(-1.0f,-1.0f,-1.0f)); CVector3DF N2 = ray.Direction().Cross(N1); const float d1 = -N1.Dot(ray.StartPoint()); const float d2 = -N2.Dot(ray.StartPoint()); float fSMall = 1e-3; CVector3DF dBu, dBv; for (unsigned int i = 0; i < iterations; i++) { const double &u(barCoord.X()); const double &v(barCoord.Y()); //partial U derivative of B dBu = GetdBu(u,v); //Partial V derivative of B dBv = GetdBv(u,v); const CVector3DF B = GetPointFromBarycentric(barCoord); const CVector3DF R = CVector3DF(N1.Dot(B) + d1, N2.Dot(B) + d2, 0); if ( ( fabs(R.X()) < fSMall ) && ( fabs(R.Y()) < fSMall ) ) { break; } //Inverse Jacobian const float fN1dotdBu = N1.Dot(dBu); const float fN1dotdBv = N1.Dot(dBv); const float fN2dotdBu = N2.Dot(dBu); const float fN2dotdBv = N2.Dot(dBv); const float invConst = 1.0f / ( fN1dotdBu * fN2dotdBv - fN1dotdBv * fN2dotdBu ); Matrix inverseJacobian; inverseJacobian[0][0] = fN2dotdBv * invConst; inverseJacobian[0][1] = -fN2dotdBu * invConst; inverseJacobian[0][2] = 0; inverseJacobian[1][0] = -fN1dotdBv * invConst; inverseJacobian[1][1] = fN1dotdBu * invConst; inverseJacobian[1][2] = 0; inverseJacobian[2][0] = 0; inverseJacobian[2][1] = 0; inverseJacobian[2][2] = 1; //Newton Iteration barCoord = barCoord - R.MatrixMultiply(inverseJacobian); barCoord.SetZ(1.0 - barCoord.X() - barCoord.Y()); if (barCoord.X() > k_fMAX || barCoord.X() < k_fMIN || barCoord.Y() > k_fMAX || barCoord.Y() < k_fMIN || barCoord.Z() > k_fMAX || barCoord.Z() < k_fMIN) { return false; } } const float &u(barCoord.X()); const float &v(barCoord.Y()); const float w(1.0 - u - v); if (u < -k_fSMALL || u > 1.0f + k_fSMALL || v < -k_fSMALL || v > 1.0f + k_fSMALL || w < -k_fSMALL || w > 1.0f + k_fSMALL) { return false; } if (bDebug) { char str[100]; sprintf( str, "u: %4.2f v: %4.2f w: %4.2f", u, v, w); qDebug() << str; } //Calculating B const CVector3DF B = GetPointFromBarycentric(barCoord); if ( ( fabs(N1.Dot(B) + d1) > fSMall ) || ( fabs(N2.Dot(B) + d2) > fSMall ) ) { if (bDebug) { qDebug() << "error too big"; } return false; } // calculate the intersection float len = (B - ray.StartPoint()).Length(); if (len > info.m_fDistance) { if (bDebug) { qDebug() << "Len > Distance"; } return false; } info.m_vIntersectionPoint = B; info.m_fDistance = len; info.m_vBarCoordsLocal.SetX(u); info.m_vBarCoordsLocal.SetY(v); info.m_vBarCoordsLocal.SetZ(w); info.m_vBarCoordsGlobal = info.m_vBarCoordsLocal; if (GetSettings()->m_bNormalSmoothing) { info.m_vNormal = GetSmoothedNormal(barCoord); } else { // info.m_vNormal = GetSmoothedNormal(barCoord); info.m_vNormal = CVector3DF::Normal(dBu, dBv); } if (bDebug) { qDebug()<< "Patch Hit!"; } return true; }
bool CTriangleMesh::Hit(CRay const& ray, CIntersection & intersection) const { // Вычисляем обратно преобразованный луч (вместо вполнения прямого преобразования объекта) CRay invRay = Transform(ray, GetInverseTransform()); CVector3d const& invRayStart = invRay.GetStart(); CVector3d const& invRayDirection = invRay.GetDirection(); ////////////////////////////////////////////////////////////////////////// // Здесь следует выполнить проверку на пересечение луча с ограничивающим // объемом (bounding volume) полигональной сетки. // При отсутствии такого пересечения луч гарантированно не будет пересекать // ни одну из граней сетки, что позволит избежать лишних проверок: // if (!ray_intesects_bounding_volume) // return false; ////////////////////////////////////////////////////////////////////////// // Получаем информацию о массиве треугольников сетки CTriangle const* const triangles = m_pMeshData->GetTriangles(); const size_t numTriangles = m_pMeshData->GetTriangleCount(); // Массив найденных пересечений луча с гранями сетки. std::vector<FaceHit> faceHits; ////////////////////////////////////////////////////////////////////////// // Используется поиск пересечения луча со всеми гранями сетки. // Данный подход является очень неэффективным уже на полигональных сетках, // содержащих более нескольких десятков граней, а, тем более, сотни и тысячи граней. // // Для эффективного поиска столкновений следует представить полигональную сетку // не в виде массива граней, а в виде древовидной структуры (Oct-Tree или BSP-Tree), // что уменьшит вычислительную сложность поиска столкновений с O(N) до O(log N) ////////////////////////////////////////////////////////////////////////// FaceHit hit; for (size_t i = 0; i < numTriangles; ++i) { CTriangle const& triangle = triangles[i]; // Проверка на пересечение луча с треугольной гранью if (triangle.HitTest(invRayStart, invRayDirection, hit.hitTime, hit.hitPointInObjectSpace, hit.w0, hit.w1, hit.w2)) { // Сохраняем индекс грани и добавляем информацию в массив найденных пересечений hit.faceIndex = i; if (faceHits.empty()) { // При обнаружени первого пересечения резервируем // память сразу под 8 пересечений (для уменьшения количества операций выделения памяти) faceHits.reserve(8); } faceHits.push_back(hit); } } // При отсутствии пересечений выходим if (faceHits.empty()) { return false; } ////////////////////////////////////////////////////////////////////////// // Упорядочиваем найденные пересечения по возрастанию времени столкновения ////////////////////////////////////////////////////////////////////////// size_t const numHits = faceHits.size(); std::vector<FaceHit const *> hitPointers(numHits); { // Инициализируем массив указателей на точки пересечения for (size_t i = 0; i < numHits; ++i) { hitPointers[i] = &faceHits[i]; } // Сортируем массив указателей по возрастанию времени столкновения // Сортируются указатели, а не сами объекты, чтобы сократить // издержки на обмен элементов массива: // На 32 битной платформе размер структуры FaceHit равен 64 байтам, // а размер указателя - всего 4 байта. if (numHits > 1) { std::sort(hitPointers.begin(), hitPointers.end(), HitPointerComparator()); // Теперь указатели в массиве hitPointers отсортированы // в порядке возрастания времени столкновения луча с гранями } } ////////////////////////////////////////////////////////////////////////// // Возвращаем информацию о найденных пересечениях ////////////////////////////////////////////////////////////////////////// for (size_t i = 0; i < numHits; ++i) { // Получаем информацию о столкновении FaceHit const& faceHit = *hitPointers[i]; // Сохраняем информацию только о первом пересечении if (i == 0) { ExtendedHitData *hd = (ExtendedHitData*)&m_lastHitData; hd->faceIndex = faceHit.faceIndex; hd->vc[0] = static_cast<float>(faceHit.w0); hd->vc[1] = static_cast<float>(faceHit.w1); hd->vc[2] = static_cast<float>(faceHit.w2); } // Точка столкновения в мировой системе координат CVector3d hitPoint = ray.GetPointAtTime(faceHit.hitTime); // Грань, с которой произошло столкновение CTriangle const& triangle = triangles[faceHit.faceIndex]; // Нормаль "плоской грани" во всех точках столкновения равна нормали самой грани CVector3d normalInObjectSpace = triangle.GetPlaneEquation(); if (!triangle.IsFlatShaded()) { // Для неплоских граней выполняется интерполяция нормалей вершин треугольника // с учетом их весовых коэффициентов в точке пересечения Vertex const& v0 = triangle.GetVertex0(); Vertex const& v1 = triangle.GetVertex1(); Vertex const& v2 = triangle.GetVertex2(); // Взвешенный вектор нормали normalInObjectSpace = faceHit.w0 * v0.normal + faceHit.w1 * v1.normal + faceHit.w2 * v2.normal; } // Нормаль в мировой системе координат CVector3d normal = GetNormalMatrix() * normalInObjectSpace; // Добавляем информацию о точке пересечения в объект intersection intersection.AddHit( CHitInfo( faceHit.hitTime, *this, hitPoint, faceHit.hitPointInObjectSpace, normal, normalInObjectSpace ) ); } return true; }
// AI for the Spark object in the Tantalus Ray Machine's of ep2 void CSpark::process() { int mx,my,x,y; mx = getXPosition() >> CSF; my = getYPosition() >> CSF; if (state==SPARK_ANIMATE) { sprite = SPARK_BASEFRAME + frame; } else { sprite = BLANKSPRITE; } switch(state) { case SPARK_ANIMATE: if (timer > SPARK_ANIMRATE) { frame++; if (frame > 3) frame = 0; timer = 0; } else timer++; if ( mHealthPoints <= 0 && state == SPARK_ANIMATE ) { playSound(SOUND_SHOT_HIT); // break the glass and blow out the electric arcs mp_Map->setTile(mx - 2, my, 492, true); mp_Map->setTile(mx - 1, my, 546, true); mp_Map->setTile(mx, my, 547, true); mp_Map->setTile(mx + 1, my, 548, true); mp_Map->setTile(mx + 2, my, 492, true); // remove the unneeded dome tiles mp_Map->setTile(mx - 1, my-1, BG_GREY, true); mp_Map->setTile(mx, my-1, BG_GREY, true); mp_Map->setTile(mx + 1, my-1, BG_GREY, true); // break the switch mp_Map->setTile(mx - 3, my + 4, 506, true); // meltdown! state = SPARK_BLOWUP1; timer = 0; blowy = 0; } break; case SPARK_BLOWUP1: // one by one blow out the purple thingies below the device if (timer > SPARK_BLOW_DELAY) { timer = 0; my = my+3+blowy; mp_Map->setTile(mx, my, 505, true); // spawn a ZAP! or a ZOT! CRay *newobject = new CRay(mp_Map, mx<<CSF, my<<CSF, CENTER, DOWN, getSpriteVariantId()); newobject->state = CRay::RAY_STATE_SETZAPZOT; newobject->setOwner(m_type, m_index); gEventManager.add( new EventSpawnObject(newobject) ); playSound(SOUND_SHOT_HIT); blowy++; if (blowy >= 3) { state = SPARK_BLOWUP2; blowx = 0; } } else timer++; break; case SPARK_BLOWUP2: // blow out the glowing cells if (timer > SPARK_BLOW_DELAY) { if (blowx >= 4) { // done blowing up the glowcells // static the targeting display mx = mx - 7; my = my + 2; for(y=0;y<3;y++) { for(x=0;x<3;x++) { mp_Map->setTile(mx+x,my+y,533, true); } } exists = false; return; } timer = 0; mx = mx + blowx + 3; for(y=3;y<6;y++) { //my = my+3+y; //my = my+y; mp_Map->setTile(mx, my+y, 549, true); // spawn a ZAP! or a ZOT! CRay *newobject = new CRay(mp_Map, mx<<CSF, (my+y)<<CSF, CENTER, DOWN, getSpriteVariantId()); newobject->setOwner(m_type ,m_index); newobject->state = CRay::RAY_STATE_SETZAPZOT; playSound(SOUND_SHOT_HIT); gEventManager.add(new EventSpawnObject(newobject)); } blowx++; } else timer++; break; default: break; } // end of state switch for SE_SPARK }
Color Union::rayTrace(CRay ray, int depth, CObject* &_object,IntersectResult*& res) { if(depth>max_depth) return Color::white(); int size = (int)CVector.size(); float distance = 100000000.0f; CObject* primitive_near = NULL; bool visible = true; Color totalColor = Color::black(); CObject* pLight; int num=0; IntersectResult s = IntersectResult::noHit(); for(int i=0;i<size;i++){ CObject* primitive = CVector.at(i); IntersectResult result = primitive->isIntersected(ray); if(result.isHit){ if(result.distance < distance){ s = result; distance = result.distance; primitive_near = result.object; num = i; } } } _object = primitive_near; res = &s; if(primitive_near == NULL) { return Color::black(); } else if(primitive_near->isLight()){ return Color::white(); } else if(!s.front){ cout<<depth<<" "<<s.object->code<<endl; GVector3 v = ray.getDirection(); v = v.normalize(); GVector3 normal = s.normal.normalize(); double cosA = v.dotMul(normal); double sinA = sqrt(1-cosA*cosA); double n = 1.000 / 1.500; //cout<<sinA<<endl; if(sinA >= n){ //cout<<"zhixingle"<<endl; CRay newray; newray.setDirection(normal*(-cosA) + (ray.getDirection() - normal*cosA).normalize()*sinA); newray.setOrigin(s.position + ray.getDirection()*1e-3); CObject* no_use = NULL; IntersectResult* n0=NULL; Color refraction_second = rayTrace(newray,depth+1,no_use,n0); //cout<<refraction_second.r<<" "<<refraction_second.g<<" "<<refraction_second.b<<endl; Color absorbance(0,0,0); if(n0){ Color absorbance = primitive_near->getMaterial()->getColor().multiply(0.15f * ((-1)*n0->distance)); } Color transparancy = Color(exp(absorbance.r),exp(absorbance.g),exp(absorbance.b)); return refraction_second.moderate(transparancy); } else{ double sinB = sinA / n; double cosB = sqrt(1 - sinB*sinB); CRay newray; newray.setDirection(normal*cosB + (v-normal*cosA).normalize()*sinB); newray.setOrigin(s.position + newray.getDirection()*1e-3); //cout<<"Origin:"<<newray.getOrigin().getX()<<" "<<newray.getOrigin().getY()<<" "<<newray.getOrigin().getZ()<<endl; //cout<<"Direction:"<<newray.getDirection().getX()<<" "<<newray.getDirection().getY()<<" "<<newray.getDirection().getZ()<<endl; CObject* no_use = NULL; IntersectResult* n0=NULL; Color refraction_second = rayTrace(newray,depth+1,no_use,n0); //cout<<refraction_second.r<<" "<<refraction_second.g<<" "<<refraction_second.b<<endl; Color absorbance(0,0,0); if(n0){ Color absorbance = primitive_near->getMaterial()->getColor().multiply(0.15f * ((-1)*n0->distance)); } Color transparancy = Color(exp(absorbance.r),exp(absorbance.g),exp(absorbance.b)); return refraction_second.moderate(transparancy); } } else{ GVector3 point; point = ray.getPoint(distance); for(int i=0;i<size;i++){ CObject* primitive = CVector.at(i); if(primitive->isLight()){ pLight = primitive; GVector3 inDir = ((Lamp*) primitive)->getCenter() - point; inDir = inDir.normalize(); CRay line(point+inDir*0.001,inDir); for(int j=0;j<size;j++){ CObject* ano_primitive = CVector.at(j); if(!ano_primitive->isLight() && j!=num){ IntersectResult result = ano_primitive->isIntersected(line); if(result.isHit && result.distance < inDir.getLength()){ visible = false; break; } } } break; } } } GVector3 point; point = ray.getPoint(distance); if(visible){ GVector3 lig = ((Lamp*)pLight)->getCenter() - point; lig = lig.normalize(); primitive_near->getMaterial()->setLightDir(lig); totalColor = totalColor.add( primitive_near->getMaterial()->sample(ray, point, primitive_near->getNormal(point)) ); } float reflection = primitive_near->getMaterial()->getRef(); if( (reflection>0.0f) && (depth<max_depth) ){ GVector3 normal_point = primitive_near->getNormal(point); normal_point = normal_point.normalize(); float s0 = ray.getDirection().dotMul(normal_point) * (-2.0f); CRay newRay; newRay.setDirection(normal_point * s0 + ray.getDirection()); newRay.setOrigin(point + newRay.getDirection()*1e-3); CObject* no_use = NULL; IntersectResult* n0=NULL; Color reflectionColor = rayTrace(newRay,depth+1,no_use,n0); reflectionColor = reflectionColor.multiply(reflection); //reflectionColor = reflectionColor.moderate(primitive_near->getMaterial()->getColor()); totalColor = totalColor.add(reflectionColor.moderate(primitive_near->getMaterial()->getColor())); } float refraction = primitive_near->getMaterial()->getRefr(); //cout<<refraction<<endl; if((refraction>0.0f) && (depth<max_depth)){ GVector3 normal_point = primitive_near->getNormal(point); GVector3 Direction = ray.getDirection().normalize(); normal_point = normal_point.normalize(); float cosA = -Direction.dotMul(normal_point); float sinA = sqrt(1-cosA*cosA); float sinB = sinA / 1.5; float cosB = sqrt(1 - sinB*sinB); //cout<<sinA<<" "<<cosA<<" "<<sinB<<" "<<cosB<<endl; CRay newray; newray.setDirection(normal_point*(-cosB) + (Direction + normal_point*cosA).normalize()*sinB); newray.setOrigin(point + newray.getDirection() * 1e-3); CObject* no_use = NULL; IntersectResult* n0=NULL; Color refractionColor = rayTrace(newray,depth+1,no_use,n0); refractionColor = refractionColor.multiply(refraction); //refractionColor = refractionColor.moderate(primitive_near->getMaterial()->getColor()); totalColor = totalColor.add(refractionColor); } return totalColor; }
bool CCone::trace(CRay ray, float& t) { static float R = r1,//max(r1,r2), r = r2;//min(r1,r2); CRay Ray = TransferToCanonical(ray); SavedEyeRay = ray; float Dirx = Ray._2.m[0], Diry = Ray._2.m[2], Dirz = Ray._2.m[1], Eyex = Ray._1.m[0], Eyey = Ray._1.m[2], Eyez = Ray._1.m[1], s = r / R, k = s - 1, d = k*Dirz, f = 1 + k*Eyez, A = Dirx*Dirx + Diry*Diry - d*d, B = (Eyex*Dirx + Eyey*Diry - f*d) * 2, C = Eyex*Eyex + Eyey*Eyey - f*f; float D = B*B - 4.0f*A*C; if (D >= 0) //бокова¤ поверхность { t = (-B - sqrtf(D)) / (2.0f*A); fl3 P = Ray.getPoint(t); if (t < 0) return false; fl3 Vscale = fl3(R, h, R), P1 = (Ray._1) ^ Vscale, P2 = P ^ Vscale; float norm1 = norm(P1 - P2); float norm2 = norm(ray._2); t = norm1 / norm2; SavedPoint = TransferToCanonical(ray.getPoint(t)); SavedNormal = normalize(fl3(SavedPoint.m[0], (R - r) / h, SavedPoint.m[2])); if (P.m[1] <= 1 && P.m[1] >= 0) return true; } float t1 = -Eyez / Dirz, //нижнее основание t2 = t1 + 1.0f / Dirz; //верхнее t = min(t1, t2); fl3 P = Ray.getPoint(t); if (t < 0) return false; fl3 Vscale = fl3(R, h, R), P1 = (Ray._1) ^ Vscale, P2 = P ^ Vscale; float norm1 = norm(P1 - P2); float norm2 = norm(ray._2); t = norm1 / norm2; SavedPoint = TransferToCanonical(ray.getPoint(t)); float px = P.m[0], py = P.m[2]; if (t1 < t2) { SavedNormal = fl3(0, -1, 0); return (px*px + py*py <= 1); } else { SavedNormal = fl3(0, 1, 0); return (px*px + py*py <= s*s); } }