void RKCell::preUpdate(double epsilon[], BaseCell* neighbors[], Grid *grid, Vector3i position) { int model = Shared::instance()->getGridConfig()->getModel(); MyVector3D colorGradient = MyVector3D(); for (int a = 0; a < model; a++) { Vector3i neighbor = position + LBUtil::C[model][a]; RKCell *cell = dynamic_cast<RKCell*>(grid->getGrid(neighbor.getY(), neighbor.getX(), neighbor.getZ())); if (cell != 0) { colorGradient = colorGradient + (LBUtil::C[model][a] ^ cell->getColor()); } } for (int i = 0; i < model; i++) { double fi = red[i] + blue[i]; double p = redP + blueP; double nextF = fi + 1.0 / epsilon[0] * (LBUtil::f_eq(u, p, model, i) - fi); double cos = (LBUtil::C[model][i] * colorGradient); if (colorGradient.norm() > 1e-10 && LBUtil::C[model][i].norm() > 1e-10) { cos = cos / (LBUtil::C[model][i].norm() * colorGradient.norm()); } else { //cos = std::sqrt(2.0) / 2; //cos = 1; cos = 0; } GridConfig *config = Shared::instance()->getGridConfig(); nextF += config->getRkA() * colorGradient.norm() * (2 * cos * cos - 1); double diff = config->getRkBeta() * redP * blueP / (p * p) * LBUtil::W[model][i] * p * cos; //double diff = 0; double newNextRed = redP / p * nextF + diff; double newNextBlue = blueP / p * nextF - diff; if (neighbors[i] != 0) { neighbors[i]->setNextF(i, newNextRed, 0); neighbors[i]->setNextF(i, newNextBlue, 1); } } }
//---------------------------------------------------------------------------- void Texture::set(void* iPtr, const Vector3i& iS, GLenum iInternalFormat, GLenum iFormat, GLenum iDataType) { vector<int> s(3, 0); s[0] = iS.x(); s[1] = iS.y(); s[2] = iS.z(); set( iPtr, s, iInternalFormat, iFormat, iDataType ); }
coord_t Box::volume() const { if (!valid()) { return 0; } Vector3i diagonal = this->diagonal(); return diagonal.x() * diagonal.y() * diagonal.z(); }
void DepositionCell::postUpdate(Grid *grid, Vector3i position) { for (int i = 0; i < 9; i++) { Vector3i neighbor = position + LBUtil::C[9][i]; nextG[i] = g[i] + deposited * (grid->getGrid(neighbor.getY(), neighbor.getX(), neighbor.getZ())->getF(LBUtil::OPPOSITE[9][i], 1) - g[i]); } for (int i = 0; i < 9; i++) { g[i] = nextG[i]; } }
double Cube::value(const Vector3i &pos) const { unsigned int index = pos.x() * m_points.y() * m_points.z() + pos.y() * m_points.z() + pos.z(); if (index < m_data.size()) return m_data[index]; else return 6969.0; }
int main(int, char**) { cout.precision(3); Vector3i v = Vector3i::Random(); cout << "Here is the vector v:" << endl << v << endl; cout << "v.rowwise().replicate(5) = ..." << endl; cout << v.rowwise().replicate(5) << endl; return 0; }
//------------------------------------------------------------------------------ IntAABB Octree::calculateTotalKeyBounds() { IntAABB bounds; for (auto it = m_roots.begin(); it != m_roots.end(); ++it) { OctreeNode & node = *(it->second); Vector3i pos = it->first; bounds.addPoint(pos.x(), pos.y()); } return bounds; }
uint getOctreeDepthForBounding(const Vector3i& maxXYZ) { coord_t max = ::std::max(maxXYZ.x(), ::std::max(maxXYZ.y(), maxXYZ.z())); if (max < 0) { throw ::std::runtime_error("Invalid bounding (all components must not be negative)"); } // how many bits are required to store numbers from 0 to max int requiredBits = getMostSignigicantSetBitPos(max) + 1; return static_cast<uint>(requiredBits); }
void BotBotCollisionGrid::Setup(Vector3i Dimensions) { assert(Dimensions.x() > 0 && "Attempting to create a world grid with zero x dimensions"); assert(Dimensions.y() > 0 && "Attempting to create a world grid with zero y dimensions"); SetupLevel(Grid1, Dimensions, 64); SetupLevel(Grid2, Dimensions, 128); SetupLevel(Grid3, Dimensions, 256); SetupLevel(Grid4, Dimensions, 512); MasterGrid.clear(); }
void BotBotCollisionGrid::SetupLevel(vector< vector< list< Robot* > > > &Grid, Vector3i Dimensions, int GridSize) { Grid.resize( (Dimensions.x() + GridSize - 1) / GridSize);//round up the number of dimensions needed for(unsigned int x = 0; x < Grid.size(); x++) { Grid[x].resize((Dimensions.y() + GridSize - 1) / GridSize); for(unsigned int y = 0; y < Grid[x].size(); y++) { Grid[x][y].clear(); } } }
void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector3i& size) { bindInternal(); /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 glTexStorage3D(target, levels, GLenum(internalFormat), size.x(), size.y(), size.z()); #else //glTexStorage3DEXT(target, levels, GLenum(internalFormat), size.x(), size.y(), size.z()); static_cast<void>(target); static_cast<void>(levels); static_cast<void>(internalFormat); static_cast<void>(size); #endif }
bool Cube::setLimits(const Vector3 &min_, const Vector3i &dim, const Vector3 &spacing_) { Vector3 max_ = Vector3(min_.x() + (dim.x()-1) * spacing_[0], min_.y() + (dim.y()-1) * spacing_[1], min_.z() + (dim.z()-1) * spacing_[2]); m_min = min_; m_max = max_; m_points = dim; m_spacing = spacing_; m_data.resize(m_points.x() * m_points.y() * m_points.z()); return true; }
bool Cube::setLimits(const Vector3d &min_, const Vector3i &dim, double spacing_) { Vector3d max_ = Vector3d(min_.x() + (dim.x()-1) * spacing_, min_.y() + (dim.y()-1) * spacing_, min_.z() + (dim.z()-1) * spacing_); m_min = min_; m_max = max_; m_points = dim; m_spacing = Vector3d(spacing_, spacing_, spacing_); m_data.resize(m_points.x() * m_points.y() * m_points.z()); return true; }
void Map::Draw(Gdiplus::Graphics* g) { Vector3i northWestTile = mMapViewport->GetNorthWestTileCoordinate(); Vector3i southEastTile = mMapViewport->GetSouthEastTileCoordinate(); Vector2i origin = mMapViewport->GetTileOrigin(northWestTile); int xTileCount = southEastTile.GetX() - northWestTile.GetX() + 1; int yTileCount = southEastTile.GetY() - northWestTile.GetY() + 1; int tileCount = xTileCount*yTileCount; for(int i = 0; i<xTileCount; i++) { for(int j = 0; j<yTileCount; j++) { Vector3i coord(northWestTile.GetX() + i, northWestTile.GetY() + j, mMapViewport->GetZoom()); Tile* tile = GetTile(coord); if(!tile->IsLoaded()) { tile->SignalReady += [this](Tile* tile) { std::lock_guard<std::mutex> lock(signal_mutex); SignalNewTile.emit(); }; continue; } Gdiplus::Image* im = tile->GetImage(); if(im) g->DrawImage(im, origin.GetX() + i*mMapSource->GetTileSize(), origin.GetY() + j*mMapSource->GetTileSize()); } } }
bool Cube::setLimits(const Vector3 &min_, const Vector3 &max_, const Vector3i &points) { // We can calculate all necessary properties and initialise our data Vector3 delta = max_ - min_; m_spacing = Vector3(delta.x() / (points.x()-1), delta.y() / (points.y()-1), delta.z() / (points.z()-1)); m_min = min_; m_max = max_; m_points = points; m_data.resize(m_points.x() * m_points.y() * m_points.z()); return true; }
void Map::SyncDraw(Gdiplus::Graphics* g) { Vector3i northWestTile = mMapViewport->GetNorthWestTileCoordinate(); Vector3i southEastTile = mMapViewport->GetSouthEastTileCoordinate(); Vector2i origin = mMapViewport->GetTileOrigin(northWestTile); int xTileCount = southEastTile.GetX() - northWestTile.GetX() + 1; int yTileCount = southEastTile.GetY() - northWestTile.GetY() + 1; int tileCount = xTileCount*yTileCount; int k = 0; for(int i = 0; i<xTileCount; i++) { for(int j = 0; j<yTileCount; j++) { k++; std::cout << k << "/" << tileCount << std::endl; Vector3i coord(northWestTile.GetX() + i, northWestTile.GetY() + j, mMapViewport->GetZoom()); Tile* tile = new Tile(coord, mMapSource); tile->Download(false); Gdiplus::Image* im = tile->GetImage(); if(im) g->DrawImage(im, origin.GetX() + i*mMapSource->GetTileSize(), origin.GetY() + j*mMapSource->GetTileSize()); delete tile; } } }
void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { bindInternal(); /** @todo Get some extension wrangler instead to avoid linker errors to glTexSubImage3D() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 glTexSubImage3D(target, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast<GLenum>(format), static_cast<GLenum>(type), data); #else static_cast<void>(target); static_cast<void>(level); static_cast<void>(offset); static_cast<void>(size); static_cast<void>(format); static_cast<void>(type); static_cast<void>(data); #endif }
MatrixX3f Surface::compute_normals(const MatrixX3f& rr, const MatrixX3i& tris) { printf("\tcomputing normals\n"); // first, compute triangle normals MatrixX3f r1(tris.rows(),3); MatrixX3f r2(tris.rows(),3); MatrixX3f r3(tris.rows(),3); for(qint32 i = 0; i < tris.rows(); ++i) { r1.row(i) = rr.row(tris(i, 0)); r2.row(i) = rr.row(tris(i, 1)); r3.row(i) = rr.row(tris(i, 2)); } MatrixX3f x = r2 - r1; MatrixX3f y = r3 - r1; MatrixX3f tri_nn(x.rows(),y.cols()); tri_nn.col(0) = x.col(1).cwiseProduct(y.col(2)) - x.col(2).cwiseProduct(y.col(1)); tri_nn.col(1) = x.col(2).cwiseProduct(y.col(0)) - x.col(0).cwiseProduct(y.col(2)); tri_nn.col(2) = x.col(0).cwiseProduct(y.col(1)) - x.col(1).cwiseProduct(y.col(0)); // Triangle normals and areas MatrixX3f tmp = tri_nn.cwiseProduct(tri_nn); VectorXf normSize = tmp.rowwise().sum(); normSize = normSize.cwiseSqrt(); for(qint32 i = 0; i < normSize.size(); ++i) if(normSize(i) != 0) tri_nn.row(i) /= normSize(i); MatrixX3f nn = MatrixX3f::Zero(rr.rows(), 3); for(qint32 p = 0; p < tris.rows(); ++p) { Vector3i verts = tris.row(p); for(qint32 j = 0; j < verts.size(); ++j) nn.row(verts(j)) = tri_nn.row(p); } tmp = nn.cwiseProduct(nn); normSize = tmp.rowwise().sum(); normSize = normSize.cwiseSqrt(); for(qint32 i = 0; i < normSize.size(); ++i) if(normSize(i) != 0) nn.row(i) /= normSize(i); return nn; }
void setScalarAsFloat(T* data, Vector3i position, Vector3i size, float value, uchar channel, uchar nrOfChannels) { if(position.x() < 0 || position.y() < 0 || position.z() < 0 || position.x() > size.x()-1 || position.y() > size.y()-1 || position.z() > size.z()-1 || channel >= nrOfChannels) throw OutOfBoundsException(); data[(position.x() + position.y()*size.x() + position.z()*size.x()*size.y())*nrOfChannels + channel] = value; }
bool Box::contains(const Vector3i& point) const { return point.x() >= m_llf.x() && point.y() >= m_llf.y() && point.z() >= m_llf.z() && m_urb.x() >= point.x() && m_urb.y() >= point.y() && m_urb.z() >= point.z(); }
InitialParticle::InitialParticle(Vector3i position, Vector3i color, int id) : position(position), color(color), id(id) { streakLines = new std::list<Particle*>(); streakLines->push_back(new Particle(position.toMyVector3D(), color, id, position.toMyVector3D())); }
Array VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channel, Vector3i min, Vector3i max) { uint64_t time_before = OS::get_singleton()->get_ticks_usec(); ERR_FAIL_COND_V(_library.is_null(), Array()); ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Array()); const VoxelLibrary &library = **_library; for (unsigned int i = 0; i < MAX_MATERIALS; ++i) { Arrays &a = _arrays[i]; a.positions.clear(); a.normals.clear(); a.uvs.clear(); a.colors.clear(); a.indices.clear(); } float baked_occlusion_darkness; if (_bake_occlusion) baked_occlusion_darkness = _baked_occlusion_darkness / 3.0; // The technique is Culled faces. // Could be improved with greedy meshing: https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/ // However I don't feel it's worth it yet: // - Not so much gain for organic worlds with lots of texture variations // - Works well with cubes but not with any shape // - Slower // => Could be implemented in a separate class? // Data must be padded, hence the off-by-one Vector3i::sort_min_max(min, max); const Vector3i pad(1, 1, 1); min.clamp_to(pad, max); max.clamp_to(min, buffer.get_size() - pad); int index_offset = 0; // Iterate 3D padded data to extract voxel faces. // This is the most intensive job in this class, so all required data should be as fit as possible. // The buffer we receive MUST be dense (i.e not compressed, and channels allocated). // That means we can use raw pointers to voxel data inside instead of using the higher-level getters, // and then save a lot of time. uint8_t *type_buffer = buffer.get_channel_raw(Voxel::CHANNEL_TYPE); // _ // | \ // /\ \\ // / /|\\\ // | |\ \\\ // | \_\ \\| // | | ) // \ | | // \ / CRASH_COND(type_buffer == NULL); //CRASH_COND(memarr_len(type_buffer) != buffer.get_volume() * sizeof(uint8_t)); // Build lookup tables so to speed up voxel access. // These are values to add to an address in order to get given neighbor. int row_size = buffer.get_size().y; int deck_size = buffer.get_size().x * row_size; int side_neighbor_lut[Cube::SIDE_COUNT]; side_neighbor_lut[Cube::SIDE_LEFT] = row_size; side_neighbor_lut[Cube::SIDE_RIGHT] = -row_size; side_neighbor_lut[Cube::SIDE_BACK] = -deck_size; side_neighbor_lut[Cube::SIDE_FRONT] = deck_size; side_neighbor_lut[Cube::SIDE_BOTTOM] = -1; side_neighbor_lut[Cube::SIDE_TOP] = 1; int edge_neighbor_lut[Cube::EDGE_COUNT]; edge_neighbor_lut[Cube::EDGE_BOTTOM_BACK] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK]; edge_neighbor_lut[Cube::EDGE_BOTTOM_FRONT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT]; edge_neighbor_lut[Cube::EDGE_BOTTOM_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_LEFT]; edge_neighbor_lut[Cube::EDGE_BOTTOM_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_RIGHT]; edge_neighbor_lut[Cube::EDGE_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT]; edge_neighbor_lut[Cube::EDGE_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT]; edge_neighbor_lut[Cube::EDGE_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT]; edge_neighbor_lut[Cube::EDGE_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT]; edge_neighbor_lut[Cube::EDGE_TOP_BACK] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK]; edge_neighbor_lut[Cube::EDGE_TOP_FRONT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT]; edge_neighbor_lut[Cube::EDGE_TOP_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_LEFT]; edge_neighbor_lut[Cube::EDGE_TOP_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_RIGHT]; int corner_neighbor_lut[Cube::CORNER_COUNT]; corner_neighbor_lut[Cube::CORNER_BOTTOM_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT]; corner_neighbor_lut[Cube::CORNER_BOTTOM_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT]; corner_neighbor_lut[Cube::CORNER_BOTTOM_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT]; corner_neighbor_lut[Cube::CORNER_BOTTOM_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT]; corner_neighbor_lut[Cube::CORNER_TOP_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT]; corner_neighbor_lut[Cube::CORNER_TOP_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT]; corner_neighbor_lut[Cube::CORNER_TOP_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT]; corner_neighbor_lut[Cube::CORNER_TOP_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT]; uint64_t time_prep = OS::get_singleton()->get_ticks_usec() - time_before; time_before = OS::get_singleton()->get_ticks_usec(); for (unsigned int z = min.z; z < max.z; ++z) { for (unsigned int x = min.x; x < max.x; ++x) { for (unsigned int y = min.y; y < max.y; ++y) { // min and max are chosen such that you can visit 1 neighbor away from the current voxel without size check // TODO In this intensive routine, there is a way to make voxel access fastest by getting a pointer to the channel, // and using offset lookup to get neighbors rather than going through get_voxel validations int voxel_index = y + x * row_size + z * deck_size; int voxel_id = type_buffer[voxel_index]; if (voxel_id != 0 && library.has_voxel(voxel_id)) { const Voxel &voxel = library.get_voxel_const(voxel_id); Arrays &arrays = _arrays[voxel.get_material_id()]; // Hybrid approach: extract cube faces and decimate those that aren't visible, // and still allow voxels to have geometry that is not a cube // Sides for (unsigned int side = 0; side < Cube::SIDE_COUNT; ++side) { const PoolVector<Vector3> &positions = voxel.get_model_side_positions(side); int vertex_count = positions.size(); if (vertex_count != 0) { int neighbor_voxel_id = type_buffer[voxel_index + side_neighbor_lut[side]]; // TODO Better face visibility test if (is_face_visible(library, voxel, neighbor_voxel_id)) { // The face is visible int shaded_corner[8] = { 0 }; if (_bake_occlusion) { // Combinatory solution for https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/ for (unsigned int j = 0; j < 4; ++j) { unsigned int edge = Cube::g_side_edges[side][j]; int edge_neighbor_id = type_buffer[voxel_index + edge_neighbor_lut[edge]]; if (!is_transparent(library, edge_neighbor_id)) { shaded_corner[Cube::g_edge_corners[edge][0]] += 1; shaded_corner[Cube::g_edge_corners[edge][1]] += 1; } } for (unsigned int j = 0; j < 4; ++j) { unsigned int corner = Cube::g_side_corners[side][j]; if (shaded_corner[corner] == 2) { shaded_corner[corner] = 3; } else { int corner_neigbor_id = type_buffer[voxel_index + corner_neighbor_lut[corner]]; if (!is_transparent(library, corner_neigbor_id)) { shaded_corner[corner] += 1; } } } } PoolVector<Vector3>::Read rv = positions.read(); PoolVector<Vector2>::Read rt = voxel.get_model_side_uv(side).read(); // Subtracting 1 because the data is padded Vector3 pos(x - 1, y - 1, z - 1); // Append vertices of the faces in one go, don't use push_back { int append_index = arrays.positions.size(); arrays.positions.resize(arrays.positions.size() + vertex_count); Vector3 *w = arrays.positions.ptrw() + append_index; for (unsigned int i = 0; i < vertex_count; ++i) { w[i] = rv[i] + pos; } } { int append_index = arrays.uvs.size(); arrays.uvs.resize(arrays.uvs.size() + vertex_count); memcpy(arrays.uvs.ptrw() + append_index, rt.ptr(), vertex_count * sizeof(Vector2)); } { int append_index = arrays.normals.size(); arrays.normals.resize(arrays.normals.size() + vertex_count); Vector3 *w = arrays.normals.ptrw() + append_index; for (unsigned int i = 0; i < vertex_count; ++i) { w[i] = Cube::g_side_normals[side].to_vec3(); } } if (_bake_occlusion) { // Use color array int append_index = arrays.colors.size(); arrays.colors.resize(arrays.colors.size() + vertex_count); Color *w = arrays.colors.ptrw() + append_index; for (unsigned int i = 0; i < vertex_count; ++i) { Vector3 v = rv[i]; // General purpose occlusion colouring. // TODO Optimize for cubes // TODO Fix occlusion inconsistency caused by triangles orientation? Not sure if worth it float shade = 0; for (unsigned int j = 0; j < 4; ++j) { unsigned int corner = Cube::g_side_corners[side][j]; if (shaded_corner[corner]) { float s = baked_occlusion_darkness * static_cast<float>(shaded_corner[corner]); float k = 1.0 - Cube::g_corner_position[corner].distance_to(v); if (k < 0.0) k = 0.0; s *= k; if (s > shade) shade = s; } } float gs = 1.0 - shade; w[i] = Color(gs, gs, gs); } } const PoolVector<int> &side_indices = voxel.get_model_side_indices(side); PoolVector<int>::Read ri = side_indices.read(); unsigned int index_count = side_indices.size(); { int i = arrays.indices.size(); arrays.indices.resize(arrays.indices.size() + index_count); int *w = arrays.indices.ptrw(); for(unsigned int j = 0; j < index_count; ++j) { w[i++] = index_offset + ri[j]; } } index_offset += vertex_count; } } } // Inside if (voxel.get_model_positions().size() != 0) { // TODO Get rid of push_backs const PoolVector<Vector3> &vertices = voxel.get_model_positions(); int vertex_count = vertices.size(); PoolVector<Vector3>::Read rv = vertices.read(); PoolVector<Vector3>::Read rn = voxel.get_model_normals().read(); PoolVector<Vector2>::Read rt = voxel.get_model_uv().read(); Vector3 pos(x - 1, y - 1, z - 1); for (unsigned int i = 0; i < vertex_count; ++i) { arrays.normals.push_back(rn[i]); arrays.uvs.push_back(rt[i]); arrays.positions.push_back(rv[i] + pos); } if(_bake_occlusion) { // TODO handle ambient occlusion on inner parts arrays.colors.push_back(Color(1,1,1)); } const PoolVector<int> &indices = voxel.get_model_indices(); PoolVector<int>::Read ri = indices.read(); unsigned int index_count = indices.size(); for(unsigned int i = 0; i < index_count; ++i) { arrays.indices.push_back(index_offset + ri[i]); } index_offset += vertex_count; } } } } } uint64_t time_meshing = OS::get_singleton()->get_ticks_usec() - time_before; time_before = OS::get_singleton()->get_ticks_usec(); // Commit mesh // print_line(String("Made mesh v: ") + String::num(_arrays[0].positions.size()) // + String(", i: ") + String::num(_arrays[0].indices.size())); Array surfaces; // TODO We could return a single byte array and use Mesh::add_surface down the line? for (int i = 0; i < MAX_MATERIALS; ++i) { const Arrays &arrays = _arrays[i]; if (arrays.positions.size() != 0) { /*print_line("Arrays:"); for(int i = 0; i < arrays.positions.size(); ++i) print_line(String(" P {0}").format(varray(arrays.positions[i]))); for(int i = 0; i < arrays.normals.size(); ++i) print_line(String(" N {0}").format(varray(arrays.normals[i]))); for(int i = 0; i < arrays.uvs.size(); ++i) print_line(String(" UV {0}").format(varray(arrays.uvs[i])));*/ Array mesh_arrays; mesh_arrays.resize(Mesh::ARRAY_MAX); { PoolVector<Vector3> positions; PoolVector<Vector2> uvs; PoolVector<Vector3> normals; PoolVector<Color> colors; PoolVector<int> indices; raw_copy_to(positions, arrays.positions); raw_copy_to(uvs, arrays.uvs); raw_copy_to(normals, arrays.normals); raw_copy_to(colors, arrays.colors); raw_copy_to(indices, arrays.indices); mesh_arrays[Mesh::ARRAY_VERTEX] = positions; mesh_arrays[Mesh::ARRAY_TEX_UV] = uvs; mesh_arrays[Mesh::ARRAY_NORMAL] = normals; mesh_arrays[Mesh::ARRAY_COLOR] = colors; mesh_arrays[Mesh::ARRAY_INDEX] = indices; } surfaces.append(mesh_arrays); } } uint64_t time_commit = OS::get_singleton()->get_ticks_usec() - time_before; //print_line(String("P: {0}, M: {1}, C: {2}").format(varray(time_prep, time_meshing, time_commit))); return surfaces; }
/** Imprints the piece in the specified chunk. Assumes they intersect. */ void ImprintInChunk(cChunkDesc & a_ChunkDesc, const Vector3i & a_Pos, int a_NumCCWRotations) { int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; Vector3i Min = a_Pos; Min.Move(-BlockX, 0, -BlockZ); Vector3i Max = Min; Max.Move(m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1); ASSERT(Min.x < cChunkDef::Width); ASSERT(Min.z < cChunkDef::Width); ASSERT(Max.x >= 0); ASSERT(Max.z >= 0); if (Min.x >= 0) { // Draw the XM wall: a_ChunkDesc.FillRelCuboid(Min.x, Min.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16); } if (Min.z >= 0) { // Draw the ZM wall: a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Min.z, Min.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16); } if (Max.x < cChunkDef::Width) { // Draw the XP wall: a_ChunkDesc.FillRelCuboid(Max.x, Max.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16); } if (Max.z < cChunkDef::Width) { // Draw the ZP wall: a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Max.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16); } // Draw all the connectors: for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr) { cConnector Conn = cPiece::RotateMoveConnector(*itr, a_NumCCWRotations, a_Pos.x, a_Pos.y, a_Pos.z); Conn.m_Pos.Move(-BlockX, 0, -BlockZ); if ( (Conn.m_Pos.x >= 0) && (Conn.m_Pos.x < cChunkDef::Width) && (Conn.m_Pos.z >= 0) && (Conn.m_Pos.z < cChunkDef::Width) ) { a_ChunkDesc.SetBlockTypeMeta(Conn.m_Pos.x, Conn.m_Pos.y, Conn.m_Pos.z, E_BLOCK_WOOL, itr->m_Type % 16); } /* // TODO: Frame the connectors switch (itr->m_Direction) { case BLOCK_FACE_XM: case BLOCK_FACE_XP: { // TODO break; } case BLOCK_FACE_ZM: case BLOCK_FACE_ZP: { // TODO break; } } */ } // for itr - m_Connectors[] }
int spheroidsToSTL(const string& out, const shared_ptr<DemField>& dem, Real tol, const string& solid, int mask, bool append, bool clipCell, bool merge){ if(tol==0 || isnan(tol)) throw std::runtime_error("tol must be non-zero."); #ifndef WOO_GTS if(merge) throw std::runtime_error("woo.triangulated.spheroidsToSTL: merge=True only possible in builds with the 'gts' feature."); #endif // first traversal to find reference radius auto particleOk=[&](const shared_ptr<Particle>&p){ return (mask==0 || (p->mask & mask)) && (p->shape->isA<Sphere>() || p->shape->isA<Ellipsoid>() || p->shape->isA<Capsule>()); }; int numTri=0; if(tol<0){ LOG_DEBUG("tolerance is negative, taken as relative to minimum radius."); Real minRad=Inf; for(const auto& p: *dem->particles){ if(particleOk(p)) minRad=min(minRad,p->shape->equivRadius()); } if(isinf(minRad) || isnan(minRad)) throw std::runtime_error("Minimum radius not found (relative tolerance specified); no matching particles?"); tol=-minRad*tol; LOG_DEBUG("Minimum radius "<<minRad<<"."); } LOG_DEBUG("Triangulation tolerance is "<<tol); std::ofstream stl(out,append?(std::ofstream::app|std::ofstream::binary):std::ofstream::binary); // binary better, anyway if(!stl.good()) throw std::runtime_error("Failed to open output file "+out+" for writing."); Scene* scene=dem->scene; if(!scene) throw std::logic_error("DEM field has not associated scene?"); // periodicity, cache that for later use AlignedBox3r cell; /* wasteful memory-wise, but we need to store the whole triangulation in case *merge* is in effect, when it is only an intermediary result and will not be output as-is */ vector<vector<Vector3r>> ppts; vector<vector<Vector3i>> ttri; vector<Particle::id_t> iid; for(const auto& p: *dem->particles){ if(!particleOk(p)) continue; const auto sphere=dynamic_cast<Sphere*>(p->shape.get()); const auto ellipsoid=dynamic_cast<Ellipsoid*>(p->shape.get()); const auto capsule=dynamic_cast<Capsule*>(p->shape.get()); vector<Vector3r> pts; vector<Vector3i> tri; if(sphere || ellipsoid){ Real r=sphere?sphere->radius:ellipsoid->semiAxes.minCoeff(); // 1 is for icosahedron int tess=ceil(M_PI/(5*acos(1-tol/r))); LOG_DEBUG("Tesselation level for #"<<p->id<<": "<<tess); tess=max(tess,0); auto uSphTri(CompUtils::unitSphereTri20(/*0 for icosahedron*/max(tess-1,0))); const auto& uPts=std::get<0>(uSphTri); // unit sphere point coords pts.resize(uPts.size()); const auto& node=(p->shape->nodes[0]); Vector3r scale=(sphere?sphere->radius*Vector3r::Ones():ellipsoid->semiAxes); for(size_t i=0; i<uPts.size(); i++){ pts[i]=node->loc2glob(uPts[i].cwiseProduct(scale)); } tri=std::get<1>(uSphTri); // this makes a copy, but we need out own for capsules } if(capsule){ #ifdef WOO_VTK int subdiv=max(4.,ceil(M_PI/(acos(1-tol/capsule->radius)))); std::tie(pts,tri)=VtkExport::triangulateCapsule(static_pointer_cast<Capsule>(p->shape),subdiv); #else throw std::runtime_error("Triangulation of capsules is (for internal and entirely fixable reasons) only available when compiled with the 'vtk' features."); #endif } // do not write out directly, store first for later ppts.push_back(pts); ttri.push_back(tri); LOG_TRACE("#"<<p->id<<" triangulated: "<<tri.size()<<","<<pts.size()<<" faces,vertices."); if(scene->isPeriodic){ // make sure we have aabb, in skewed coords and such if(!p->shape->bound){ // this is a bit ugly, but should do the trick; otherwise we would recompute all that ourselves here if(sphere) Bo1_Sphere_Aabb().go(p->shape); else if(ellipsoid) Bo1_Ellipsoid_Aabb().go(p->shape); else if(capsule) Bo1_Capsule_Aabb().go(p->shape); } assert(p->shape->bound); const AlignedBox3r& box(p->shape->bound->box); AlignedBox3r cell(Vector3r::Zero(),scene->cell->getSize()); // possibly in skewed coords // central offset Vector3i off0; scene->cell->canonicalizePt(p->shape->nodes[0]->pos,off0); // computes off0 Vector3i off; // offset from the original cell //cerr<<"#"<<p->id<<" at "<<p->shape->nodes[0]->pos.transpose()<<", off0="<<off0<<endl; for(off[0]=off0[0]-1; off[0]<=off0[0]+1; off[0]++) for(off[1]=off0[1]-1; off[1]<=off0[1]+1; off[1]++) for(off[2]=off0[2]-1; off[2]<=off0[2]+1; off[2]++){ Vector3r dx=scene->cell->intrShiftPos(off); //cerr<<" off="<<off.transpose()<<", dx="<<dx.transpose()<<endl; AlignedBox3r boxOff(box); boxOff.translate(dx); //cerr<<" boxOff="<<boxOff.min()<<";"<<boxOff.max()<<" | cell="<<cell.min()<<";"<<cell.max()<<endl; if(boxOff.intersection(cell).isEmpty()) continue; // copy the entire triangulation, offset by dx vector<Vector3r> pts2(pts); for(auto& p: pts2) p+=dx; vector<Vector3i> tri2(tri); // same topology ppts.push_back(pts2); ttri.push_back(tri2); LOG_TRACE(" offset "<<off.transpose()<<": #"<<p->id<<": "<<tri2.size()<<","<<pts2.size()<<" faces,vertices."); } } } if(!merge){ LOG_DEBUG("Will export (unmerged) "<<ppts.size()<<" particles to STL."); stl<<"solid "<<solid<<"\n"; for(size_t i=0; i<ppts.size(); i++){ const auto& pts(ppts[i]); const auto& tri(ttri[i]); LOG_TRACE("Exporting "<<i<<" with "<<tri.size()<<" faces."); for(const Vector3i& t: tri){ Vector3r pp[]={pts[t[0]],pts[t[1]],pts[t[2]]}; // skip triangles which are entirely out of the canonical periodic cell if(scene->isPeriodic && clipCell && (!scene->cell->isCanonical(pp[0]) && !scene->cell->isCanonical(pp[1]) && !scene->cell->isCanonical(pp[2]))) continue; numTri++; Vector3r n=(pp[1]-pp[0]).cross(pp[2]-pp[1]).normalized(); stl<<" facet normal "<<n.x()<<" "<<n.y()<<" "<<n.z()<<"\n"; stl<<" outer loop\n"; for(auto p: {pp[0],pp[1],pp[2]}){ stl<<" vertex "<<p[0]<<" "<<p[1]<<" "<<p[2]<<"\n"; } stl<<" endloop\n"; stl<<" endfacet\n"; } } stl<<"endsolid "<<solid<<"\n"; stl.close(); return numTri; } #if WOO_GTS /***** Convert all triangulation to GTS surfaces, find their distances, isolate connected components, merge these components incrementally and write to STL *****/ // total number of points const size_t N(ppts.size()); // bounds for collision detection struct Bound{ Bound(Real _coord, int _id, bool _isMin): coord(_coord), id(_id), isMin(_isMin){}; Bound(): coord(NaN), id(-1), isMin(false){}; // just for allocation Real coord; int id; bool isMin; bool operator<(const Bound& b) const { return coord<b.coord; } }; vector<Bound> bounds[3]={vector<Bound>(2*N),vector<Bound>(2*N),vector<Bound>(2*N)}; /* construct GTS surface objects; all objects must be deleted explicitly! */ vector<GtsSurface*> ssurf(N); vector<vector<GtsVertex*>> vvert(N); vector<vector<GtsEdge*>> eedge(N); vector<AlignedBox3r> boxes(N); for(size_t i=0; i<N; i++){ LOG_TRACE("** Creating GTS surface for #"<<i<<", with "<<ttri[i].size()<<" faces, "<<ppts[i].size()<<" vertices."); AlignedBox3r box; // new surface object ssurf[i]=gts_surface_new(gts_surface_class(),gts_face_class(),gts_edge_class(),gts_vertex_class()); // copy over all vertices vvert[i].reserve(ppts[i].size()); eedge[i].reserve(size_t(1.5*ttri[i].size())); // each triangle consumes 1.5 edges, for closed surfs for(size_t v=0; v<ppts[i].size(); v++){ vvert[i].push_back(gts_vertex_new(gts_vertex_class(),ppts[i][v][0],ppts[i][v][1],ppts[i][v][2])); box.extend(ppts[i][v]); } // create faces, and create edges on the fly as needed std::map<std::pair<int,int>,int> edgeIndices; for(size_t t=0; t<ttri[i].size(); t++){ //const Vector3i& t(ttri[i][t]); //LOG_TRACE("Face with vertices "<<ttri[i][t][0]<<","<<ttri[i][t][1]<<","<<ttri[i][t][2]); Vector3i eIxs; for(int a:{0,1,2}){ int A(ttri[i][t][a]), B(ttri[i][t][(a+1)%3]); auto AB=std::make_pair(min(A,B),max(A,B)); auto ABI=edgeIndices.find(AB); if(ABI==edgeIndices.end()){ // this edge not created yet edgeIndices[AB]=eedge[i].size(); // last index eIxs[a]=eedge[i].size(); //LOG_TRACE(" New edge #"<<eIxs[a]<<": "<<A<<"--"<<B<<" (length "<<(ppts[i][A]-ppts[i][B]).norm()<<")"); eedge[i].push_back(gts_edge_new(gts_edge_class(),vvert[i][A],vvert[i][B])); } else { eIxs[a]=ABI->second; //LOG_TRACE(" Found edge #"<<ABI->second<<" for "<<A<<"--"<<B); } } //LOG_TRACE(" New face: edges "<<eIxs[0]<<"--"<<eIxs[1]<<"--"<<eIxs[2]); GtsFace* face=gts_face_new(gts_face_class(),eedge[i][eIxs[0]],eedge[i][eIxs[1]],eedge[i][eIxs[2]]); gts_surface_add_face(ssurf[i],face); } // make sure the surface is OK if(!gts_surface_is_orientable(ssurf[i])) LOG_ERROR("Surface of #"+to_string(iid[i])+" is not orientable (expect troubles)."); if(!gts_surface_is_closed(ssurf[i])) LOG_ERROR("Surface of #"+to_string(iid[i])+" is not closed (expect troubles)."); assert(!gts_surface_is_self_intersecting(ssurf[i])); // copy bounds LOG_TRACE("Setting bounds of surf #"<<i); boxes[i]=box; for(int ax:{0,1,2}){ bounds[ax][2*i+0]=Bound(box.min()[ax],/*id*/i,/*isMin*/true); bounds[ax][2*i+1]=Bound(box.max()[ax],/*id*/i,/*isMin*/false); } } /* broad-phase collision detection between GTS surfaces only those will be probed with exact algorithms below and merged if needed */ for(int ax:{0,1,2}) std::sort(bounds[ax].begin(),bounds[ax].end()); vector<Bound>& bb(bounds[0]); // run the search along x-axis, does not matter really std::list<std::pair<int,int>> int0; // broad-phase intersections for(size_t i=0; i<2*N; i++){ if(!bb[i].isMin) continue; // only start with lower bound // go up to the upper bound, but handle overflow safely (no idea why it would happen here) as well for(size_t j=i+1; j<2*N && bb[j].id!=bb[i].id; j++){ if(bb[j].isMin) continue; // this is handled by symmetry #if EIGEN_VERSION_AT_LEAST(3,2,5) if(!boxes[bb[i].id].intersects(boxes[bb[j].id])) continue; // no intersection along all axes #else // old, less elegant if(boxes[bb[i].id].intersection(boxes[bb[j].id]).isEmpty()) continue; #endif int0.push_back(std::make_pair(min(bb[i].id,bb[j].id),max(bb[i].id,bb[j].id))); LOG_TRACE("Broad-phase collision "<<int0.back().first<<"+"<<int0.back().second); } } /* narrow-phase collision detection between GTS surface this must be done via gts_surface_inter_new, since gts_surface_distance always succeeds */ std::list<std::pair<int,int>> int1; for(const std::pair<int,int> ij: int0){ LOG_TRACE("Testing narrow-phase collision "<<ij.first<<"+"<<ij.second); #if 0 GtsRange gr1, gr2; gts_surface_distance(ssurf[ij.first],ssurf[ij.second],/*delta ??*/(gfloat).2,&gr1,&gr2); if(gr1.min>0 && gr2.min>0) continue; LOG_TRACE(" GTS reports collision "<<ij.first<<"+"<<ij.second<<" (min. distances "<<gr1.min<<", "<<gr2.min); #else GtsSurface *s1(ssurf[ij.first]), *s2(ssurf[ij.second]); GNode* t1=gts_bb_tree_surface(s1); GNode* t2=gts_bb_tree_surface(s2); GtsSurfaceInter* I=gts_surface_inter_new(gts_surface_inter_class(),s1,s2,t1,t2,/*is_open_1*/false,/*is_open_2*/false); GSList* l=gts_surface_intersection(s1,s2,t1,t2); // list of edges describing intersection int n1=g_slist_length(l); // extra check by looking at number of faces of the intersected surface #if 1 GtsSurface* s12=gts_surface_new(gts_surface_class(),gts_face_class(),gts_edge_class(),gts_vertex_class()); gts_surface_inter_boolean(I,s12,GTS_1_OUT_2); gts_surface_inter_boolean(I,s12,GTS_2_OUT_1); int n2=gts_surface_face_number(s12); gts_object_destroy(GTS_OBJECT(s12)); #endif gts_bb_tree_destroy(t1,TRUE); gts_bb_tree_destroy(t2,TRUE); gts_object_destroy(GTS_OBJECT(I)); g_slist_free(l); if(n1==0) continue; #if 1 if(n2==0){ LOG_ERROR("n1==0 but n2=="<<n2<<" (no narrow-phase collision)"); continue; } #endif LOG_TRACE(" GTS reports collision "<<ij.first<<"+"<<ij.second<<" ("<<n<<" edges describe the intersection)"); #endif int1.push_back(ij); } /* connected components on the graph: graph nodes are 0…(N-1), graph edges are in int1 see http://stackoverflow.com/a/37195784/761090 */ typedef boost::subgraph<boost::adjacency_list<boost::vecS,boost::vecS,boost::undirectedS,boost::property<boost::vertex_index_t,int>,boost::property<boost::edge_index_t,int>>> Graph; Graph graph(N); for(const auto& ij: int1) boost::add_edge(ij.first,ij.second,graph); vector<size_t> clusters(boost::num_vertices(graph)); size_t numClusters=boost::connected_components(graph,clusters.data()); for(size_t n=0; n<numClusters; n++){ // beginning cluster #n // first, count how many surfaces are in this cluster; if 1, things are easier int numThisCluster=0; int cluster1st=-1; for(size_t i=0; i<N; i++){ if(clusters[i]!=n) continue; numThisCluster++; if(cluster1st<0) cluster1st=(int)i; } GtsSurface* clusterSurf=NULL; LOG_DEBUG("Cluster "<<n<<" has "<<numThisCluster<<" surfaces."); if(numThisCluster==1){ clusterSurf=ssurf[cluster1st]; } else { clusterSurf=ssurf[cluster1st]; // surface of the cluster itself LOG_TRACE(" Initial cluster surface from "<<cluster1st<<"."); /* composed surface */ for(size_t i=0; i<N; i++){ if(clusters[i]!=n || ((int)i)==cluster1st) continue; LOG_TRACE(" Adding "<<i<<" to the cluster"); // ssurf[i] now belongs to cluster #n // trees need to be rebuild every time anyway, since the merged surface keeps changing in every cycle //if(gts_surface_face_number(clusterSurf)==0) LOG_ERROR("clusterSurf has 0 faces."); //if(gts_surface_face_number(ssurf[i])==0) LOG_ERROR("Surface #"<<i<<" has 0 faces."); GNode* t1=gts_bb_tree_surface(clusterSurf); GNode* t2=gts_bb_tree_surface(ssurf[i]); GtsSurfaceInter* I=gts_surface_inter_new(gts_surface_inter_class(),clusterSurf,ssurf[i],t1,t2,/*is_open_1*/false,/*is_open_2*/false); GtsSurface* merged=gts_surface_new(gts_surface_class(),gts_face_class(),gts_edge_class(),gts_vertex_class()); gts_surface_inter_boolean(I,merged,GTS_1_OUT_2); gts_surface_inter_boolean(I,merged,GTS_2_OUT_1); gts_object_destroy(GTS_OBJECT(I)); gts_bb_tree_destroy(t1,TRUE); gts_bb_tree_destroy(t2,TRUE); if(gts_surface_face_number(merged)==0){ LOG_ERROR("Cluster #"<<n<<": 0 faces after fusing #"<<i<<" (why?), adding #"<<i<<" separately!"); // this will cause an extra 1-particle cluster to be created clusters[i]=numClusters; numClusters+=1; } else { // not from global vectors (cleanup at the end), explicit delete! if(clusterSurf!=ssurf[cluster1st]) gts_object_destroy(GTS_OBJECT(clusterSurf)); clusterSurf=merged; } } } #if 0 LOG_TRACE(" GTS surface cleanups..."); pygts_vertex_cleanup(clusterSurf,.1*tol); // cleanup 10× smaller than tolerance pygts_edge_cleanup(clusterSurf); pygts_face_cleanup(clusterSurf); #endif LOG_TRACE(" STL: cluster "<<n<<" output"); stl<<"solid "<<solid<<"_"<<n<<"\n"; /* output cluster to STL here */ _gts_face_to_stl_data data(stl,scene,clipCell,numTri); gts_surface_foreach_face(clusterSurf,(GtsFunc)_gts_face_to_stl,(gpointer)&data); stl<<"endsolid\n"; if(clusterSurf!=ssurf[cluster1st]) gts_object_destroy(GTS_OBJECT(clusterSurf)); } // this deallocates also edges and vertices for(size_t i=0; i<ssurf.size(); i++) gts_object_destroy(GTS_OBJECT(ssurf[i])); return numTri; #endif /* WOO_GTS */ }
int run(int argc, char **argv) { if(argc != 7 && argc != 9) { cout << "Down-sample grid volume data by a scale" << endl; cout << "Syntax: mtsutil downSampleVolume 0 <grid_volume> <scale x> <scale y> <scale z> <target_volume>" << endl; cout << "Syntax: mtsutil downSampleVolume 1 <hgrid_volume_dict> <scale x> <scale y> <scale z> <prefix> <origin_suffix> <target_suffix>" << endl; return -1; } if (strcmp(argv[1], "0") == 0) { char *end_ptr = NULL; scale.x = strtol(argv[3], &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse integer value"); scale.y = strtol(argv[4], &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse integer value"); scale.z = strtol(argv[5], &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse integer value"); Properties props("gridvolume"); props.setString("filename", argv[2]); props.setBoolean("sendData", false); VolumeDataSource *originVol = static_cast<VolumeDataSource *> (PluginManager::getInstance()-> createObject(MTS_CLASS(VolumeDataSource), props)); originVol->configure(); Log(EInfo, "%s", originVol->getClass()->getName().c_str()); Log(EInfo, "res = (%d, %d, %d)", originVol->getResolution().x, originVol->getResolution().y, originVol->getResolution().z); Log(EInfo, "channels = %d", originVol->getChannels()); Log(EInfo, "min = (%.6f, %.6f, %.6f)", originVol->getAABB().min.x, originVol->getAABB().min.y, originVol->getAABB().min.z); Log(EInfo, "max = (%.6f, %.6f, %.6f)", originVol->getAABB().max.x, originVol->getAABB().max.y, originVol->getAABB().max.z); AABB bbox = originVol->getAABB(); GridData s; downSample(originVol, s); Log(EInfo, "finish down-sampling, save volume data to file"); ref<FileStream> outFile = new FileStream(argv[6], FileStream::ETruncReadWrite); writeVolume(s, bbox, originVol->getChannels(), outFile); } else if (strcmp(argv[1], "1") == 0) { char *end_ptr = NULL; scale.x = strtol(argv[3], &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse integer value"); scale.y = strtol(argv[4], &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse integer value"); scale.z = strtol(argv[5], &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse integer value"); fs::path resolved = Thread::getThread()->getFileResolver()->resolve(argv[2]); Log(EInfo, "Loading hierarchical grid dictrionary \"%s\"", argv[2]); ref<FileStream> stream = new FileStream(resolved, FileStream::EReadOnly); stream->setByteOrder(Stream::ELittleEndian); Float xmin = stream->readSingle(), ymin = stream->readSingle(), zmin = stream->readSingle(); Float xmax = stream->readSingle(), ymax = stream->readSingle(), zmax = stream->readSingle(); AABB aabb = AABB(Point(xmin, ymin, zmin), Point(xmax, ymax, zmax)); Vector3i res = Vector3i(stream); int nCells = res.x * res.y * res.z; int numBlocks = 0; while (!stream->isEOF()) { Vector3i block = Vector3i(stream); Assert(block.x >= 0 && block.y >= 0 && block.z >= 0 && block.x < res.x && block.y < res.y && block.z < res.z); Properties props("gridvolume"); props.setString("filename", formatString("%s%03i_%03i_%03i%s", argv[6], block.x, block.y, block.z, argv[7])); props.setBoolean("sendData", false); VolumeDataSource *ori = static_cast<VolumeDataSource *> (PluginManager::getInstance()-> createObject(MTS_CLASS(VolumeDataSource), props)); ori->configure(); //Log(EInfo, "Loading grid %03i_%03i_%03i", block.x, block.y, block.z); AABB bbox = ori->getAABB(); GridData s; downSample(ori, s); std::string filename(formatString("%s%03i_%03i_%03i%s", argv[6], block.x, block.y, block.z, argv[8])); ref<FileStream> outFile = new FileStream(filename.c_str(), FileStream::ETruncReadWrite); writeVolume(s, bbox, ori->getChannels(), outFile); ++numBlocks; } Log(EInfo, "%i blocks total, %s, resolution=%s", numBlocks, aabb.toString().c_str(), res.toString().c_str()); } return 0; }
void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { glTextureSubImage3DEXT(_id, target, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast<GLenum>(format), static_cast<GLenum>(type), data); }
void AbstractTexture::invalidateSubImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size) { glInvalidateTexSubImage(_id, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z()); }
bool MeshGenerator::marchingCube(const Vector3i &pos) { float afCubeValue[8]; Vector3f asEdgeVertex[12]; Vector3f asEdgeNorm[12]; // Calculate the position in the Cube Vector3f fPos(pos.x() * m_stepSize + m_min.x(), pos.y() * m_stepSize + m_min.y(), pos.z() * m_stepSize + m_min.z()); //Make a local copy of the values at the cube's corners for(int i = 0; i < 8; ++i) { afCubeValue[i] = m_cube->value(Vector3i(pos + Vector3i(a2iVertexOffset[i]))); } //Find which vertices are inside of the surface and which are outside long iFlagIndex = 0; for(int i = 0; i < 8; ++i) { if(afCubeValue[i] <= m_iso) { iFlagIndex |= 1<<i; } } //Find which edges are intersected by the surface long iEdgeFlags = aiCubeEdgeFlags[iFlagIndex]; // No intersections if the cube is entirely inside or outside of the surface if(iEdgeFlags == 0) { return false; } //Find the point of intersection of the surface with each edge //Then find the normal to the surface at those points for(int i = 0; i < 12; ++i) { //if there is an intersection on this edge if(iEdgeFlags & (1<<i)) { float fOffset = offset(afCubeValue[a2iEdgeConnection[i][0]], afCubeValue[a2iEdgeConnection[i][1]]); asEdgeVertex[i] = Vector3f( fPos.x() + (a2fVertexOffset[a2iEdgeConnection[i][0]][0] + fOffset * a2fEdgeDirection[i][0]) * m_stepSize, fPos.y() + (a2fVertexOffset[a2iEdgeConnection[i][0]][1] + fOffset * a2fEdgeDirection[i][1]) * m_stepSize, fPos.z() + (a2fVertexOffset[a2iEdgeConnection[i][0]][2] + fOffset * a2fEdgeDirection[i][2]) * m_stepSize); /// FIXME Optimize this to only calculate normals when required asEdgeNorm[i] = normal(asEdgeVertex[i]); } } // Store the triangles that were found, there can be up to five per cube for(int i = 0; i < 5; ++i) { if(a2iTriangleConnectionTable[iFlagIndex][3*i] < 0) break; int iVertex = 0; iEdgeFlags = a2iTriangleConnectionTable[iFlagIndex][3*i]; // Make sure we get the triangle winding the right way around! if (!m_reverseWinding) { for(int j = 0; j < 3; ++j) { iVertex = a2iTriangleConnectionTable[iFlagIndex][3*i+j]; m_indices.push_back(m_vertices.size()); m_normals.push_back(asEdgeNorm[iVertex]); m_vertices.push_back(asEdgeVertex[iVertex]); } } else { for(int j = 2; j >= 0; --j) { iVertex = a2iTriangleConnectionTable[iFlagIndex][3*i+j]; m_indices.push_back(m_vertices.size()); m_normals.push_back(-asEdgeNorm[iVertex]); m_vertices.push_back(asEdgeVertex[iVertex]); } } } return true; }
inline bool operator()(const Vector3i &a, const Vector3i &b) const { return a.distance_sq(center) < b.distance_sq(center); }
void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, InternalFormat internalFormat, const Vector3i& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) { glTextureImage3DEXT(_id, target, level, GLint(internalFormat), size.x(), size.y(), size.z(), 0, static_cast<GLenum>(format), static_cast<GLenum>(type), data); }