void ogl::mesh::cache_verts(const ogl::mesh *that, const mat4& M, const mat4& I, int id) { const size_t n = that->vv.size(); // Cache that mesh's transformed vertices here. Update bounding volume. vv.resize(n); nv.resize(n); tv.resize(n); uv.resize(n); bound = aabb(); for (size_t i = 0; i < n; ++i) { transform_vertex(vv[i].v, M, that->vv[i].v); transform_normal(nv[i].v, transpose(I), that->nv[i].v); transform_normal(tv[i].v, transpose(I), that->tv[i].v); bound.merge(vec3(double(vv[i].v[0]), double(vv[i].v[1]), double(vv[i].v[2]))); // Handy trick: Store the unit ID in the texture coordinate. uv[i].v[0] = that->uv[i].v[0]; uv[i].v[1] = that->uv[i].v[1]; uv[i].v[2] = GLfloat(id); } dirty_verts = true; }
void RunFloat2Or3Tests(std::string const& typeName) { RunCommonVectorTests<T>(typeName); RunPerfTest<T, T>(typeName + " reflect", [](T* value, T const& param) { *value = reflect(*value, param); }); RunPerfTest<T, float4x4>(typeName + " transform_normal (float4x4)", [](T* value, float4x4 const& param) { *value = transform_normal(*value, param); }); RunPerfTest<T, float4x4>(typeName + " transform4 (float4x4)", [](T* value, float4x4 const& param) { float4 t = transform4(*value, param); value->x = t.x + t.y + t.z + t.w; }); RunPerfTest<T, quaternion>(typeName + " transform4 (quaternion)", [](T* value, quaternion const& param) { float4 t = transform4(*value, param); value->x = t.x + t.y + t.z + t.w; }); }
void RunFloat2Tests() { RunFloat2Or3Tests<float2>("float2"); RunPerfTest<float2, float3x2>("float2 transform (float3x2)", [](float2* value, float3x2 const& param) { *value = transform(*value, param); }); RunPerfTest<float2, float3x2>("float2 transform_normal (float3x2)", [](float2* value, float3x2 const& param) { *value = transform_normal(*value, param); }); }
// \en Calculates intersections. Stores intersection info to intersections and returns the number of intersections.\enden \ja 交点計算を行う。交点の情報はintersectionsに格納し、交点の数を返す。 \endja // \en The ray is defined as the starting point o and the normalized direction vector d as in o + td, 0.0 <= t.\enden \ja レイは始点位置ベクトルo、単位方向ベクトルdから成る、o + td, 0.0 <= t として指定される。 \endja int attribute_component::ray_intersection (const sxsdk::custom_element_info_base_class *info, sxsdk::shape_class &shape, const sxsdk::mat4 &lw, const sxsdk::mat4 &wl, int i, const sx::vec<float,3> &o, const sx::vec<float,3> &d, sxsdk::intersection_class intersections[], sxsdk::custom_element_info_base_class *per_thread, void *) { { custom_element_info__class *info = dynamic_cast<custom_element_info__class *>(per_thread); if (info) { for (int i = 0; i < 100; i++) info->data[i] = i; } } int n = 0; sxsdk::sphere_class &sphere = shape.get_sphere(); if (info) { // \en Fetch the data created in the new_custom_element_info function.\enden \ja new_custom_element_infoで作成したデータを取得する。 \endja const float size = dynamic_cast<const custom_size_class &>(*info).size; sxsdk::mat4 t = sphere.get_matrix(); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) t[i][j] *= size; t *= lw; sxsdk::mat4 itrans = inv(t); sx::vec<float,3> p2 = o * itrans; // \en Transform the starting point of the ray to the sphere primitive coordinates.\enden \ja レイの始点位置ベクトルを球プリミティブ座標系に変換する。 \endja sx::vec<float,3> d2 = transform_direction(d, itrans); // \en Transform the normalized direction vector of the ray to the sphere primitive coordinates.\enden \ja レイの単位方向ベクトルを球プリミティブ座標系に変換する。 \endja // \en Calculate the intersections between the sphere and the ray.\enden \ja 球とレイの交点計算。 \endja float a = d2.x * d2.x + d2.y * d2.y + d2.z * d2.z; float b = p2.x * d2.x + p2.y * d2.y + p2.z * d2.z; float c = p2.x * p2.x + p2.y * p2.y + p2.z * p2.z - 1.0f; float k = b*b - a*c; if (k <= 0.0f) ; else { k = sqrt(k); float t1 = (-b + k) / a; float t0 = (-b - k) / a; //sxassert(t0 <= t1); if (0.0f <= t0) { intersections[n].t = t0; sx::vec<float,3> normal = p2 + d2 * t0; intersections[n].normal = normalize(transform_normal(itrans, normal)); intersections[n].point = o + d * t0; // \en Merge Info.\enden \ja 融合情報 \endja if (shape.has_sis()) { intersections[n].number_of_shapes = 2; //sxassert(intersections[n].shape_mixes); intersections[n].shape_mixes[1] = sxsdk::shape_mix_class(0.5f, shape.get_sis()); intersections[n].shape_mixes[0] = sxsdk::shape_mix_class(0.5f, &shape); } n++; } if (0.0f <= t1) { intersections[n].t = t1; sx::vec<float,3> normal = p2 + d2 * t1; intersections[n].normal = normalize(transform_normal(itrans, normal)); intersections[n].point = o + d * t1; // \en Merge Info.\enden \ja 融合情報 \endja if (shape.has_sis()) { intersections[n].number_of_shapes = 2; //sxassert(intersections[n].shape_mixes); intersections[n].shape_mixes[1] = sxsdk::shape_mix_class(0.5f, shape.get_sis()); intersections[n].shape_mixes[0] = sxsdk::shape_mix_class(0.5f, &shape); } n++; } } } return n; }
// 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; }
normal transform::inverse_transform(const normal &n) const { // note we send the transform itself, not its inverse return transform_normal(m_xfrm, n); } // end transform::inverse_transform()
normal transform::operator()(const normal &n) const { // note we send the inverse of the transform return transform_normal(m_inv, n); } // end transform::operator()()