//helper function for ray terrain intersection static bool cellIntersect(float h1, float h2, float h3, float h4, float X, float Y, const WFMath::Vector<3> &nDir, float dirLen, const WFMath::Point<3> &sPt, WFMath::Point<3> &intersection, WFMath::Vector<3> &normal, float &par) { //ray plane intersection roughly using the following: //parametric ray eqn: p=po + par V //plane eqn: p dot N + d = 0 // //intersection: // -par = (po dot N + d ) / (V dot N) // // // effectively we calculate the ray parametric variable for the // intersection of the plane corresponding to each triangle // then clip them by endpints of the ray, and by the sides of the square // and by the diagonal // // if they both still intersect, then we choose the earlier intersection //intersection points for top and bottom triangles WFMath::Point<3> topInt, botInt; //point to use in plane equation for both triangles WFMath::Vector<3> p0 = WFMath::Vector<3>(X, Y, h1); // square is broken into two triangles // top triangle |/ bool topIntersected = false; WFMath::Vector<3> topNormal(h2-h3, h1-h2, 1.0); topNormal.normalize(); float t = Dot(nDir, topNormal); float topP=0.0; if ((t > 1e-7) || (t < -1e-7)) { topP = - (Dot((sPt-WFMath::Point<3>(0.,0.,0.)), topNormal) - Dot(topNormal, p0)) / t; topInt = sPt + nDir*topP; //check the intersection is inside the triangle, and within the ray extents if ((topP <= dirLen) && (topP > 0.0) && (topInt[0] >= X ) && (topInt[1] <= Y + 1 ) && ((topInt[0] - topInt[1]) <= (X - Y)) ) { topIntersected=true; } } // bottom triangle /| bool botIntersected = false; WFMath::Vector<3> botNormal(h1-h4, h4-h3, 1.0); botNormal.normalize(); float b = Dot(nDir, botNormal); float botP=0.0; if ((b > 1e-7) || (b < -1e-7)) { botP = - (Dot((sPt-WFMath::Point<3>(0.,0.,0.)), botNormal) - Dot(botNormal, p0)) / b; botInt = sPt + nDir*botP; //check the intersection is inside the triangle, and within the ray extents if ((botP <= dirLen) && (botP > 0.0) && (botInt[0] <= X + 1 ) && (botInt[1] >= Y ) && ((botInt[0] - botInt[1]) >= (X - Y)) ) { botIntersected = true; } } if (topIntersected && botIntersected) { //intersection with both if (botP <= topP) { intersection = botInt; normal = botNormal; par=botP/dirLen; if (botP == topP) { normal += topNormal; normal.normalize(); } return true; } else { intersection = topInt; normal = topNormal; par=topP/dirLen; return true; } } else if (topIntersected) { //intersection with top intersection = topInt; normal = topNormal; par=topP/dirLen; return true; } else if (botIntersected) { //intersection with bot intersection = botInt; normal = botNormal; par=botP/dirLen; return true; } return false; }
//helper function for ray terrain intersection static bool cellIntersect(float h1, float h2, float h3, float h4, float X, float Y, const std::tuple<float, float, float> &nDir, float dirLen, const WFMath::Point<3> &sPt, WFMath::Point<3> &intersection, std::tuple<float, float, float> &normal, float &par) { //ray plane intersection roughly using the following: //parametric ray eqn: p=po + par V //plane eqn: p dot N + d = 0 // //intersection: // -par = (po dot N + d ) / (V dot N) // // // effectively we calculate the ray parametric variable for the // intersection of the plane corresponding to each triangle // then clip them by endpints of the ray, and by the sides of the square // and by the diagonal // // if they both still intersect, then we choose the earlier intersection //intersection points for top and bottom triangles WFMath::Point<3> topInt, botInt; //point to use in plane equation for both triangles std::tuple<float, float, float> p0 = std::tuple<float, float, float>(X, Y, h1); // square is broken into two triangles // top triangle |/ bool topIntersected = false; std::tuple<float, float, float> topNormal(h2 - h3, h1 - h2, 1.0); normalise_i(topNormal); float t = dot(nDir, topNormal); decltype(t) topP = 0.0; if ((t > 1e-7) || (t < -1e-7)) { topP = -(dot(std::tuple<float, float, float>(sPt[0], sPt[1], sPt[2]), topNormal) - dot(topNormal, p0)) / t; topInt = translate(sPt, scale(nDir, topP)); //check the intersection is inside the triangle, and within the ray extents if ((topP <= dirLen) && (topP > 0.0) && (topInt[0] >= X ) && (topInt[1] <= Y + 1 ) && ((topInt[0] - topInt[1]) <= (X - Y)) ) { topIntersected = true; } } // bottom triangle /| bool botIntersected = false; std::tuple<float, float, float> botNormal(h1 - h4, h4 - h3, 1.0); normalise_i(botNormal); auto b = dot(nDir, botNormal); decltype(b) botP = 0.0; if ((b > 1e-7) || (b < -1e-7)) { botP = -(dot(std::tuple<float, float, float>(sPt[0], sPt[1], sPt[2]), botNormal) - dot(botNormal, p0)) / b; botInt = translate(sPt, scale(nDir, botP)); //check the intersection is inside the triangle, and within the ray extents if ((botP <= dirLen) && (botP > 0.0) && (botInt[0] <= X + 1 ) && (botInt[1] >= Y ) && ((botInt[0] - botInt[1]) >= (X - Y)) ) { botIntersected = true; } } if (topIntersected && botIntersected) //intersection with both { if (botP <= topP) { intersection = botInt; normal = botNormal; par = botP / dirLen; if (botP == topP) { add_i(normal, topNormal); normalise_i(normal); } return true; } else { intersection = topInt; normal = topNormal; par = topP / dirLen; return true; } } else if (topIntersected) //intersection with top { intersection = topInt; normal = topNormal; par = topP / dirLen; return true; } else if (botIntersected) //intersection with bot { intersection = botInt; normal = botNormal; par = botP / dirLen; return true; } return false; }