float Camera::world_to_raster_size(float3 P) { if(type == CAMERA_ORTHOGRAPHIC) { return min(len(full_dx), len(full_dy)); } else if(type == CAMERA_PERSPECTIVE) { /* Calculate as if point is directly ahead of the camera. */ float3 raster = make_float3(0.5f*width, 0.5f*height, 0.0f); float3 Pcamera = transform_perspective(&rastertocamera, raster); /* dDdx */ float3 Ddiff = transform_direction(&cameratoworld, Pcamera); float3 dx = len_squared(full_dx) < len_squared(full_dy) ? full_dx : full_dy; float3 dDdx = normalize(Ddiff + dx) - normalize(Ddiff); /* dPdx */ float dist = len(transform_point(&worldtocamera, P)); float3 D = normalize(Ddiff); return len(dist*dDdx - dot(dist*dDdx, D)*D); } else { // TODO(mai): implement for CAMERA_PANORAMA assert(!"pixel width calculation for panoramic projection not implemented yet"); } return 1.0f; }
bool BlenderObjectCulling::test_distance(Scene *scene, float3 bb[8]) { float3 camera_position = transform_get_column(&scene->camera->matrix, 3); float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); /* Find min & max points for x & y & z on bounding box */ for(int i = 0; i < 8; ++i) { float3 p = bb[i]; bb_min = min(bb_min, p); bb_max = max(bb_max, p); } float3 closest_point = max(min(bb_max,camera_position),bb_min); return (len_squared(camera_position - closest_point) > distance_cull_margin_ * distance_cull_margin_); }
static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision) { if (!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { return; } const int num_verts = b_mesh.vertices.length(); if (num_verts == 0) { return; } /* STEP 1: Find out duplicated vertices and point duplicates to a single * original vertex. */ vector<int> sorted_vert_indeices(num_verts); for (int vert_index = 0; vert_index < num_verts; ++vert_index) { sorted_vert_indeices[vert_index] = vert_index; } VertexAverageComparator compare(mesh->verts); sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare); /* This array stores index of the original vertex for the given vertex * index. */ vector<int> vert_orig_index(num_verts); for (int sorted_vert_index = 0; sorted_vert_index < num_verts; ++sorted_vert_index) { const int vert_index = sorted_vert_indeices[sorted_vert_index]; const float3 &vert_co = mesh->verts[vert_index]; bool found = false; for (int other_sorted_vert_index = sorted_vert_index + 1; other_sorted_vert_index < num_verts; ++other_sorted_vert_index) { const int other_vert_index = sorted_vert_indeices[other_sorted_vert_index]; const float3 &other_vert_co = mesh->verts[other_vert_index]; /* We are too far away now, we wouldn't have duplicate. */ if ((other_vert_co.x + other_vert_co.y + other_vert_co.z) - (vert_co.x + vert_co.y + vert_co.z) > 3 * FLT_EPSILON) { break; } /* Found duplicate. */ if (len_squared(other_vert_co - vert_co) < FLT_EPSILON) { found = true; vert_orig_index[vert_index] = other_vert_index; break; } } if (!found) { vert_orig_index[vert_index] = vert_index; } } /* Make sure we always points to the very first orig vertex. */ for (int vert_index = 0; vert_index < num_verts; ++vert_index) { int orig_index = vert_orig_index[vert_index]; while (orig_index != vert_orig_index[orig_index]) { orig_index = vert_orig_index[orig_index]; } vert_orig_index[vert_index] = orig_index; } sorted_vert_indeices.free_memory(); /* STEP 2: Calculate vertex normals taking into account their possible * duplicates which gets "welded" together. */ vector<float3> vert_normal(num_verts, make_float3(0.0f, 0.0f, 0.0f)); /* First we accumulate all vertex normals in the original index. */ for (int vert_index = 0; vert_index < num_verts; ++vert_index) { const float3 normal = get_float3(b_mesh.vertices[vert_index].normal()); const int orig_index = vert_orig_index[vert_index]; vert_normal[orig_index] += normal; } /* Then we normalize the accumulated result and flush it to all duplicates * as well. */ for (int vert_index = 0; vert_index < num_verts; ++vert_index) { const int orig_index = vert_orig_index[vert_index]; vert_normal[vert_index] = normalize(vert_normal[orig_index]); } /* STEP 3: Calculate pointiness using single ring neighborhood. */ vector<int> counter(num_verts, 0); vector<float> raw_data(num_verts, 0.0f); vector<float3> edge_accum(num_verts, make_float3(0.0f, 0.0f, 0.0f)); BL::Mesh::edges_iterator e; EdgeMap visited_edges; int edge_index = 0; memset(&counter[0], 0, sizeof(int) * counter.size()); for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; if (visited_edges.exists(v0, v1)) { continue; } visited_edges.insert(v0, v1); float3 co0 = get_float3(b_mesh.vertices[v0].co()), co1 = get_float3(b_mesh.vertices[v1].co()); float3 edge = normalize(co1 - co0); edge_accum[v0] += edge; edge_accum[v1] += -edge; ++counter[v0]; ++counter[v1]; } for (int vert_index = 0; vert_index < num_verts; ++vert_index) { const int orig_index = vert_orig_index[vert_index]; if (orig_index != vert_index) { /* Skip duplicates, they'll be overwritten later on. */ continue; } if (counter[vert_index] > 0) { const float3 normal = vert_normal[vert_index]; const float angle = safe_acosf(dot(normal, edge_accum[vert_index] / counter[vert_index])); raw_data[vert_index] = angle * M_1_PI_F; } else { raw_data[vert_index] = 0.0f; } } /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */ AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes; Attribute *attr = attributes.add(ATTR_STD_POINTINESS); float *data = attr->data_float(); memcpy(data, &raw_data[0], sizeof(float) * raw_data.size()); memset(&counter[0], 0, sizeof(int) * counter.size()); edge_index = 0; visited_edges.clear(); for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; if (visited_edges.exists(v0, v1)) { continue; } visited_edges.insert(v0, v1); data[v0] += raw_data[v1]; data[v1] += raw_data[v0]; ++counter[v0]; ++counter[v1]; } for (int vert_index = 0; vert_index < num_verts; ++vert_index) { data[vert_index] /= counter[vert_index] + 1; } /* STEP 4: Copy attribute to the duplicated vertices. */ for (int vert_index = 0; vert_index < num_verts; ++vert_index) { const int orig_index = vert_orig_index[vert_index]; data[vert_index] = data[orig_index]; } }
static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int motion_step) { VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name << ", motion step " << motion_step; /* find attribute */ Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); bool new_attribute = false; /* add new attribute if it doesn't exist already */ if (!attr_mP) { VLOG(1) << "Creating new motion vertex position attribute"; attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); new_attribute = true; } /* export motion vectors for curve keys */ size_t numkeys = mesh->curve_keys.size(); float4 *mP = attr_mP->data_float4() + motion_step * numkeys; bool have_motion = false; int i = 0; int num_curves = 0; for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { /* Curve lengths may not match! Curves can be clipped. */ int curve_key_end = (num_curves + 1 < (int)mesh->curve_first_key.size() ? mesh->curve_first_key[num_curves + 1] : (int)mesh->curve_keys.size()); const int num_center_curve_keys = curve_key_end - mesh->curve_first_key[num_curves]; const int is_num_keys_different = CData->curve_keynum[curve] - num_center_curve_keys; if (!is_num_keys_different) { for (int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { if (i < mesh->curve_keys.size()) { mP[i] = CurveSegmentMotionCV(CData, sys, curve, curvekey); if (!have_motion) { /* unlike mesh coordinates, these tend to be slightly different * between frames due to particle transforms into/out of object * space, so we use an epsilon to detect actual changes */ float4 curve_key = float3_to_float4(mesh->curve_keys[i]); curve_key.w = mesh->curve_radius[i]; if (len_squared(mP[i] - curve_key) > 1e-5f * 1e-5f) have_motion = true; } } i++; } } else { /* Number of keys has changed. Generate an interpolated version * to preserve motion blur. */ const float step_size = num_center_curve_keys > 1 ? 1.0f / (num_center_curve_keys - 1) : 0.0f; for (int step_index = 0; step_index < num_center_curve_keys; ++step_index) { const float step = step_index * step_size; mP[i] = LerpCurveSegmentMotionCV(CData, sys, curve, step); i++; } have_motion = true; } num_curves++; } } /* in case of new attribute, we verify if there really was any motion */ if (new_attribute) { if (i != numkeys || !have_motion) { /* No motion or hair "topology" changed, remove attributes again. */ if (i != numkeys) { VLOG(1) << "Hair topology changed, removing attribute."; } else { VLOG(1) << "No motion, removing attribute."; } mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); } else if (motion_step > 0) { VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step; /* motion, fill up previous steps that we might have skipped because * they had no motion, but we need them anyway now */ for (int step = 0; step < motion_step; step++) { float4 *mP = attr_mP->data_float4() + step * numkeys; for (int key = 0; key < numkeys; key++) { mP[key] = float3_to_float4(mesh->curve_keys[key]); mP[key].w = mesh->curve_radius[key]; } } } } }
static void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution) { int vertexno = mesh->verts.size(); int vertexindex = vertexno; int numverts = 0, numtris = 0; /* compute and reserve size of arrays */ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { numverts += (CData->curve_keynum[curve] - 1) * resolution + resolution; numtris += (CData->curve_keynum[curve] - 1) * 2 * resolution; } } mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); /* actually export */ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { float3 firstxbasis = cross(make_float3(1.0f, 0.0f, 0.0f), CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]]); if (!is_zero(firstxbasis)) firstxbasis = normalize(firstxbasis); else firstxbasis = normalize(cross(make_float3(0.0f, 1.0f, 0.0f), CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]])); for (int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { float3 xbasis = firstxbasis; float3 v1; float3 v2; if (curvekey == CData->curve_firstkey[curve]) { v1 = CData->curvekey_co[min( curvekey + 2, CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey + 1]; v2 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; } else if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; v2 = CData->curvekey_co[curvekey - 1] - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; } else { v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; } xbasis = cross(v1, v2); if (len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { firstxbasis = normalize(xbasis); break; } } for (int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { int subv = 1; float3 xbasis; float3 ybasis; float3 v1; float3 v2; if (curvekey == CData->curve_firstkey[curve]) { subv = 0; v1 = CData->curvekey_co[min( curvekey + 2, CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey + 1]; v2 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; } else if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; v2 = CData->curvekey_co[curvekey - 1] - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; } else { v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; } xbasis = cross(v1, v2); if (len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { xbasis = normalize(xbasis); firstxbasis = xbasis; } else xbasis = firstxbasis; ybasis = normalize(cross(xbasis, v2)); for (; subv <= 1; subv++) { float3 ickey_loc = make_float3(0.0f, 0.0f, 0.0f); float time = 0.0f; InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData); float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); if ((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == 1)) radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); if (CData->psys_closetip[sys] && (subv == 1) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)) radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); float angle = M_2PI_F / (float)resolution; for (int section = 0; section < resolution; section++) { float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis); mesh->add_vertex(ickey_loc_shf); } if (subv != 0) { for (int section = 0; section < resolution - 1; section++) { mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], true); mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], true); } mesh->add_triangle(vertexindex - 1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], true); mesh->add_triangle(vertexindex, vertexindex - resolution, vertexindex + resolution - 1, CData->psys_shader[sys], true); } vertexindex += resolution; } } } } mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles()); mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); mesh->add_face_normals(); mesh->add_vertex_normals(); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); /* texture coords still needed */ }
void test_07() { //// WRITES SYSTEM ENERGY TO FILE int width = 600; int height = 400; Object* A = new Player; Object* B = new Object; Object* C = new Object; Object* D = new Object; Window window = Window(width,height,NULL,30,vis::AUTO_SIZE_UNIVERSE); // Set them apart, and on a collision course A->set_position(2, 0); A->set_velocity(0,0); A->set_radius(0.5); A->set_mass(5); A->bouncyness = 1; B->set_position(2, 2); B->set_velocity(0, -1); B->set_mass(2); //B->bouncyness = 0.7; C->set_position(-2, -2); C->set_mass(2); //C->bouncyness = 0.7; D->set_position(-4, -4); D->set_mass(2); //D->bouncyness = 0.7; // Generate a universe Universe universe(width/window.pixRatio, height/window.pixRatio); window.bindUniverse(&universe); // Add them to the universe universe.add_object(A); universe.add_object(B); universe.add_object(C); universe.add_object(D); vec2d posA; vec2d posB; std::ofstream outputfile; outputfile.open("test_07.csv"); Universe* uni = &universe; do{ for(int ii = 0; ii < universe.objects.size(); ii++){ double vel2 = len_squared(universe.objects[ii]->get_velocity()); outputfile << 0.5*universe.objects[ii]->get_mass()*vel2 << ","; double ener = 0; for (int qq = 0; qq < universe.objects.size(); ++qq ) { // Make sure you are not calculating yourself if (qq == ii) { // This is myself, skip this loop iteration continue; } // Here add up the contribution to the acceleration ener += potentialEnergy(universe.objects[ii], universe.objects[qq],uni); } //// Made the potential energy per object only store half, as for each potential between 2 objects 2 objects store it but there is only one potential. if(ii == universe.objects.size()-1){ outputfile << ener/2 << ";" << std::endl; }else{ outputfile << ener/2 << ","; } } // Clear the buffers to set values (in our case only colour buffer needs to be cleared) glClear(GL_COLOR_BUFFER_BIT); // Draw the universe's objects on top of that window.drawObjectList(universe.objects); // Do a physics iteration universe.simulate_one_time_unit(window.fps); // Swap buffers glfwSwapBuffers(window.GLFWpointer); glfwPollEvents(); window.pace_frame(); } // Check if the ESC key was pressed or the window was closed while( glfwGetKey(window.GLFWpointer, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window.GLFWpointer) == 0 ); outputfile.close(); // Close OpenGL window and terminate GLFW glfwTerminate(); }
static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int motion_step) { VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name << ", motion step " << motion_step; /* find attribute */ Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); bool new_attribute = false; /* add new attribute if it doesn't exist already */ if(!attr_mP) { VLOG(1) << "Creating new motion vertex position attribute"; attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); new_attribute = true; } /* export motion vectors for curve keys */ size_t numkeys = mesh->curve_keys.size(); float4 *mP = attr_mP->data_float4() + motion_step*numkeys; bool have_motion = false; int i = 0; for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { if(CData->psys_curvenum[sys] == 0) continue; for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { if(i < mesh->curve_keys.size()) { float3 ickey_loc = CData->curvekey_co[curvekey]; float time = CData->curvekey_time[curvekey]/CData->curve_length[curve]; float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) radius = 0.0f; /* curve motion keys store both position and radius in float4 */ mP[i] = float3_to_float4(ickey_loc); mP[i].w = radius; /* unlike mesh coordinates, these tend to be slightly different * between frames due to particle transforms into/out of object * space, so we use an epsilon to detect actual changes */ float4 curve_key = float3_to_float4(mesh->curve_keys[i]); curve_key.w = mesh->curve_radius[i]; if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f) have_motion = true; } i++; } } } /* in case of new attribute, we verify if there really was any motion */ if(new_attribute) { if(i != numkeys || !have_motion) { /* No motion or hair "topology" changed, remove attributes again. */ if(i != numkeys) { VLOG(1) << "Hair topology changed, removing attribute."; } else { VLOG(1) << "No motion, removing attribute."; } mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); } else if(motion_step > 0) { VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step; /* motion, fill up previous steps that we might have skipped because * they had no motion, but we need them anyway now */ for(int step = 0; step < motion_step; step++) { float4 *mP = attr_mP->data_float4() + step*numkeys; for(int key = 0; key < numkeys; key++) { mP[key] = float3_to_float4(mesh->curve_keys[key]); mP[key].w = mesh->curve_radius[key]; } } } } }