IGME_waypoint_t* ME_GetWaypointUnderCrosshair() { vec3_t mins, maxs, dir; float dist, closestDist = MAX_SELECTION_DISTANCE; IGME_waypoint_t* selwpt = 0; IGME_waypoint_t* wpt = 0; box3_t bbox; ray3_t ray; int i; IGME_vehicle_t* selveh = ME_GetSelectedVehicle(); vec3_t wmins = { -25, -25, -25 }, wmaxs = { 25, 25, 25 }; if( !selveh ) return 0; VectorCopy( cg.predictedPlayerState.origin, ray.start ); AngleVectors( cg.predictedPlayerState.viewangles, ray.dir, 0, 0 ); VectorScale( ray.dir, MAX_SELECTION_DISTANCE, ray.dir ); for( i = 0; i < IGME_MAX_WAYPOINTS; ++i ) { wpt = &selveh->waypoints[i]; // not active if( !wpt->active ) continue; VectorSubtract( wpt->origin, ray.start, dir ); dist = VectorNormalize( dir ); // too far away if( dist > closestDist ) continue; VectorAdd( wmins, wpt->origin, mins ); VectorAdd( wmaxs, wpt->origin, maxs ); MakeBoxFromExtents(&bbox, mins, maxs, vec3_origin); if( RayIntersectBox(&ray, &bbox) ) { closestDist = dist; selwpt = wpt; } } return selwpt; }
IGME_vehicle_t* ME_GetVehicleUnderCrosshair() { vec3_t mins, maxs, dir; float dist, closestDist = MAX_SELECTION_DISTANCE; IGME_vehicle_t* selveh = 0; IGME_vehicle_t* veh = 0; box3_t bbox; ray3_t ray; int i; VectorCopy( cg.predictedPlayerState.origin, ray.start ); AngleVectors( cg.predictedPlayerState.viewangles, ray.dir, 0, 0 ); VectorScale( ray.dir, MAX_SELECTION_DISTANCE, ray.dir ); for( i = 0; i < IGME_MAX_VEHICLES; ++i ) { veh = &cgs.IGME.vehicles[i]; // not active if( !veh->active ) continue; VectorSubtract( veh->origin, ray.start, dir ); dist = VectorNormalize( dir ); // too far away if( dist > closestDist ) continue; if( veh->groundInstallation ) { VectorAdd( availableGroundInstallations[veh->vehidx].mins, veh->origin, mins ); VectorAdd( availableGroundInstallations[veh->vehidx].maxs, veh->origin, maxs ); } else { VectorAdd( availableVehicles[veh->vehidx].mins, veh->origin, mins ); VectorAdd( availableVehicles[veh->vehidx].maxs, veh->origin, maxs ); } MakeBoxFromExtents(&bbox, mins, maxs, veh->angles); if( RayIntersectBox(&ray, &bbox) ) { closestDist = dist; selveh = veh; } } return selveh; }
/*************** 进行光线跟踪 *******************/ void RayThread::traceRay(RayVector start, RayVector direction, int depth, RayColor &color, bool isInside) { RayVector interPoint, refDirection, completeRefDirection, transDirection; RayColor localColor, refColor, completeRefColor, transColor; if (depth > maxDepth) // 递归层数超过限制 { color.setR(0.0); color.setG(0.0); color.setB(0.0); } else { int objIndex, faceIndex; int objIndex1, faceIndex1; double T, T1; bool result = false, result1 = false, isPoly = false; RayColor useless; if (!m_bUseBSP) // 不使用BSP加速 { result = findNearestPoly(start, direction, T, objIndex, faceIndex, true, isInside, useless); result1 = findNearestSphere(start, direction, T1, objIndex1, faceIndex1, true, isInside, useless); isPoly = true; if (result && result1) { if (T1 < T) { T = T1; isPoly = false; objIndex = objIndex1; faceIndex = faceIndex1; } } else if (!result && result1) { T = T1; isPoly = false; objIndex = objIndex1; faceIndex = faceIndex1; } result = result || result1; } else // 使用BSP加速 { double tMin = 0.0, tMax = 0.0; /* 与最大包围盒相交才需要计算其内部相交情况,否则直接断定无交点 */ if (RayIntersectBox(start, direction, tMin, tMax)) { result = findNearestPointBSP(start, direction, T, objIndex, faceIndex, tMin, tMax, bspTree, isPoly, true, useless); } else { result = false; } } if (!result) // 无交点 { color.setR(0.0); color.setG(0.0); color.setB(0.0); } else { RayColor ks, kt, ksTrans(0.0, 0.0, 0.0), transRefColor(0.0, 0.0, 0.0); RayVector N; bool isSpecular, isTransparent; interPoint = start + direction * T; shade(objIndex, faceIndex, interPoint, localColor, isPoly, N, ks, isSpecular, isTransparent); if (isSpecular) // 交点所在的表面为镜面 { direction.normalize(); refDirection = direction - N * (direction * N) * 2.0; traceRay(interPoint, refDirection, depth + 1, refColor, false); } if (isTransparent) // 交点所在表面为透明面 { double eta; if (isPoly) { eta = objData->objectList[objIndex].faceList[faceIndex].eta(); kt = objData->objectList[objIndex].faceList[faceIndex].kt(); } else { eta = objData->objectList[objIndex].sphereList[faceIndex].eta(); kt = objData->objectList[objIndex].sphereList[faceIndex].kt(); } double cosTheta1, cosTheta2; RayVector L, T; L = -direction; L.normalize(); cosTheta1 = N * L; if (cosTheta1 > 0.0) // 光线从空气射向物体 { cosTheta2 = sqrt(1 - (1 - cosTheta1 * cosTheta1) / (eta * eta)); transDirection = -L / eta - N * (cosTheta2 - cosTheta1 / eta); traceRay(interPoint, transDirection, depth + 1, transColor, true); } else // 光线从物体射向空气 { cosTheta1 *= -1.0; double sinTheta1 = sqrt(1 - cosTheta1 * cosTheta1); double sinThetaMax = 1.0 / eta; // 临界角,入射角大于这个角会发生全反射 ksTrans.setR(sinTheta1 / sinThetaMax); ksTrans.setG(sinTheta1 / sinThetaMax); ksTrans.setB(sinTheta1 / sinThetaMax); //ksTrans = RayColor(0.5, 0.5, 0.5); RayVector transRefDirection = -N * (L * -N) * 2.0 - L; traceRay(interPoint, transRefDirection, depth + 1, transRefColor, true); if ((1.0 - cosTheta1 * cosTheta1) * eta * eta < 1.0) // 不发生全反射,此时需要计算折射 { cosTheta2 = sqrt(1.0 - (1.0 - cosTheta1 * cosTheta1) * eta * eta); transDirection = -L * eta - -N * (cosTheta2 - cosTheta1 * eta); traceRay(interPoint, transDirection, depth + 1, transColor, false); } } } color = localColor + ks * refColor + kt * transColor + ksTrans * transRefColor; } } }