// intersects the scene and return for any intersection bool intersect_shadow(Scene* scene, ray3f ray) { // foreach surface for(auto surface : scene->surfaces) { // if it is a quad if(surface->isquad) { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect quad if(intersect_quad(tray, surface->radius)) return true; } else { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect sphere if(intersect_sphere(tray, surface->radius)) return true; } } // foreach mesh for(auto mesh : scene->meshes) { // quads are not supported: check for error error_if_not(mesh->quad.empty(), "quad intersection is not supported"); // tranform the ray auto tray = transform_ray_inverse(mesh->frame, ray); // if it is accelerated if(mesh->bvh) { if(intersect_shadow(mesh->bvh, 0, tray, [mesh](int tid, ray3f tray){ // grab triangle auto triangle = mesh->triangle[tid]; // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // return if intersected return intersect_triangle(tray, v0, v1, v2);})) return true; } else { // foreach triangle for(auto triangle : mesh->triangle) { // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // intersect triangle if(intersect_triangle(tray, v0, v1, v2)) return true; } } } // no intersection found return false; }
// Performs an intersection test between a ray and the given mesh part // and stores the result in "point". bool intersect(const Vector3& rayOrigin, const Vector3& rayDirection, const std::vector<Vertex>& vertices, const std::vector<MeshPart*>& parts, Vector3* point) { const float* orig = &rayOrigin.x; const float* dir = &rayDirection.x; for (unsigned int i = 0, partCount = parts.size(); i < partCount; ++i) { MeshPart* part = parts[i]; for (unsigned int j = 0, indexCount = part->getIndicesCount(); j < indexCount; j += 3) { const float* v0 = &vertices[part->getIndex( j )].position.x; const float* v1 = &vertices[part->getIndex(j+1)].position.x; const float* v2 = &vertices[part->getIndex(j+2)].position.x; float t, u, v; if (intersect_triangle(orig, dir, v0, v1, v2, &t, &u, &v)) { // Found an intersection! if (point) { Vector3 rd(rayDirection); rd.scale(t); Vector3::add(rayOrigin, rd, point); } return true; } } } return false; }
// Performs an intersection test between a ray and the given mesh part and stores the result in "point". bool intersect(const Vector3& rayOrigin, const Vector3& rayDirection, const std::vector<Vertex>& vertices, const std::vector<MeshPart*>& parts, Vector3* point) { const float* orig = &rayOrigin.x; const float* dir = &rayDirection.x; float minT = FLT_MAX; for (unsigned int i = 0, partCount = parts.size(); i < partCount; ++i) { MeshPart* part = parts[i]; for (unsigned int j = 0, indexCount = part->getIndicesCount(); j < indexCount; j += 3) { const float* v0 = &vertices[part->getIndex( j )].position.x; const float* v1 = &vertices[part->getIndex(j+1)].position.x; const float* v2 = &vertices[part->getIndex(j+2)].position.x; // Perform a quick check (in 2D) to determine if the point is definitely NOT in the triangle float xmin, xmax, zmin, zmax; xmin = v0[0] < v1[0] ? v0[0] : v1[0]; xmin = xmin < v2[0] ? xmin : v2[0]; xmax = v0[0] > v1[0] ? v0[0] : v1[0]; xmax = xmax > v2[0] ? xmax : v2[0]; zmin = v0[2] < v1[2] ? v0[2] : v1[2]; zmin = zmin < v2[2] ? zmin : v2[2]; zmax = v0[2] > v1[2] ? v0[2] : v1[2]; zmax = zmax > v2[2] ? zmax : v2[2]; if (orig[0] < xmin || orig[0] > xmax || orig[2] < zmin || orig[2] > zmax) continue; // Perform a full ray/traingle intersection test in 3D to get the intersection point float t, u, v; if (intersect_triangle(orig, dir, v0, v1, v2, &t, &u, &v)) { // Found an intersection! if (t < minT) { minT = t; if (point) { Vector3 rd(rayDirection); rd.scale(t); Vector3::add(rayOrigin, rd, point); } } //return true; } } } return (minT != FLT_MAX);//false; }
void Surf::IntersectLineSegMesh( vec3d & p0, vec3d & p1, vector< double > & t_vals ) { BndBox line_box; line_box.Update( p0 ); line_box.Update( p1 ); if ( !Compare( line_box, m_BBox ) ) { return; } double tparm, uparm, vparm; list< Tri* >::iterator t; list <Tri*> triList = m_Mesh.GetTriList(); vec3d dir = p1 - p0; for ( t = triList.begin() ; t != triList.end(); t++ ) { int iFlag = intersect_triangle( p0.v, dir.v, ( *t )->n0->pnt.v, ( *t )->n1->pnt.v, ( *t )->n2->pnt.v, &tparm, &uparm, &vparm ); if ( iFlag && tparm > 0.0 ) { //==== Find If T is Already Included ====// int dupFlag = 0; for ( int j = 0 ; j < ( int )t_vals.size() ; j++ ) { if ( fabs( tparm - t_vals[j] ) < 0.0000001 ) { dupFlag = 1; break; } } if ( !dupFlag ) { t_vals.push_back( tparm ); } } } }
bool KDTree::intersectRay(int nodeIndex, const Ray& localRay, float& oDistance) { float boxNear, boxFar; if(!mNodes[nodeIndex].mBounds.intersect(localRay, boxNear, boxFar)) return false; float distance; for(int iTri = mNodes[nodeIndex].mTriStart; iTri < (mNodes[nodeIndex].mTriStart + mNodes[nodeIndex].mTriNum); ++iTri) { KDTriangle& triangle = mTriangles[iTri]; if(intersect_triangle(localRay, triangle, distance)) { oDistance = distance; return true; } } for(unsigned int iChild = 0; iChild < KDTREE_CHILDREN; ++iChild) { if(mNodes[nodeIndex].mChildren[iChild] != 0 && intersectRay(mNodes[nodeIndex].mChildren[iChild], localRay, oDistance)) return true; } return false; }
// intersects the scene and return the first intrerseciton intersection3f intersect(Scene* scene, ray3f ray) { // create a default intersection record to be returned auto intersection = intersection3f(); // foreach surface for(auto surface : scene->surfaces) { // if it is a quad if(surface->isquad) { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect quad auto t = 0.0f; auto p = zero3f; auto hit = intersect_quad(tray, surface->radius, t, p); // skip if not hit if(not hit) continue; // check if this is the closest intersection, continue if not if(t > intersection.ray_t and intersection.hit) continue; // if hit, set intersection record values intersection.hit = true; intersection.ray_t = t; intersection.pos = transform_point(surface->frame,p); intersection.norm = transform_normal(surface->frame,z3f); intersection.texcoord = {0.5f*p.x/surface->radius+0.5f,0.5f*p.y/surface->radius+0.5f}; intersection.mat = surface->mat; } else { // compute ray intersection (and ray parameter), continue if not hit auto tray = transform_ray_inverse(surface->frame,ray); // intersect sphere auto t = 0.0f; auto hit = intersect_sphere(tray, surface->radius, t); // skip if not hit if(not hit) continue; // check if this is the closest intersection, continue if not if(t > intersection.ray_t and intersection.hit) continue; // compute local point and normal auto p = tray.eval(t); auto n = normalize(p); // if hit, set intersection record values intersection.hit = true; intersection.ray_t = t; intersection.pos = transform_point(surface->frame,p); intersection.norm = transform_normal(surface->frame,n); intersection.texcoord = {(pif+(float)atan2(n.y, n.x))/(2*pif),(float)acos(n.z)/pif}; intersection.mat = surface->mat; } } // foreach mesh for(auto mesh : scene->meshes) { // quads are not supported: check for error error_if_not(mesh->quad.empty(), "quad intersection is not supported"); // tranform the ray auto tray = transform_ray_inverse(mesh->frame, ray); // save auto mesh intersection auto sintersection = intersection3f(); // if it is accelerated if(mesh->bvh) { sintersection = intersect(mesh->bvh, 0, tray, [mesh](int tid, ray3f tray){ // grab triangle auto triangle = mesh->triangle[tid]; // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // intersect triangle auto t = 0.0f, u = 0.0f, v = 0.0f; auto hit = intersect_triangle(tray, v0, v1, v2, t, u, v); // skip if not hit if(not hit) return intersection3f(); // if hit, set up intersection, trasforming hit data to world space auto sintersection = intersection3f(); sintersection.hit = true; sintersection.ray_t = t; sintersection.pos = tray.eval(t); sintersection.norm = normalize(mesh->norm[triangle.x]*u+ mesh->norm[triangle.y]*v+ mesh->norm[triangle.z]*(1-u-v)); if(mesh->texcoord.empty()) sintersection.texcoord = zero2f; else { sintersection.texcoord = mesh->texcoord[triangle.x]*u+ mesh->texcoord[triangle.y]*v+ mesh->texcoord[triangle.z]*(1-u-v); } sintersection.mat = mesh->mat; return sintersection; }); } else { // clear intersection sintersection = intersection3f(); // foreach triangle for(auto triangle : mesh->triangle) { // grab vertices auto v0 = mesh->pos[triangle.x]; auto v1 = mesh->pos[triangle.y]; auto v2 = mesh->pos[triangle.z]; // intersect triangle auto t = 0.0f, u = 0.0f, v = 0.0f; auto hit = intersect_triangle(tray, v0, v1, v2, t, u, v); // skip if not hit if(not hit) continue; // check if closer then the found hit if(t > sintersection.ray_t and sintersection.hit) continue; // if hit, set up intersection, trasforming hit data to world space sintersection.hit = true; sintersection.ray_t = t; sintersection.pos = tray.eval(t); sintersection.norm = normalize(mesh->norm[triangle.x]*u+ mesh->norm[triangle.y]*v+ mesh->norm[triangle.z]*(1-u-v)); if(mesh->texcoord.empty()) sintersection.texcoord = zero2f; else { sintersection.texcoord = mesh->texcoord[triangle.x]*u+ mesh->texcoord[triangle.y]*v+ mesh->texcoord[triangle.z]*(1-u-v); } sintersection.mat = mesh->mat; } } // if did not hit the mesh, skip if(not sintersection.hit) continue; // check not first intersection, skip if(sintersection.ray_t > intersection.ray_t and intersection.hit) continue; // set interserction intersection = sintersection; // transform by mesh frame intersection.pos = transform_point(mesh->frame,sintersection.pos); intersection.norm = transform_normal(mesh->frame,sintersection.norm); // set material intersection.mat = sintersection.mat; } // record closest intersection return intersection; }
// intersect triangle without returning bounds inline bool intersect_triangle(const ray3f& ray, const vec3f& v0, const vec3f& v1, const vec3f& v2) { float t, u, v; return intersect_triangle(ray, v0, v1, v2, t, u, v); }
bool ModelGetIsVertexHitLineDirection(Model* model, Vector3D origin, Vector3D direction, Vector3D* hitVector, Vector3D* hitVectorGlobal) { Matrix3D modelMatrix; //현재 매트릭스 가져오기 glGetFloatv(GL_MODELVIEW_MATRIX, (float*)&modelMatrix); Vector3D triangleVector[3]; Vector3D collosion[3]; Vector3D* vertex = model->hitVertex; for(int i = 0; i < model->hitTrianglePolygonLength; i++) { if(i == 0) { triangleVector[0] = vertex[0]; triangleVector[1] = vertex[1]; triangleVector[2] = vertex[2]; vertex += 3; } else { if(model->isTriangleFanMode) { triangleVector[0] = model->hitVertex[0]; triangleVector[1] = triangleVector[2]; triangleVector[2] = vertex[0]; } else { triangleVector[0] = triangleVector[1]; triangleVector[1] = triangleVector[2]; triangleVector[2] = vertex[0]; } vertex += 1; } collosion[0] = Matrix3DMultiplyVector3D(modelMatrix, triangleVector[0]); collosion[1] = Matrix3DMultiplyVector3D(modelMatrix, triangleVector[1]); collosion[2] = Matrix3DMultiplyVector3D(modelMatrix, triangleVector[2]); double ta, tb, tc; double ori[3], dir[3], va[3], vb[3], vc[3]; ori[0] = (double)origin.x; dir[0] = (double)direction.x; va[0] = (double)collosion[0].x; vb[0] = (double)collosion[1].x; vc[0] = (double)collosion[2].x; ori[1] = (double)origin.y; dir[1] = (double)direction.y; va[1] = (double)collosion[0].y; vb[1] = (double)collosion[1].y; vc[1] = (double)collosion[2].y; ori[2] = (double)origin.z; dir[2] = (double)direction.z; va[2] = (double)collosion[0].z; vb[2] = (double)collosion[1].z; vc[2] = (double)collosion[2].z; bool hit = intersect_triangle(ori, dir, va, vb, vc, &ta, &tb, &tc); if(hitVector || hitVectorGlobal) { Vector3D collisionVector = Vector3DInit(origin.x + (direction.x * ta), origin.y + (direction.y * ta), origin.z + (direction.z * ta)); if(hitVectorGlobal) { *hitVectorGlobal = Vector3DInit(collisionVector.x, collisionVector.y, collisionVector.z); } if(hitVector) { Vector3D collisionVectorOfModel = Matrix3DMultiplyVector3D(Matrix3DInverte(modelMatrix), collisionVector); *hitVector = Vector3DInit(collisionVectorOfModel.x, collisionVectorOfModel.y, collisionVectorOfModel.z); } } if(hit) return hit; } return false; }
/****************************************** * Performs ambient occlusion on vertices * ******************************************/ void objAmbientOcclusion(object *obj) { int i; int j; int k = 0; int r; float ray_num; float ray_hit; double vert1[3]; double vert2[3]; double vert3[3]; double orig[3]; double dir[3]; double norm[3]; float light[] = {4,3,-2}; float mag; int current_mesh = 0; int current_mat = 0; int current_vertex = 0; int current_normal = 0; int current_face = 0; int test_mesh; int test_face; mesh *meshp; mesh *tmeshp; face *facep; face *tfacep; vertex *vertp; point3 *normp; double b[3]; double ot; double ou; double ov; // boobs (also, normalize the light vector) mag = sqrt(light[0]*light[0]+ light[1]*light[1]+ light[2]*light[2]); light[0] /= mag; light[1] /= mag; light[2] /= mag; printf("Ambient occlusion"); // perform AO for(current_mesh = 0; current_mesh < obj->numMeshes; current_mesh++) { meshp = &obj->meshes[current_mesh]; if(strstr(meshp->name, "_noao") == NULL){ //for(current_face = 0; current_face < meshp->numFaces; current_face++) //{ for(current_vertex = 0; current_vertex < meshp->numVertices; current_vertex++) { if((current_vertex & 2) == 2) printf("\rMesh %d/%d\t\t%d percent completed ", current_mesh+1, obj->numMeshes, lroundf(((float)(current_vertex)/(float)(meshp->numVertices)) * 100.0f)); //facep = &meshp->faces[current_face]; //vertp = &meshp->vertices[current_vertex]; //vertp = &meshp->vertices[facep->v[current_vertex]-1]; //normp = &meshp->normals[facep->vn[current_vertex]-1]; vertp = &meshp->vertices[current_vertex]; // now cast a shitload of rays out randomly from the point, towards the normal(ish) ray_num = 0; ray_hit = 0; for(r = 0; r < 300; r++) { ray_num++; // make this ray start at the current vertex // bias in the direction of the normal orig[0] = vertp->x + vertp->nx * 0.0001; orig[1] = vertp->y + vertp->ny * 0.0001; orig[2] = vertp->z + vertp->nz * 0.0001; norm[0] = vertp->nx; norm[1] = vertp->ny; norm[2] = vertp->nz; // generate a random vector inside the unit sphere while(1){ dir[0] = ( (double)rand() / ((double)(RAND_MAX)+(double)(1)) )*2.0f-1.0f; dir[1] = ( (double)rand() / ((double)(RAND_MAX)+(double)(1)) )*2.0f-1.0f; dir[2] = ( (double)rand() / ((double)(RAND_MAX)+(double)(1)) )*2.0f-1.0f; if(sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]) <= 1.0f) break; } if(DOT(norm, dir) < 0.0f){ dir[0] *= -1; dir[1] *= -1; dir[2] *= -1; } // test this ray against every other single goddamn triangle for(test_mesh = 0; test_mesh < obj->numMeshes; test_mesh++) { tmeshp = &obj->meshes[test_mesh]; // go through each triangle for(test_face = 0; test_face < tmeshp->numFaces; test_face++) { tfacep = &tmeshp->faces[test_face]; vert1[0] = tmeshp->vertices[tfacep->v[0]-1].x; vert1[1] = tmeshp->vertices[tfacep->v[0]-1].y; vert1[2] = tmeshp->vertices[tfacep->v[0]-1].z; vert2[0] = tmeshp->vertices[tfacep->v[1]-1].x; vert2[1] = tmeshp->vertices[tfacep->v[1]-1].y; vert2[2] = tmeshp->vertices[tfacep->v[1]-1].z; vert3[0] = tmeshp->vertices[tfacep->v[2]-1].x; vert3[1] = tmeshp->vertices[tfacep->v[2]-1].y; vert3[2] = tmeshp->vertices[tfacep->v[2]-1].z; if(intersect_triangle(orig, dir, vert1, vert2, vert3, &ot, &ou, &ov) == 1) { // hit! if(ot > -0.0001) { ray_hit++; goto next_ray; } } } } next_ray: ov = 0; } // done testing all rays vertp->b = 255 - (ray_hit / ray_num) * 255 ; i = DOT(norm, light)*64+128; if(i> 255) i = 255; if(i <0) i = 0; // vertp->b = i>vertp->b ? vertp->b : i; } printf("\rMesh %d/%d\t\t100 percent completed ", current_mesh+1, obj->numMeshes); } } printf("\n\n"); }