I have integrated 'Assimp' librairy to load my OBJ/MTL files components.
All works correctly.
But let's have a focus on a following MTL file example:
# Blender MTL File: 'plane.blend'
# Material Count: 1
newmtl PlaneMtl
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.640000 0.640000 0.640000
Ks 0.500000 0.500000 0.500000
Ni 1.000000
d 1.000000
illum 2
map_Ka ambient_texture.jpg
map_Kd diffuse_texture.jpg
map_Ks specular_texture.jpg
map_Bump bump_texture.jpg
And let's examine the following code:
aiMesh *pMesh = scene->mMeshes[idz];
aiMaterial *pMaterial = scene->mMaterials[pMesh->mMaterialIndex];
aiString ambient_texture_path, diffuse_texture_path, specular_texture_path, bump_texture_path;
pMaterial->GetTexture(aiTextureType_AMBIENT, 0, &ambient_texture_path);
pMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &diffuse_texture_path);
pMaterial->GetTexture(aiTextureType_SPECULAR, 0, &specular_texture_path);
pMaterial->GetTexture(aiTextureType_HEIGHT, 0, &bump_texture_path);
std::cout << "AmbientTexture: " << ambient_texture_path.C_Str() << std::endl;
std::cout << "DiffuseTexture: " << diffuse_texture_path.C_Str() << std::endl;
std::cout << "SpecularTexture: " << specular_texture_path.C_Str() << std::endl;
std::cout << "BumpTexture: " << bump_texture_path.C_Str() << std::endl;
Here's the output:
ambient_texture.jpg
diffuse_texture.jpg
specular_texture.jpg
bump_texture.jpg
As you can see all works perfectly and the keywords 'map_Ka, map_Kd, map_Ks and map_Bump' refer to ambient, diffuse, specular and bump (height) map respectively. So these keywords are correct.
But what about normal texture (for normal mapping) and displacement texture (for displacement mapping) for example ?
I tried to add the following lines in my MTL file to test:
map_Normal normal_texture.jpg
map_Disp disp_texture.jpg
using the code:
aiString normal_texture_path, displacement_texture_path;
pMaterial->GetTexture(aiTextureType_NORMALS, 0, &normal_texture_path);
pMaterial->GetTexture(aiTextureType_DISPLACEMENT, 0, &displacement_texture_path);
std::cout << "NormalTexture: " << normal_texture_path.C_Str() << std::endl;
std::cout << "DispTexture: " << displacement_texture_path.C_Str() << std::endl;
and the output:
NormalTexture:
DispTexture:
So the keyword 'map_Normal' and 'map_Disp' are not corrects and so are not part of Wavefront MTL documentation.
I couldn't try to find a correct and official documentation about WaveFront MTL format (only the ones on Wikipedia or tutorials nut nothing official and complete).
Does it exist an official documentation about Wavefront MTL and OBJ format with all the keywords explained within ?
If it's not the case does anyone knows the keywords for normal and displacement texture ?
I know this is an old question, but I needed to use normal maps, and I'm using Assimp and OBJ files, so I searched and found the answer to this. After looking at the source code of Assimp you can see in assimp/code/ObjFileMtlImporter.cpp:
static const std::string DiffuseTexture = "map_Kd";
static const std::string AmbientTexture = "map_Ka";
static const std::string SpecularTexture = "map_Ks";
static const std::string OpacityTexture = "map_d";
static const std::string EmissiveTexture = "map_emissive";
static const std::string EmissiveTexture_1 = "map_Ke";
static const std::string BumpTexture1 = "map_bump";
static const std::string BumpTexture2 = "map_Bump";
static const std::string BumpTexture3 = "bump";
static const std::string NormalTexture = "map_Kn";
static const std::string ReflectionTexture = "refl";
static const std::string DisplacementTexture = "disp";
static const std::string SpecularityTexture = "map_ns";
So as you can see, Assimp use map_Kn to refer to normal textures anddisp for displacement textures (confirmed when I loaded a model after modifying its MTL).
Alias/Wavefront is now so old and passed through so many owning companies that I very much doubt you will find an 'official' specification anywhere.
I suggest the excellent write-up by Paul Bourke, which includes the keywords details for bump and displacement maps. (But not normal maps - I don't think they were ever official for OBJ)
http://paulbourke.net/dataformats/mtl/
Hope this helps.
Related
First off, I'm aware of the CGAL GIS tutorial, but I just can't seem to copy properties from Point_set to surface mesh.
Any way, I'm loading the LIDAR point cloud to the point set as follows:
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Point = Kernel::Point_3;
using Point_set = CGAL::Point_set_3<Point>;
std::ifstream ifile("input.ply", std::ios_base::binary);
ifile >> point_set;
std::cerr << point_set.size() << " point(s) read" << std::endl;
ifile.close();
I can get the properties via
auto props = point_set.properties();
for (const auto& item : props)
std::cerr << item << std::endl;
// I do know that there exist property "classification" that is of unsigned char type
Point_set::Property_map<unsigned char> original_class_map
= point_set.property_map<unsigned char>("classification").first;
Then, I had tried to set the mesh and had added vertex property, using the code from above mentioned CGAL tutorial. The code below set the point's z coordinate as a property.
auto idx_to_point_with_info
= [&](const Point_set::Index& idx) -> std::pair<Point, Point_set::Index> {
return std::make_pair(point_set.point(idx), idx);
};
using Vbi = CGAL::Triangulation_vertex_base_with_info_2<Point_set::Index, Projection_traits>;
using Fbi = CGAL::Triangulation_face_base_with_info_2<int, Projection_traits>;
using TDS = CGAL::Triangulation_data_structure_2<Vbi, Fbi>;
using TIN_with_info = CGAL::Delaunay_triangulation_2<Projection_traits, TDS>;
TIN_with_info tin_with_info(
boost::make_transform_iterator(point_set.begin(), idx_to_point_with_info),
boost::make_transform_iterator(point_set.end(), idx_to_point_with_info));
auto classification_value = [&](const TIN_with_info::Vertex_handle vh) -> double
{
return vh->point().z();
};
for (TIN_with_info::Vertex_handle vh : tin_with_info.all_vertex_handles())
{ // should work without classification_value, just plain vh->info() = vh->point().z();
vh->info() = classification_value(vh);
}
using Mesh = CGAL::Surface_mesh<Point>;
Mesh tin_class_mesh;
Mesh::Property_map<Mesh::Vertex_index, double> class_map
= tin_class_mesh.add_property_map<Mesh::Vertex_index, double>("v:class").first;
CGAL::copy_face_graph(tin_with_info, tin_class_mesh,
CGAL::parameters::vertex_to_vertex_output_iterator(
boost::make_function_output_iterator(class_lambda)));
std::cerr << tin_class_mesh.number_of_vertices() << " vs " << point_set.size() <<std::endl;
Now, this works just fine, I had successfully set the z coordinate as a property on a mesh.
But, I just can't figure out how can I copy the classification property from the point_set to the tin_class_mesh. I know that I'd need to change double to unsigned char in the code, but I don't know how to access the property from the point_set and assign it to the corresponding vertex in tin_class_mesh. What am I doing wrong?
As a side note, the interesting part here is that the number of tin_colored_mesh.number_of_vertices() differs slightly from the point_set.size(). Why is that?
I want to simplify or edge collapse a mesh read from .off file as a combinatorial map using CGAL
std::ifstream ifile(fileName.toStdString().c_str());
if (ifile)
{
CGAL::load_off(lcc, ifile);
lcc.display_characteristics(std::cout)<<", is_valid="<<CGAL::is_valid(lcc)<<std::endl;
}
namespace SMS = CGAL::Surface_mesh_simplification ;
SMS::Count_stop_predicate<LCC> stop(lcc.number_of_halfedges()/2 - 1);
int r = SMS::edge_collapse
(lcc
,stop
,CGAL::parameters::halfedge_index_map(get(CGAL::halfedge_index, lcc))
.vertex_index_map(get(boost::vertex_index, lcc))
.get_cost(SMS::Edge_length_cost<LCC>())
.get_placement(SMS::Midpoint_placement<LCC>())
);
std::cout << "\nFinished...\n" << r << " edges removed.\n"
<< (lcc.number_of_darts()/2) << " final edges.\n" ;
lcc.display_characteristics(std::cout)<<", is_valid="<<CGAL::is_valid(lcc)<<std::endl;
the output :
#Darts=16674, #0-cells=2775, #1-cells=8337, #2-cells=5558, #ccs=1, is_valid=1
Finished...
0 edges removed.
8337 final edges.
#Darts=16674, #0-cells=2775, #1-cells=8337, #2-cells=5558, #ccs=1, is_valid=1
the method do nothing , I tried more than .off file and it's preview it properly but it cannot simplify it
I appreciate any help .
See the example given here, it works perfectly.
I saved my training data (maybe float vectors) in some files, and tried to load it as a Tensor using Tensorflow C++ reader class.
Here is my code.
using namespace tensorflow;
using namespace tensorflow::ops;
using namespace tensorflow::sparse;
Scope root = Scope::NewRootScope();
auto indexReader = FixedLengthRecordReader(root, sizeof(uint32_t));
auto queue = FIFOQueue(root, {DataType::DT_STRING});
auto file = Input::Initializer(std::string("mydata.feat"));
std::cerr << file.tensor.DebugString() << std::endl;
auto enqueue = QueueEnqueue(root, queue, {file});
std::cerr << Input(QueueSize(root, queue).size).tensor().DebugString() << std::endl;
auto rawInputIndex = ReaderRead(root, indexReader, queue);
std::cerr << Input(rawInputIndex.key).tensor().DebugString() << std::endl;
auto decodedInputIndex = DecodeRaw(root, rawInputIndex.value, DataType::DT_UINT8);
std::cerr << Input(decodedInputIndex.output).tensor().DebugString() << std::endl;
It is compiled very well but the cerr shows always empty Tensor. (below is execution result of my program on shell)
Tensor<type: string shape: [] values: mydata.feat>
Tensor<type: float shape: [0] values: >
Tensor<type: float shape: [0] values: >
Tensor<type: float shape: [0] values: >
I don't know why it doesn't work.
Or, is there any C++ example code for class ReaderRead or class FIFOQueue? I cannot find it anywhere...
What you're doing is building a graph. To run this graph you need to create a Session and run it. See the label_image example on the tensorflow codebase for an example of how to do this.
How to load and write .mhd/.raw format 3D images in ITK? I have tried to use the following code but it is not getting loaded as the dimension of the loaded image is displayed as 0,0,0.
Can someone please point out the mistake I am making?
typedef float InputPixelType;
const unsigned int DimensionOfRaw = 3;
typedef itk::Image< InputPixelType, DimensionOfRaw > InputImageType;
//typedef itk::RawImageIO<InputPixelType, DimensionOfRaw> ImageIOType;
typedef itk::ImageFileReader<InputImageType > ReaderType;
/*
* --------------------Loader and saver of Raws, as well the function that takes a resulting (from inference matrix/vector) and creates a Raw out of it.-----------------------
*/
InputImageType::Pointer loadRawImageItk( std::string RawFullFilepathname, ReaderType::Pointer & RawImageIO ) {
//http://www.itk.org/Doxygen/html/classitk_1_1Image.html
//http://www.itk.org/Doxygen/html/classitk_1_1ImageFileReader.html
typedef itk::ImageFileReader<InputImageType> ReaderType;
ReaderType::Pointer reader = ReaderType::New();
reader->SetFileName(RawFullFilepathname);
//ImageIOType::Pointer RawImageIO = ImageIOType::New();
reader->SetImageIO( RawImageIO );
try {
reader->Update();
} catch (itk::ExceptionObject& e) {
std::cerr << e.GetDescription() << std::endl;
exit(1); // You can choose to do something else, of course.
}
//InputImageType::Pointer inputImage = reader->GetOutput();
InputImageType::Pointer inputImage = reader->GetOutput();
return inputImage;
}
int saveRawImageItk( std::string RawFullFilepathname, InputImageType::Pointer & outputImageItkType , ImageIOType::Pointer & RawImageIO) {
std::cout << "Saving image to: " << RawFullFilepathname << "\n";
typedef itk::ImageFileWriter< InputImageType > Writer1Type;
Writer1Type::Pointer writer1 = Writer1Type::New();
writer1->SetInput( outputImageItkType );
writer1->SetFileName( RawFullFilepathname );
writer1->SetImageIO( RawImageIO ); //seems like this is useless.
// Execution of the writer is triggered by invoking the \code{Update()} method.
try
{
writer1->Update();
}
catch (itk::ExceptionObject & e)
{
std::cerr << "exception in file writer " << std::endl;
std::cerr << e.GetDescription() << std::endl;
std::cerr << e.GetLocation() << std::endl;
return 1;
}
return 0;
}
I have just read the mhd and raw files in Python successfully using the following SimpleITK code:
import SimpleITK as sitk
import numpy as np
def load_itk_image(filename):
itkimage = sitk.ReadImage(filename)
numpyImage = sitk.GetArrayFromImage(itkimage)
return numpyImage
Maybe you can use it as a reference.
Whether you should use the ReadImage function instead of the ImageFileReader? You can have a try.
A few good examples of file reading depending on a known format are found here.
reader->SetImageIO( RawImageIO );
seems the incorrect thing to do here if you are loading both .mhd and .raw files as they are seperate formats, MetaImage vs Raw format where you do and don't know the image size, origin, spacing etc based on the absense or presense of a header.
How are you determining the size of the image and getting (0,0,0)? image->GetSize()?
Can you provide test data?
https://itk.org/Wiki/ITK/Examples/IO/ReadUnknownImageType
https://itk.org/ITKExamples/src/IO/ImageBase/RegisterIOFactories/Documentation.html
My OpenGL ES application isn't working. I'm using SDL for windowing management, and it holds the context. After looking around, I noticed that the vertex shader and the fragment shader showed up as 0 on the debugger. Even the program was 0. Could this be a reason? I followed my shader compiling and linking code to a template that was previously made.
If it is, what is wrong? Here is the code:
GLuint ShaderHelper::compileShader(GLenum type, std::string fileName) {
std::string fileContents;
std::ifstream fin;
std::string path;
// Getting the necessary path...
// These are abstractions for getting file contents
// from the main bundle.
if (type == GL_VERTEX_SHADER) {
FileOpener opener;
path = opener.retriveFileFromBundle(fileName, "vsh");
} else if (type == GL_FRAGMENT_SHADER) {
FileOpener opener;
path = opener.retriveFileFromBundle(fileName, "fsh");
} else {
std::cout << "ERROR: Invalid shader type at filename " << fileName << std::endl;
exit(1);
}
fin.open(path);
if (!fin.is_open()) {
std::cout << "ERROR: Failed to open file " << fileName << std::endl;
exit(1);
}
// Retrieving the string from the file...
while (!fin.eof()) {
char CLine[255];
fin.getline(CLine, 255);
std::string line = CLine;
fileContents = fileContents + line;
fileContents = fileContents + " \n";
}
fin.close();
// I'm creating these variables because a pointer is needed for
// glShaderSource
GLuint shaderHandle = glCreateShader(type);
const GLint shaderStringLength = (GLint)fileContents.size();
const GLchar *shaderCString = fileContents.c_str();
glShaderSource(shaderHandle, 1, &shaderCString, &shaderStringLength);
glCompileShader(shaderHandle);
return shaderHandle;
}
void ShaderHelper::linkProgram(std::vector<GLuint *> shaderArray) {
program = glCreateProgram();
for (int i = 0; i < shaderArray.size(); i++) {
glAttachShader(program, *shaderArray[i]);
}
glLinkProgram(program);
}
void ShaderHelper::addUniform(uniform_t uniform) {
std::string name = uniform.name;
uniforms[name] = uniform;
// With that step done, we need to assign the location...
uniforms[name].location = glGetUniformLocation(program, uniforms[name].name.c_str());
}
EDIT: After suggestions, I ran my code through glError(). I fixed an error, but I still got a blank screen. I'm no longer getting 0 as my shader values. I set glClearColor to a white image, and it's just appearing pure white. I adjusted numbers in the MV matrix and projection matrix, but there's still nothing at all. I disabled face culling, but still nothing. Also, shaders are compiling and linking fine. So now what?
The dreaded blank screen can be caused by a variety of problems:
Your context is not created correctly or you're not presenting your scene properly. Does changing your clear color to something else than black show anything?
Your transformation matrix is wrong. How are you setting up the position of the "camera"? Are you using something like GLM to set up a matrix? If so, have a look at glm::perspective() and glm:::lookAt(). Make sure you're passing the matrix to the shader and that you're using it to set gl_Position in your vertex shader.
The geometry you're trying to display is facing away from the viewer. Try glDisable(GL_CULL_FACE). If it works, reverse the order of your vertices.
An OpenGL call is failing somewhere. Make sure you check glGetError() after every call. I usually have something like the following:
struct gl_checker
{
~gl_checker()
{
const auto e = glGetError();
assert(e == GL_NO_ERROR);
}
};
template <class F>
inline auto gl_call(F f) -> decltype(f())
{
gl_checker gc;
return f();
}
which can be used like this:
gl_call([]{ glDisable(GL_CULL_FACE); });
Your shaders fail to compile or link. Have a look at glGetShaderiv() with GL_COMPILE_STATUS and glGetProgramiv() with GL_LINK_STATUS. If they report an error, have a look at glGetShaderInfoLog() and glGetProgramInfoLog().
As for the partial code you provided, I see nothing strictly wrong with it. Providing the shaders and a smaller, complete program might help with finding the problem.