-
Notifications
You must be signed in to change notification settings - Fork 420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Rendering Replica models in the simulator (under CONSTRUCTION) #132
Changes from 3 commits
e7e23ed
542d34f
6885297
809ab0a
97eeb0f
17c982f
df7f34f
8773ddd
3ee45ed
940df4e
9aae2d8
161ba3f
e2ed28c
fb665b5
57593bb
da79cf6
dd6a0ae
62029e3
9f88219
0948307
fc92467
cfc92e2
92b35ea
0705779
d66a5d5
fd96621
3c7c963
48e00eb
1c6cb00
a2ee4a9
77ccc25
2cf1154
9fdfbdc
dcd693c
6ee58da
507ec12
f04d33c
c901eea
0de630b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -4,12 +4,16 @@ | |||||
|
||||||
#include "PTexMeshData.h" | ||||||
|
||||||
#include <fcntl.h> | ||||||
#include <sys/mman.h> | ||||||
#include <sys/stat.h> | ||||||
#include <fstream> | ||||||
#include <sstream> | ||||||
#include <unordered_map> | ||||||
#include <vector> | ||||||
|
||||||
#include <Corrade/Containers/Array.h> | ||||||
#include <Corrade/Containers/ArrayView.h> | ||||||
#include <Corrade/Utility/Directory.h> | ||||||
#include <Magnum/GL/BufferTextureFormat.h> | ||||||
#include <Magnum/ImageView.h> | ||||||
|
@@ -34,7 +38,10 @@ void PTexMeshData::load(const std::string& meshFile, | |||||
ASSERT(io::exists(atlasFolder)); | ||||||
|
||||||
// Parse parameters | ||||||
const auto& paramsFile = atlasFolder + "/parameters.json"; | ||||||
// careful: when using "join", no leading forward slash in the file name. | ||||||
// otherwise the corrade would think it is absolute path | ||||||
bigbike marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
const auto& paramsFile = | ||||||
Corrade::Utility::Directory::join(atlasFolder, "parameters.json"); | ||||||
ASSERT(io::exists(paramsFile)); | ||||||
const io::JsonDocument json = io::parseJsonFile(paramsFile); | ||||||
splitSize_ = json["splitSize"].GetDouble(); | ||||||
|
@@ -203,20 +210,23 @@ void PTexMeshData::calculateAdjacency(const PTexMeshData::MeshData& mesh, | |||||
|
||||||
std::unordered_map<uint64_t, std::vector<EdgeData>> edgeMap; | ||||||
|
||||||
size_t numFaces = mesh.ibo.size() / 4; | ||||||
// only works on quad meshes | ||||||
const int polygonStride = 4; | ||||||
size_t numFaces = mesh.ibo.size() / polygonStride; | ||||||
|
||||||
typedef std::unordered_map<uint64_t, std::vector<EdgeData>>::iterator | ||||||
EdgeIter; | ||||||
std::vector<EdgeIter> edgeIterators(numFaces * 4); | ||||||
std::vector<EdgeIter> edgeIterators(numFaces * polygonStride); | ||||||
|
||||||
// for each face | ||||||
for (int f = 0; f < numFaces; f++) { | ||||||
// for each edge | ||||||
for (int e = 0; e < 4; e++) { | ||||||
for (int e = 0; e < polygonStride; e++) { | ||||||
// add to edge to face map | ||||||
const int e_index = f * 4 + e; | ||||||
const int e_index = f * polygonStride + e; | ||||||
const uint32_t i0 = mesh.ibo[e_index]; | ||||||
const uint32_t i1 = mesh.ibo[f * 4 + ((e + 1) % 4)]; | ||||||
const uint32_t i1 = | ||||||
mesh.ibo[f * polygonStride + ((e + 1) % polygonStride)]; | ||||||
const uint64_t key = | ||||||
(uint64_t)std::min(i0, i1) << 32 | (uint32_t)std::max(i0, i1); | ||||||
|
||||||
|
@@ -236,11 +246,11 @@ void PTexMeshData::calculateAdjacency(const PTexMeshData::MeshData& mesh, | |||||
} | ||||||
} | ||||||
|
||||||
adjFaces.resize(numFaces * 4); | ||||||
adjFaces.resize(numFaces * polygonStride); | ||||||
|
||||||
for (int f = 0; f < numFaces; f++) { | ||||||
for (int e = 0; e < 4; e++) { | ||||||
const int e_index = f * 4 + e; | ||||||
for (int e = 0; e < polygonStride; e++) { | ||||||
const int e_index = f * polygonStride + e; | ||||||
auto it = edgeIterators[e_index]; | ||||||
const std::vector<EdgeData>& adj = it->second; | ||||||
|
||||||
|
@@ -267,13 +277,16 @@ void PTexMeshData::calculateAdjacency(const PTexMeshData::MeshData& mesh, | |||||
} | ||||||
|
||||||
// pack adjacent face and rotation into 32-bit int | ||||||
adjFaces[f * 4 + e] = (rot << ROTATION_SHIFT) | (adjFace & FACE_MASK); | ||||||
adjFaces[f * polygonStride + e] = | ||||||
(rot << ROTATION_SHIFT) | (adjFace & FACE_MASK); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
void PTexMeshData::loadMeshData(const std::string& meshFile) { | ||||||
PTexMeshData::MeshData originalMesh; | ||||||
|
||||||
std::cout << "start parsing PLY... " << std::endl; | ||||||
parsePLY(meshFile, originalMesh); | ||||||
|
||||||
submeshes_.clear(); | ||||||
|
@@ -583,7 +596,7 @@ void PTexMeshData::uploadBuffersToGPU(bool forceReload) { | |||||
currentMesh->ibo.setData(submeshes_[iMesh].ibo, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mosra: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am asking this question is because I observed the size of currentMesh->ibo.size() was 4x of the submeshes_[iMesh].ibo.size(). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The naming is making this harder than it should be, first I assumed the two Few lines below in the diff I see this -- could it be related? - .setCount(currentMesh->ibo.size() / 2)
+ .setCount(currentMesh->ibo.size()) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that is the problem. We actually need to pass the "number of primitives" to the setCount(), not the "number of bytes". That is why no matter if we divide it by 2, it will segfault anyway. Thank you for the confirmation. Yes, I also consider using the info from CPU-side, like you mentioned. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have any other example in your docs that shows how to correctly use ibo, vbo? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Primitives example expands on that, and the GL::Mesh documentation is very extensive. |
||||||
Magnum::GL::BufferUsage::StaticDraw); | ||||||
} | ||||||
std::cout << "... done" << std::endl; | ||||||
std::cout << "done" << std::endl; | ||||||
|
||||||
std::cout << "Calculating mesh adjacency... "; | ||||||
std::cout.flush(); | ||||||
|
@@ -594,6 +607,7 @@ void PTexMeshData::uploadBuffersToGPU(bool forceReload) { | |||||
for (int iMesh = 0; iMesh < submeshes_.size(); ++iMesh) { | ||||||
calculateAdjacency(submeshes_[iMesh], adjFaces[iMesh]); | ||||||
} | ||||||
std::cout << "... done" << std::endl; | ||||||
|
||||||
for (int iMesh = 0; iMesh < submeshes_.size(); ++iMesh) { | ||||||
auto& currentMesh = renderingBuffers_[iMesh]; | ||||||
|
@@ -602,35 +616,56 @@ void PTexMeshData::uploadBuffersToGPU(bool forceReload) { | |||||
currentMesh->abo); | ||||||
currentMesh->abo.setData(adjFaces[iMesh], | ||||||
Magnum::GL::BufferUsage::StaticDraw); | ||||||
|
||||||
// experiment code (may not work): | ||||||
currentMesh->mesh.setPrimitive(Magnum::GL::MeshPrimitive::LinesAdjacency) | ||||||
.setCount(currentMesh->ibo.size() / 2) | ||||||
.addVertexBuffer(currentMesh->vbo, 0, gfx::PTexMeshShader::Position{}) | ||||||
.setIndexBuffer(currentMesh->ibo, 0, | ||||||
Magnum::GL::MeshIndexType::UnsignedInt); | ||||||
} | ||||||
|
||||||
// load atlas data and upload them to GPU | ||||||
|
||||||
std::cout << "loading atlas textures: " << std::endl; | ||||||
for (size_t iMesh = 0; iMesh < renderingBuffers_.size(); ++iMesh) { | ||||||
const std::string rgbFile = | ||||||
atlasFolder_ + "/" + std::to_string(iMesh) + "-color-ptex.rgb"; | ||||||
if (!io::exists(rgbFile)) { | ||||||
ASSERT(false, "Can't find " + rgbFile); | ||||||
} | ||||||
const std::string rgbFile = Corrade::Utility::Directory::join( | ||||||
atlasFolder_, std::to_string(iMesh) + "-color-ptex.rgb"); | ||||||
|
||||||
ASSERT(io::exists(rgbFile), Error : Cannot find the rgb file); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's CORRADE_ASSERT() btw, which could make
Suggested change
Also, for ... 🤔 should I open a PR moving everything from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logging.h and io.h are legacy. |
||||||
|
||||||
std::cout << "\rLoading atlas " << iMesh + 1 << "/" | ||||||
<< renderingBuffers_.size() << "... "; | ||||||
<< renderingBuffers_.size() << " from " << rgbFile << "... "; | ||||||
std::cout.flush(); | ||||||
|
||||||
Cr::Containers::Array<const char, Cr::Utility::Directory::MapDeleter> data = | ||||||
Cr::Utility::Directory::mapRead(rgbFile); | ||||||
const int dim = static_cast<int>(std::sqrt(data.size() / 3)); // square | ||||||
const size_t numBytes = io::fileSize(rgbFile); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like to load the textures from the file. Such textures are not in common picture format (e.g., png, jpg, tga), but some customized format in binary. In ReplicaSDK, they mapped a texture (rgbFile) to the memory, and uploaded it to a texture (atlas). The code is as follows. const size_t numBytes = std::experimental::filesystem::file_size(rgbFile); @mosra : Do you think the current implementation is proper? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait wait but this is practically reverting #106 to what was there before, and that change was done in order to help with #84 (and besides that, reducing platform-specific code). The code you're showing is precisely what Is there any issue with the way it was done using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Allow me to reply this one first before I read the other comments. After reading your comment, assuming the mapRead() did exactly the same, then it means getting the "numBytes" using "data.size()" is incorrect. What is the correct way to get this number? I would change it back. (I am not aware of the #106 or #84 since I was on leave for a couple of months. Good to know.) Thank you very much for the comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh. The array returned from What does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good to know. It is also possible my testing code has some bugs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just tested it again. The numbers are identical. There must be something wrong in my previous debugging code. My bad. I sincerely apologize for the confusion. Sorry, Vladimir. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No problem ;) In any case, I'm not claiming my implementation is bug-free either, so if you see something strange with it, let me know. |
||||||
const int dim = static_cast<int>(std::sqrt(numBytes / 3)); // square | ||||||
|
||||||
// Open file | ||||||
int fd = open(std::string(rgbFile).c_str(), O_RDONLY, 0); | ||||||
// MAP_POPULATE does not work on mac. It is to reduce the penalty of page | ||||||
// faults. Code should be OK without it. void* mmappedData = mmap(NULL, | ||||||
// numBytes, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0); | ||||||
void* mmappedData = mmap(NULL, numBytes, PROT_READ, MAP_PRIVATE, fd, 0); | ||||||
|
||||||
Corrade::Containers::ArrayView<unsigned char> data( | ||||||
(unsigned char*)(mmappedData), numBytes); | ||||||
|
||||||
// atlas | ||||||
// the size of each image is dim x dim x 3 (RGB), which equals to numBytes | ||||||
Magnum::ImageView2D image(Magnum::PixelFormat::RGB8UI, {dim, dim}, data); | ||||||
renderingBuffers_[iMesh] | ||||||
->tex.setWrapping(Magnum::GL::SamplerWrapping::ClampToEdge) | ||||||
.setMagnificationFilter(Magnum::GL::SamplerFilter::Linear) | ||||||
.setMinificationFilter(Magnum::GL::SamplerFilter::Linear) | ||||||
// .setStorage(1, GL::TextureFormat::RGB8UI, image.size()) | ||||||
// .setStorage(1, Magnum::GL::TextureFormat::RGB8UI, image.size()) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mosra : There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was commited this way by @msavva in October 2018, I don't know what was the original reason :) Generally, calling If you are on linux you can run the viewer with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am developing everything on the Mac. I guess I will have to require a linux box. :) So here, if I understand you correctly, I should actively call setStorage(). Correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, or change the below to |
||||||
.setSubImage(0, {}, image); | ||||||
|
||||||
munmap(mmappedData, numBytes); | ||||||
close(fd); | ||||||
|
||||||
std::cout << "done" << std::endl; | ||||||
} | ||||||
std::cout << "... done" << std::endl; | ||||||
|
||||||
buffersOnGPU_ = true; | ||||||
} | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,14 +105,21 @@ bool ResourceManager::loadPTexMeshData(const AssetInfo& info, | |
// if this is a new file, load it and add it to the dictionary | ||
const std::string& filename = info.filepath; | ||
if (resourceDict_.count(filename) == 0) { | ||
const std::string atlasDir = | ||
Corrade::Utility::String::stripSuffix(filename, "ptex_quad_mesh.ply") + | ||
"ptex_textures"; | ||
const auto atlasDir = [=]()->std::string{ | ||
// backwards compatibility | ||
if (Corrade::Utility::String::endsWith(filename, "ptex_quad_mesh.ply")) { | ||
return (Corrade::Utility::String::stripSuffix(filename, "ptex_quad_mesh.ply") + | ||
"ptex_textures"); | ||
} | ||
// officially released Replica dataset | ||
return (Corrade::Utility::String::stripSuffix(filename, "mesh.ply") + | ||
"textures"); | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see why the lambda is needed if it's used just on a single place :) Also there's Directory::path() to make this an oneliner: const std::string atlasDir = Corrade::Utility::Directory::join(
Corrade::Utility::Directory::path(filename), "textures"); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new format is using "textures" as the folder name, while the old one was using "ptex_textures". Cannot put them in a single line. Well, I can use Ternary Operator instead of the lambda. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh well, sorry, missed that part, thought it's just cutting off a different filename 🙈 |
||
|
||
meshes_.emplace_back(std::make_unique<PTexMeshData>()); | ||
int index = meshes_.size() - 1; | ||
auto* pTexMeshData = dynamic_cast<PTexMeshData*>(meshes_[index].get()); | ||
pTexMeshData->load(filename, atlasDir); | ||
pTexMeshData->load(filename, atlasDir()); | ||
|
||
// update the dictionary | ||
resourceDict_.emplace(filename, MeshMetaData(index, index)); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would do
here instead of the comment :)