I am triing tor read diferent 3D formats using Assimp. My corresponding C++ code looks like this:
void loadScene(string myFile)
{
Importer importer;
const aiScene *scene = importer.ReadFile(myFile, 0);
if(scene) cout<<"OK"<<endl;
else cout<< importer.GetErrorString () <<endl;
}
int main()
{
loadScene("myFile.fbx");
loadScene("myFile.3ds");
loadScene("myFile.obj");
loadScene("myFile.glb");
return 0;
}
and the output:
OBJ: Invalid face indice
OBJ: Invalid face indice
OK
OBJ: Invalid face indice
Can This be fixed? All 4 files, I am triing to read are OK, checked them with some 3D viewer.
I checked the reason for that problem is because Assimp always selects the importer for obj format. The simplest solution would be to force Assimp explicitly to use the right importer, since I know exactly which importer is suitable for which file. Unfortunately it seems like Assimp has no way to select importer explicitly.
So what I did, just added this code:
const std::string::size_type s = pFile.find_last_of('.');
if (s != std::string::npos) {
unsigned int a = GetImporterIndex(_pFile+s);
imp = pimpl->mImporter[a];
}
to const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) and my output looks like this:
OK
Chunk is too large
OK
GLTF: Unsupported binary glTF version
The problem with glb file seems to be because wrong importer is used, it should be gltf2 but gltf used instead.
Related
I am trying out tflite C++ API for running a model that I built. I converted the model to tflite format by following snippet:
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_keras_model_file('model.h5')
tfmodel = converter.convert()
open("model.tflite", "wb").write(tfmodel)
I am following the steps provided at tflite official guide, and my code upto this point looks like this
// Load the model
std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile("model.tflite");
// Build the interpreter
tflite::ops::builtin::BuiltinOpResolver resolver;
std::unique_ptr<tflite::Interpreter> interpreter;
tflite::InterpreterBuilder builder(*model, resolver);
builder(&interpreter);
interpreter->AllocateTensors();
// Check interpreter state
tflite::PrintInterpreterState(_interpreter.get());
This shows my input layer has a shape of (1, 2050, 6). For giving input from C++, I followed this thread, and my input code looks like this:
std::vector<std::vector<double>> tensor; // I filled this vector, (dims are 2050, 6)
int input = interpreter->inputs()[0];
float* input_data_ptr = interpreter->typed_input_tensor<float>(input);
for (int i = 0; i < 2050; ++i) {
for (int j = 0; j < 6; j++) {
*(input_data_ptr) = (float)tensor[i][j];
input_data_ptr++;
}
}
Last layer of this model returns a single floating point(a probability). I get output from following code.
interpreter->Invoke();
int output_idx = interpreter->outputs()[0];
float* output = interpreter->typed_output_tensor<float>(output_idx);
std::cout << "OUTPUT: " << *output << std::endl;
My problem is that I am getting same output for different inputs. Moreover, the outputs are not matching with tensorflow-python outputs.
I don't understand why it's behaving this way. Also, can anyone confirm if this is the right way to give inputs to the model?
Some extra information:
I built tflite from source, v1.14.0, using command: bazel build -c opt //tensorflow/contrib/lite:libtensorflowLite.so --cxxopt="-std=c++11" --verbose_failures
I trained my model and converted it to tflite on a different machine, with tensorflow v2.0
This is wrong API usage.
Changing typed_input_tensor to typed_tensor and typed_output_tensor to typed_tensor resolved the issue for me.
For anyone else having the same issue,
int input_tensor_idx = 0;
int input = interpreter->inputs()[input_tensor_idx];
float* input_data_ptr = interpreter->typed_input_tensor<float>(input_tensor_idx);
and
int input_tensor_idx = 0;
int input = interpreter->inputs()[input_tensor_idx];
float* input_data_ptr = interpreter->typed_tensor<float>(input);
are identical.
This can be verified by looking at implementation of typed_input_tensor.
template <class T>
T* typed_input_tensor(int index) {
return typed_tensor<T>(inputs()[index]);
}
I got a problem when I want to import a simple model using assimp, whenever I compile the code it throws:
0xC0000005: Access violation reading location 0x00000000.
I know this is something about a null pointer but I just can't find it, the code goes as follows:
Model::Model(GLchar* path)
{
loadModel(path);
}
void Model::loadModel(std::string path)
{
Assimp::Importer import;
const aiScene* scene = import.ReadFile(
path,
aiProcess_Triangulate |
aiProcess_FlipUVs);
if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){
std::cout << "ERROR::ASSIMP::" << import.GetErrorString() << std::endl;
return;
}
directory = path.substr(0, path.find_last_of('/'));
aiNode* node = scene->mRootNode;
for (GLuint i = 0; i < node->mNumChildren; i++){
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(processMesh(mesh, scene));
}
for (GLuint i = 0; i < node->mNumChildren; i++){
processNode(node->mChildren[i], scene);
}
}
I use this Model class as a global variable:
//include stuff
//other global variable
Model mymodel("D:/Project/xxx/xxx.obj");
int main(){
//...
return 0;
}
The thing is that the error happens just between the line directory = path.substr(0, path.find_last_of('/')); and the line aiNode* node = scene->mRootNode; so I don't know how to debug it, could anyone tell me how to fix this? I use Visual Studio 2013-64 and assimp-3.1.1.
Thank you very much.
I think the problem could be in this part of the code:
Model::Model(GLchar* path)
{
loadModel(path); // path is declared a string in loadModel function - type conversion might not be happening as expected.
}
Check, if you are getting a correct/valid value in the path variable on the line:
directory = path.substr(0, path.find_last_of('/'));
This link might be helpful:
GLchar could not be resolved
Note: I am not familiar with OpenGL, but looking at the error you are getting this is the first place I would check.
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.
I've been trying to get Assimp to work correctly for the past two weeks, to no avail, so I decided asking here was the best thing to do. I followed thecplusplusguy's tutorial on importing static meshes, and I've copied it word for word in an effort to get it to work.
When I try to import an .obj (a cube, if that matters) it says I have an "Unhandled exception at 0x00EF061B in OpenGL.exe: 0xC0000005: Access violation reading location 0xABABAFFB", it stops the program and tells me it's on line 30 of my code ( "for(int i=0; imNumMeshes; i++)" ).
#include "sceneloader.h"
sceneLoader::sceneLoader(){
std::cout<<"New scene created."<<std::endl;
}
sceneLoader::sceneLoader(const char* filename){
std::cout<<"Scene loading hath begun."<<std::endl;
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(filename,aiProcess_GenSmoothNormals | aiProcess_Triangulate |
aiProcess_CalcTangentSpace | aiProcess_FlipUVs |
aiProcess_JoinIdenticalVertices);
if(scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE){
std::cout<<"MFLAGS - Scene '"<<filename<<"' could not be loaded."<<std::endl;
return;
}
if(!scene->mRootNode){
std::cout<<"MROOTNODE - Scene '"<<filename<<"' could not be loaded."<<std::endl;
return;
}
std::cout<<"Recursive processing about to begin."<<std::endl;
recursiveProcess(scene->mRootNode,scene);
std::cout<<"Recursive processing finished."<<std::endl;
}
void sceneLoader::recursiveProcess(aiNode* node, const aiScene* scene){
//process
for(int i = 0; i<node->mNumMeshes;i++){ //HERE IS THE PROBLEM
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
processMesh(mesh,scene);
}
//recursion
for(int i = 0; 0<node->mNumChildren;i++){
recursiveProcess(node->mChildren[i],scene);
}
}
When I've added couts to debug it, the "scene->mNumMeshes" returns 1 (which it should, since it's one cube), but "node->mNumMeshes" returns 0.
I understand that an unhandled exception occurs when there's a null pointer, and that the null pointer here is the "node->mNumMeshes", but why is it null? And how would I fix this?
My bad.
There was a typo:
void sceneLoader::recursiveProcess(aiNode* node, const aiScene* scene){
//process
for(int i = 0; i<node->mNumMeshes;i++){
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
processMesh(mesh,scene);
}
//recursion
for(int i = 0; 0<node->mNumChildren;i++){ //IT SHOULD BE AN i INSTEAD OF A ZERO
recursiveProcess(node->mChildren[i],scene);
}
}
Finished code looks like this:
void sceneLoader::recursiveProcess(aiNode* node, const aiScene* scene){
//process
for(unsigned int i = 0; i<node->mNumMeshes;i++){
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
processMesh(mesh,scene);
}
//recursion
if(node->mNumChildren > 0){
for(unsigned int i = 0; i<node->mNumChildren;i++){
recursiveProcess(node->mChildren[i],scene);
}
}
}
Sorry.
Won't happen again.
i am currently trying to figure out a way to write a file (an allegro configuration file to be exact) to a mounted zip-file using physfs and allegro 5.
reading the config file works fine, but when it comes to writing the changed config, nothing happens (e.g. the file is not re-written and thus remains in it's old state).
also, when not using physfs, everything works perfectly.
here's the code i use:
Game::Game(int height, int width, int newDifficulty)
{
PHYSFS_init(NULL);
if (!PHYSFS_addToSearchPath("Data.zip", 1)) {
// error handling
}
al_set_physfs_file_interface();
cfg = al_load_config_file("cfg.cfg");
if (cfg != NULL) // file exists, read from it
{
const char *score = al_get_config_value(cfg, "", "highScore");
highScore = atoi(score); // copy value
}
else // file does not exist, create it and init highScore to 0
{
cfg = al_create_config();
al_set_config_value(cfg, "", "highScore", "0");
highScore = 0;
al_save_config_file("cfg.cfg", cfg);
}
...
}
and in another function:
void Game::resetGame()
{
// high score
if (player->getScore() > highScore)
{
highScore = player->getScore();
// convert new highScore to char* that can be saved
stringstream strs;
strs << highScore;
string temp_str = strs.str();
char const* pchar = temp_str.c_str();
if (cfg != NULL) // file exists, read from it
{
al_set_config_value(cfg, "", "highScore", pchar);
al_save_config_file("cfg.cfg", cfg);
}
}
...
}
since the code works without physfs, i guess i handle the config file itself correctly.
any help would be highly appreciated!
cheers,
hannes
in the meantime, i solved the issue myself.
apparently, physfs has no ability to write to an archive.
therefore, i need to PHYSFS_setWriteDir("jhdsaf"), save the cfg-file in that folder and then replace the original zip-file by an updated version with the cfg-file, just before the game closes (after all resources are unloaded because the zip is otherwise still in use).
if anyone is interested in the code to do this, just reply to this post!
hannes