Meshes::UID revolved_sphere(unsigned int longitude_quads, unsigned int latitude_quads, unsigned char buffer_bitmask) { if (longitude_quads < 3 || latitude_quads < 2) return Meshes::UID::invalid_UID(); unsigned int latitude_size = latitude_quads + 1; unsigned int longitude_size = longitude_quads + 1; unsigned int vertex_count = latitude_size * longitude_size; unsigned int quad_count = latitude_quads * longitude_quads; unsigned int index_count = (quad_count - longitude_quads) * 2; float radius = 0.5f; Mesh mesh = Meshes::create("RevolvedSphere", index_count, vertex_count, buffer_bitmask); { // Vertex attributes. Vector3f* positions = mesh.get_positions(); Vector3f* normals = mesh.get_normals(); Vector2f* texcoords = mesh.get_texcoords(); Vector2f tc_normalizer = Vector2f(1.0f / longitude_quads, 1.0f / latitude_quads); for (unsigned int y = 0; y < latitude_size; ++y) { for (unsigned int x = 0; x < longitude_size; ++x) { unsigned int vertex_index = y * longitude_size + x; Vector2f tc = Vector2f(float(x), float(y)) * tc_normalizer; if (texcoords) texcoords[vertex_index] = tc; positions[vertex_index] = spherical_to_direction(tc.y * Math::PI<float>(), tc.x * 2.0f * Math::PI<float>()) * radius; if (normals) normals[vertex_index] = normalize(positions[vertex_index]); } } // Hard set the poles to [0,1,0] and [0,-1,0]. for (unsigned int x = 0; x < longitude_size; ++x) { positions[x] = Vector3f(0, radius, 0); positions[(latitude_size - 1) * longitude_size + x] = Vector3f(0, -radius, 0); } } { // Primitives. Vector3ui* primitives = mesh.get_primitives(); for (unsigned int y = 0; y < latitude_quads; ++y) { for (unsigned int x = 0; x < longitude_quads; ++x) { unsigned int base_vertex_index = x + y * longitude_size; if (y != 0) *primitives++ = Vector3ui(0, 1, longitude_size) + base_vertex_index; if (y != latitude_quads - 1) *primitives++ = Vector3ui(1, longitude_size + 1, longitude_size) + base_vertex_index; } } } mesh.set_bounds(AABB(Vector3f(-radius), Vector3f(radius))); return mesh.get_ID(); }
bool VisVoxelMap::visualize(const bool force_repaint) { if (force_repaint) { openOrCreateSegment(); uint32_t shared_mem_id; if (m_shm_memHandle == NULL) { // there should only be one segment of number_of_voxelmaps std::pair<uint32_t*, std::size_t> r = m_segment.find<uint32_t>( shm_variable_name_number_of_voxelmaps.c_str()); if (r.second == 0) { // if it doesn't exists .. m_segment.construct<uint32_t>(shm_variable_name_number_of_voxelmaps.c_str())(1); shared_mem_id = 0; } else { // if it exists increase it by one shared_mem_id = *r.first; (*r.first)++; } // get shared memory pointer std::stringstream id; id << shared_mem_id; m_shm_memHandle = m_segment.find_or_construct<cudaIpcMemHandle_t>( std::string(shm_variable_name_voxelmap_handler_dev_pointer + id.str()).c_str())( cudaIpcMemHandle_t()); m_shm_mapDim = m_segment.find_or_construct<Vector3ui>( std::string(shm_variable_name_voxelmap_dimension + id.str()).c_str())(Vector3ui(0)); m_shm_VoxelSize = m_segment.find_or_construct<float>( std::string(shm_variable_name_voxel_side_length + id.str()).c_str())(0.0f); m_shm_mapName = m_segment.find_or_construct_it<char>( std::string(shm_variable_name_voxelmap_name + id.str()).c_str())[m_map_name.size()]( m_map_name.data()); m_shm_voxelmap_type = m_segment.find_or_construct<MapType>( std::string(shm_variable_name_voxelmap_type + id.str()).c_str())(m_voxelmap->getMapType()); m_shm_voxelmap_changed = m_segment.find_or_construct<bool>( std::string(shm_variable_name_voxelmap_data_changed + id.str()).c_str())(true); } // first open or create and the set the values HANDLE_CUDA_ERROR(cudaIpcGetMemHandle(m_shm_memHandle, m_voxelmap->getVoidDeviceDataPtr())); *m_shm_mapDim = m_voxelmap->getDimensions(); *m_shm_VoxelSize = m_voxelmap->getVoxelSideLength(); *m_shm_voxelmap_changed = true; // // wait till data was read by visualizer. Otherwise a // while(*m_shm_voxelmap_changed) // usleep(10000); // sleep 10 ms return true; } return false; }
Meshes::UID plane(unsigned int quads_pr_edge, unsigned char buffer_bitmask) { if (quads_pr_edge == 0) return Meshes::UID::invalid_UID(); unsigned int size = quads_pr_edge + 1; unsigned int vertex_count = size * size; unsigned int quad_count = quads_pr_edge * quads_pr_edge; unsigned int index_count = quad_count * 2; Mesh mesh = Meshes::create("Plane", index_count, vertex_count, buffer_bitmask); // Vertex attributes. float tc_normalizer = 1.0f / quads_pr_edge; for (unsigned int z = 0; z < size; ++z) { for (unsigned int x = 0; x < size; ++x) { mesh.get_positions()[z * size + x] = Vector3f(x - quads_pr_edge * 0.5f, 0.0f, z - quads_pr_edge * 0.5f); if (mesh.get_normals() != nullptr) mesh.get_normals()[z * size + x] = Vector3f(0.0f, 1.0f, 0.0f); if (mesh.get_texcoords() != nullptr) mesh.get_texcoords()[z * size + x] = Vector2f(float(x), float(z)) * tc_normalizer; } } // Primitives. for (unsigned int z = 0; z < quads_pr_edge; ++z) { for (unsigned int x = 0; x < quads_pr_edge; ++x) { Vector3ui* primitives = mesh.get_primitives() + (z * quads_pr_edge + x) * 2; unsigned int base_index = x + z * size; primitives[0] = Vector3ui(base_index, base_index + size, base_index + 1); primitives[1] = Vector3ui(base_index + 1, base_index + size, base_index + size + 1); } } mesh.compute_bounds(); return mesh.get_ID(); }
Vector3ui NodeId::getPosition() const { return Vector3ui(_blockPosX, _blockPosY, _blockPosZ); }
void VoxelMapProvider::init(Provider_Parameter& parameter) { m_mutex.lock(); const string prefix = "VoxelMapProvider::" + string(__FUNCTION__); const string temp_timer = prefix + "_temp"; PERF_MON_START(prefix); PERF_MON_START(temp_timer); Provider::init(parameter); // get shared memory pointer m_shm_memHandle = m_segment.find_or_construct<cudaIpcMemHandle_t>( std::string(shm_variable_name_voxelmap_handler_dev_pointer + m_shared_mem_id).c_str())( cudaIpcMemHandle_t()); m_shm_mapDim = m_segment.find_or_construct<Vector3ui>( std::string(shm_variable_name_voxelmap_dimension + m_shared_mem_id).c_str())(Vector3ui(0)); m_shm_VoxelSize = m_segment.find_or_construct<float>( std::string(shm_variable_name_voxel_side_length + m_shared_mem_id).c_str())(0.0f); // there should only be one segment of number_of_voxelmaps std::pair<uint32_t*, std::size_t> r = m_segment.find<uint32_t>( shm_variable_name_number_of_voxelmaps.c_str()); if (r.second == 0) { // if it doesn't exist .. m_segment.construct<uint32_t>(shm_variable_name_number_of_voxelmaps.c_str())(1); } else { // if it exit increase it by one (*r.first)++; } Vector3ui map_dim; std::vector<Vector3f> insert_points; float voxel_map_res = 1.0f; if (parameter.points.size() != 0) { Vector3f offset; Vector3ui point_data_bounds = getMapDimensions(parameter.points, offset); map_dim = point_data_bounds; printf("point cloud dimension %u %u %u\n", map_dim.x, map_dim.y, map_dim.z); if (parameter.plan_size.x != 0.0f && parameter.plan_size.y != 0.0f && parameter.plan_size.z != 0.0f) { Vector3f tmp = parameter.plan_size * 1000.0f; map_dim = Vector3ui(uint32_t(tmp.x), uint32_t(tmp.y), uint32_t(tmp.z)); printf("dim in cm %u %u %u\n", map_dim.x, map_dim.y, map_dim.z); } uint64_t map_voxel = uint64_t(map_dim.x) * uint64_t(map_dim.y) * uint64_t(map_dim.z); float scaling = 1.0; if (parameter.max_memory == 0) { // compute scaling factor based on voxel size scaling = 1.0f / parameter.resolution_tree; } else { // compute max scaling factor based on memory restriction uint64_t max_voxel = uint64_t(parameter.max_memory) / sizeof(ProbabilisticVoxel); printf("max_voxel %lu map_voxel %lu\n", max_voxel, map_voxel); if (max_voxel <= map_voxel) scaling = float(pow(max_voxel / double(map_voxel), 1.0 / 3)); } printf("scaling %f\n", scaling); std::vector<Vector3ui> points; Vector3ui map_dim_tmp; transformPointCloud(parameter.points, points, map_dim_tmp, scaling * 1000.0f); map_dim = Vector3ui(uint32_t(ceil(map_dim.x * scaling)), uint32_t(ceil(map_dim.y * scaling)), uint32_t(ceil(map_dim.z * scaling))); printf("voxel map dimension %u %u %u\n", map_dim.x, map_dim.y, map_dim.z); // center data at the middle of the map, just like for NTree point_data_bounds = Vector3ui(uint32_t(ceil(point_data_bounds.x * scaling)), uint32_t(ceil(point_data_bounds.y * scaling)), uint32_t(ceil(point_data_bounds.z * scaling))); Vector3ui tmp_offset = (map_dim - point_data_bounds) / Vector3ui(2); insert_points.resize(points.size()); printf("scaling %f\n", scaling); voxel_map_res = (1.0f / scaling) / 1000.0f;; printf("mapres %f\n", voxel_map_res); for (int i = 0; i < int(points.size()); ++i) { points[i] = points[i] + tmp_offset; insert_points[i].x = points[i].x * voxel_map_res + voxel_map_res / 2; insert_points[i].y = points[i].y * voxel_map_res + voxel_map_res / 2; insert_points[i].z = points[i].z * voxel_map_res + voxel_map_res / 2; } PERF_MON_START(temp_timer); } else { // VoxelMap with same size as octree uint32_t dim = (uint32_t) pow(pow(BRANCHING_FACTOR, 1.0 / 3), parameter.resolution_tree); map_dim = Vector3ui(dim); voxel_map_res = parameter.resolution_tree * 0.001f; // voxel size in meter } switch(m_parameter->model_type) { case Provider_Parameter::eMT_Probabilistic: { m_voxelMap = new gpu_voxels::voxelmap::ProbVoxelMap(map_dim.x, map_dim.y, map_dim.z, voxel_map_res, MT_PROBAB_VOXELMAP); break; } case Provider_Parameter::eMT_BitVector: { m_voxelMap = new gpu_voxels::voxelmap::BitVectorVoxelMap(map_dim.x, map_dim.y, map_dim.z, voxel_map_res, MT_BITVECTOR_VOXELMAP); break; } default: { printf("ERROR: Unknown 'model_type'\n"); } } m_segment.find_or_construct<MapType>(std::string(shm_variable_name_voxelmap_type + m_shared_mem_id).c_str())(m_voxelMap->getMapType()); if (insert_points.size() != 0) { m_voxelMap->insertPointCloud(insert_points, gpu_voxels::eBVM_OCCUPIED); // if (m_parameter->model_type == Provider_Parameter::eMT_BitVector) // { // Vector3f offset(1, 1, 1); // for (uint32_t k = 1; k < 4; ++k) // { // std::vector<Vector3f> tmp = insert_points; // for (int i = 0; i < int(tmp.size()); ++i) // tmp[i] = tmp[i] + offset * k; // // m_voxelMap->insertPointCloud(tmp, gpu_voxels::eBVM_UNDEFINED + k); // } // } PERF_MON_PRINT_INFO_P(temp_timer, "Build", prefix); } PERF_MON_ADD_DATA_NONTIME_P("UsedMemory", m_voxelMap->getMemoryUsage(), prefix); m_sensor_orientation = gpu_voxels::Vector3f(0, 0, 0); m_sensor_position = gpu_voxels::Vector3f( (m_voxelMap->getDimensions().x * m_voxelMap->getVoxelSideLength()) / 2, (m_voxelMap->getDimensions().y * m_voxelMap->getVoxelSideLength()) / 2, (m_voxelMap->getDimensions().z * m_voxelMap->getVoxelSideLength()) / 2) * 0.001f; // in meter printf("VoxelMap created!\n"); m_mutex.unlock(); }
void DataManager::Initialize(itk::SmartPointer<LabelMapType> labelMap, std::shared_ptr<Coordinates> coordinates, std::shared_ptr<Metadata> metadata) { m_orientationData = coordinates; auto spacing = m_orientationData->GetImageSpacing(); auto imageorigin = m_orientationData->GetImageOrigin(); auto imagesize = m_orientationData->GetImageSize(); // insert background label info, initially all voxels are background, we'll subtract later auto object = std::make_shared<ObjectInformation>(); object->scalar = 0; object->centroid = Vector3d((imagesize[0] / 2.0) * spacing[0], (imagesize[1] / 2.0) * spacing[1], (imagesize[2] / 2.0) / spacing[2]); object->size = imagesize[0] * imagesize[1] * imagesize[2]; object->min = Vector3ui(0, 0, 0); object->max = Vector3ui(imagesize[0], imagesize[1], imagesize[2]); ObjectVector.insert(std::pair<unsigned short, std::shared_ptr<ObjectInformation>>(0, object)); // evaluate shapelabelobjects to get the centroid of the object auto evaluator = itk::ShapeLabelMapFilter<LabelMapType>::New(); evaluator->SetInput(labelMap); evaluator->ComputePerimeterOff(); evaluator->ComputeFeretDiameterOff(); evaluator->SetInPlace(true); evaluator->Update(); // get voxel count for each label for statistics and "flatten" the labelmap (make all labels consecutive starting from 1) auto labelChanger = ChangeType::New(); labelChanger->SetInput(evaluator->GetOutput()); labelChanger->SetInPlace(true); ImageRegionType region; unsigned short i = 1; itk::Point<double, 3> centroid; for (int i = 0; i < evaluator->GetOutput()->GetNumberOfLabelObjects(); ++i) { auto labelObject = evaluator->GetOutput()->GetNthLabelObject(i); auto scalar = labelObject->GetLabel(); centroid = labelObject->GetCentroid(); region = labelObject->GetBoundingBox(); auto regionOrigin = region.GetIndex(); auto regionSize = region.GetSize(); object = std::make_shared<ObjectInformation>(); object->scalar = scalar; object->centroid = Vector3d(centroid[0] / spacing[0], centroid[1] / spacing[1], centroid[2] / spacing[2]); object->size = labelObject->Size(); object->min = Vector3ui(regionOrigin[0], regionOrigin[1], regionOrigin[2]); object->max = Vector3ui(regionSize[0] + regionOrigin[0], regionSize[1] + regionOrigin[1], regionSize[2] + regionOrigin[2]) - Vector3ui(1, 1, 1); ObjectVector.insert(std::pair<unsigned short, std::shared_ptr<ObjectInformation>>(i, object)); // substract the voxels of this object from the background label ObjectVector[0]->size -= labelObject->Size(); // need to mark object label as used to correct errors in the segmha metadata (defined labels but empty objects) metadata->markAsUsed(scalar); // flatten label labelChanger->SetChange(scalar, i); } // start entering new labels at the end of the scalar range m_firstFreeValue = GetScalarForLabel(GetNumberOfLabels() - 1) + 1; // apply all the changes made to labels labelChanger->Update(); m_labelMap = LabelMapType::New(); m_labelMap = labelChanger->GetOutput(); m_labelMap->Optimize(); m_labelMap->Update(); // generate the initial vtkLookupTable m_lookupTable = vtkSmartPointer<vtkLookupTable>::New(); GenerateLookupTable(); m_lookupTable->Modified(); }
void DataManager::SetVoxelScalar(const Vector3ui &point, const unsigned short scalar) { int extent[6]; m_structuredPoints->GetExtent(extent); if(extent[0] > point[0] || extent[1] < point[0] || extent[2] > point[1] || extent[3] < point[1] || extent[4] > point[2] || extent[5] < point[2]) { qWarning() << "point out of range - point[" << point[0] << point[1] << point[2] << "] extent[" << extent[0] << extent[1] << extent[2] << extent[3] << extent[4] << extent[5] << "]"; return; } auto x = point[0]; auto y = point[1]; auto z = point[2]; auto pixel = static_cast<unsigned short*>(m_structuredPoints->GetScalarPointer(x,y,z)); if (scalar == *pixel) return; if (ActionInformationVector.find(*pixel) == ActionInformationVector.end()) { auto action = std::make_shared<ActionInformation>(); ActionInformationVector[*pixel] = action; action->min = Vector3ui(x, y, z); action->max = Vector3ui(x, y, z); } ActionInformationVector[*pixel]->size -= 1; ActionInformationVector[*pixel]->centroid[0] -= x; ActionInformationVector[*pixel]->centroid[1] -= y; ActionInformationVector[*pixel]->centroid[2] -= z; if (ActionInformationVector.find(scalar) == ActionInformationVector.end()) { auto action = std::make_shared<ActionInformation>(); ActionInformationVector[scalar] = action; action->min = Vector3ui(x, y, z); action->max = Vector3ui(x, y, z); } ActionInformationVector[scalar]->size += 1; ActionInformationVector[scalar]->centroid[0] += x; ActionInformationVector[scalar]->centroid[1] += y; ActionInformationVector[scalar]->centroid[2] += z; // have to check if the added voxel is out of the object region to make the bounding box grow Vector3ui min = ActionInformationVector[scalar]->min; Vector3ui max = ActionInformationVector[scalar]->max; if (x < min[0]) min[0] = x; if (x > max[0]) max[0] = x; if (y < min[1]) min[1] = y; if (y > max[1]) max[1] = y; if (z < min[2]) min[2] = z; if (z > max[2]) max[2] = z; ActionInformationVector[scalar]->min = min; ActionInformationVector[scalar]->max = max; m_actionsBuffer->storePoint(Vector3ui(x, y, z), *pixel); *pixel = scalar; }
Meshes::UID cube(unsigned int quads_pr_edge, unsigned char buffer_bitmask) { if (quads_pr_edge == 0) return Meshes::UID::invalid_UID(); unsigned int sides = 6; unsigned int verts_pr_edge = quads_pr_edge + 1; float scale = 1.0f / quads_pr_edge; float halfsize = 0.5f; // verts_pr_edge * 0.5f; unsigned int quad_count = quads_pr_edge * quads_pr_edge * sides; unsigned int index_count = quad_count * 2; unsigned int verts_pr_side = verts_pr_edge * verts_pr_edge; unsigned int vertex_count = verts_pr_side * sides; Mesh mesh = Meshes::create("Cube", index_count, vertex_count, buffer_bitmask); // Create the vertices. // [..TOP.. ..BOTTOM.. ..LEFT.. ..RIGHT.. ..FRONT.. ..BACK..] Vector3f* position_iterator = mesh.get_positions(); for (unsigned int i = 0; i < verts_pr_edge; ++i) // Top for (unsigned int j = 0; j < verts_pr_edge; ++j) *position_iterator++ = Vector3f(halfsize - i * scale, halfsize, j * scale - halfsize); for (unsigned int i = 0; i < verts_pr_edge; ++i) // Bottom for (unsigned int j = 0; j < verts_pr_edge; ++j) *position_iterator++ = Vector3f(halfsize - i * scale, -halfsize, halfsize - j * scale); for (unsigned int i = 0; i < verts_pr_edge; ++i) // Left for (unsigned int j = 0; j < verts_pr_edge; ++j) *position_iterator++ = Vector3f(-halfsize, halfsize - i * scale, j * scale - halfsize); for (unsigned int i = 0; i < verts_pr_edge; ++i) // Right for (unsigned int j = 0; j < verts_pr_edge; ++j) *position_iterator++ = Vector3f(halfsize, i * scale - halfsize, j * scale - halfsize); for (unsigned int i = 0; i < verts_pr_edge; ++i) // Front for (unsigned int j = 0; j < verts_pr_edge; ++j) *position_iterator++ = Vector3f(halfsize - i * scale, halfsize - j * scale, halfsize); for (unsigned int i = 0; i < verts_pr_edge; ++i) // Back for (unsigned int j = 0; j < verts_pr_edge; ++j) *position_iterator++ = Vector3f(i * scale - halfsize, halfsize - j * scale, -halfsize); if (mesh.get_normals() != nullptr) { Vector3f* normal_iterator = mesh.get_normals(); while (normal_iterator < mesh.get_normals() + verts_pr_side) // Top *normal_iterator++ = Vector3f(0, 1, 0); while (normal_iterator < mesh.get_normals() + verts_pr_side * 2) // Bottom *normal_iterator++ = Vector3f(0, -1, 0); while (normal_iterator < mesh.get_normals() + verts_pr_side * 3) // Left *normal_iterator++ = Vector3f(-1, 0, 0); while (normal_iterator < mesh.get_normals() + verts_pr_side * 4) // Right *normal_iterator++ = Vector3f(1, 0, 0); while (normal_iterator < mesh.get_normals() + verts_pr_side * 5) // Front *normal_iterator++ = Vector3f(0, 0, 1); while (normal_iterator < mesh.get_normals() + verts_pr_side * 6) // Back *normal_iterator++ = Vector3f(0, 0, -1); } if (mesh.get_texcoords() != nullptr) { Vector2f* texcoords = mesh.get_texcoords(); float tc_normalizer = 1.0f / quads_pr_edge; for (unsigned int i = 0; i < verts_pr_edge; ++i) for (unsigned int j = 0; j < verts_pr_edge; ++j) texcoords[i * verts_pr_edge + j] = texcoords[i * verts_pr_edge + j + verts_pr_side] = texcoords[i * verts_pr_edge + j + verts_pr_side * 2] = texcoords[i * verts_pr_edge + j + verts_pr_side * 3] = texcoords[i * verts_pr_edge + j + verts_pr_side * 4] = texcoords[i * verts_pr_edge + j + verts_pr_side * 5] = Vector2f(float(i), float(j)) * tc_normalizer; } // Set indices. Vector3ui* primitives = mesh.get_primitives(); for (unsigned int side_offset = 0; side_offset < vertex_count; side_offset += verts_pr_side) for (unsigned int i = 0; i < quads_pr_edge; ++i) for (unsigned int j = 0; j < quads_pr_edge; ++j) { *primitives++ = Vector3ui(j + i * verts_pr_edge, j + (i + 1) * verts_pr_edge, j + 1 + i * verts_pr_edge) + side_offset; *primitives++ = Vector3ui(j + 1 + i * verts_pr_edge, j + (i + 1) * verts_pr_edge, j + 1 + (i + 1) * verts_pr_edge) + side_offset; } mesh.set_bounds(AABB(Vector3f(-halfsize), Vector3f(halfsize))); return mesh.get_ID(); }
Meshes::UID cylinder(unsigned int vertical_quads, unsigned int circumference_quads, unsigned char buffer_bitmask) { if (vertical_quads == 0 || circumference_quads == 0) return Meshes::UID::invalid_UID(); unsigned int lid_vertex_count = circumference_quads + 1; unsigned int side_vertex_count = (vertical_quads + 1) * circumference_quads; unsigned int vertex_count = 2 * lid_vertex_count + side_vertex_count; unsigned int lid_index_count = circumference_quads; unsigned int side_index_count = 2 * vertical_quads * circumference_quads; unsigned int index_count = 2 * lid_index_count + side_index_count; float radius = 0.5f; Mesh mesh = Meshes::create("Cylinder", index_count, vertex_count, buffer_bitmask); // Vertex layout is // [..TOP.. ..BOTTOM.. ..SIDE..] { // Positions. Vector3f* positions = mesh.get_positions(); // Create top positions. positions[0] = Vector3f(0.0f, radius, 0.0f); for (unsigned int v = 0; v < circumference_quads; ++v) { float radians = v / float(circumference_quads) * 2.0f * Math::PI<float>(); positions[v + 1] = Vector3f(cos(radians) * radius, radius, sin(radians) * radius); } // Mirror top to create bottom positions. for (unsigned int v = 0; v < lid_vertex_count; ++v) { positions[lid_vertex_count + v] = positions[v]; positions[lid_vertex_count + v].y = -radius; } // Create side positions. for (unsigned int i = 0; i < vertical_quads + 1; ++i) { float l = i / float(vertical_quads); for (unsigned int j = 0; j < circumference_quads; ++j) { unsigned int vertex_index = 2 * lid_vertex_count + i * circumference_quads + j; positions[vertex_index] = positions[j+1]; positions[vertex_index].y = lerp(radius, -radius, l); } } } if (mesh.get_normals() != nullptr) { Vector3f* normal_iterator = mesh.get_normals(); while (normal_iterator < mesh.get_normals() + lid_vertex_count) // Top *normal_iterator++ = Vector3f(0, 1, 0); while (normal_iterator < mesh.get_normals() + 2 * lid_vertex_count) // Bottom *normal_iterator++ = Vector3f(0, -1, 0); Vector3f* side_position_iterator = mesh.get_positions() + 2 * lid_vertex_count; while (normal_iterator < mesh.get_normals() + vertex_count) { // Side Vector3f position = *side_position_iterator++; *normal_iterator++ = normalize(Vector3f(position.x, 0.0f, position.z)); } } if (mesh.get_texcoords() != nullptr) { Vector2f* texcoords = mesh.get_texcoords(); // Top and bottom. for (unsigned int i = 0; i < 2 * lid_vertex_count; ++i) { Vector3f position = mesh.get_positions()[i]; texcoords[i] = Vector2f(position.x, position.z) + 0.5f; } // Side. for (unsigned int i = 0; i < vertical_quads + 1; ++i) { float v = i / float(vertical_quads); for (unsigned int j = 0; j < circumference_quads; ++j) { unsigned int vertex_index = 2 * lid_vertex_count + i * circumference_quads + j; float u = abs(-2.0f * j / float(circumference_quads) + 1.0f); // Magic u mapping. Mirror repeat mapping of the texture coords. texcoords[vertex_index] = Vector2f(u, v); } } } { // Primitives. Vector3ui* primitives = mesh.get_primitives(); // Top. for (unsigned int i = 0; i < lid_index_count; ++i) primitives[i] = Vector3ui(0, i + 2, i + 1); primitives[lid_index_count - 1].y = 1; // Bottom. for (unsigned int i = 0; i < lid_index_count; ++i) primitives[i + lid_index_count] = Vector3ui(0, i + 1, i + 2) + lid_vertex_count; primitives[2 * lid_index_count - 1].z = 1 + lid_vertex_count; // Side. unsigned int side_vertex_offset = 2 * lid_vertex_count; for (unsigned int i = 0; i < vertical_quads; ++i) { for (unsigned int j = 0; j < circumference_quads; ++j) { unsigned int side_index = 2 * lid_index_count + 2 * (i * circumference_quads + j); unsigned int i0 = i * circumference_quads + j; unsigned int i1 = (i + 1) * circumference_quads + j; unsigned int j_plus_1 = (j + 1) < circumference_quads ? (j + 1) : 0; // Handle wrap around. unsigned int i2 = i * circumference_quads + j_plus_1; unsigned int i3 = (i + 1) * circumference_quads + j_plus_1; primitives[side_index + 0] = Vector3ui(i0, i3, i1) + side_vertex_offset; primitives[side_index + 1] = Vector3ui(i0, i2, i3) + side_vertex_offset; } } } mesh.set_bounds(AABB(Vector3f(-radius), Vector3f(radius))); return mesh.get_ID(); }