OSG: Why there is texture coordinate array but not texture itself? - c++

I am trying to get texture file name from an osg::Geometry I get the texture coordinates like this:
osg::Geometry* geom = dynamic_cast<osg::Geometry*> (drawable);
const osg::Geometry::ArrayList& texCoordArrayList = dynamic_cast<const osg::Geometry::ArrayList&>(geom->getTexCoordArrayList());
auto texCoordArrayListSize = texCoordArrayList.size();
auto sset = geom->getOrCreateStateSet();
processStateSet(sset);
for (size_t k = 0; k < texCoordArrayListSize; k++)
{
const osg::Vec2Array* texCoordArray = dynamic_cast<const osg::Vec2Array*>(geom->getTexCoordArray(k));
//doing sth with vertexarray, normalarray and texCoordArray
}
But I am not able to get texture file name in processStateSet() function. I take the processStateSet function code from OSG examples (specifically from osganalysis example). Even though there is a texture file, Sometimes it works and gets the name but sometimes not. Here is my processStateSet function
void processStateSet(osg::StateSet* stateset)
{
if (!stateset) return;
for (unsigned int ti = 0; ti < stateset->getNumTextureAttributeLists(); ++ti)
{
osg::StateAttribute* sa = stateset->getTextureAttribute(ti, osg::StateAttribute::TEXTURE);
osg::Texture* texture = dynamic_cast<osg::Texture*>(sa);
if (texture)
{
LOG("texture! ");
//TODO: something with this.
for (unsigned int i = 0; i < texture->getNumImages(); ++i)
{
auto img (texture->getImage(i));
auto texturefname (img->getFileName());
LOG("image ! image no: " + IntegerToStr(i) + " file: " + texturefname);
}
}
}
}
EDIT:
I just realized that: if the model that I load is ".3ds", texturefname is exist but if model is ".flt" there is not texture name.
Is it about loading different types? But I know that they both have textures. What is the difference? I confused.

Some 3D models don't have texture names. Your choices are to deal with it, or use model files that do. It also depends on the format. Some formats can't have texture names. Some Blender export scripts can't write texture names even though the format supports it. And so on.
3D model formats are not interchangeable - every one is different.

Related

Assimp GLTF: Meshes not properly scaled (?)

I am currently trying to load the Sponza model for my PBR Renderer. It is in the GLTF format. I have been able to load smaller models quite successfully, but when I try to load the Sponza scene, some meshes aren't properly scaled. This image demonstrates my issue (I am not actually doing the PBR calculations here, that's just the albedo of the model). The wall is there, but it's only a 1x1 quad with the wall texture, even though it's supposed to be a lot bigger ans stretch across the entire model. Same goes for every wall and every floor in the model. The model is not broken as Blender and that default windows model viewer can load it correctly. I am even applying the mNode->mTransformation, but it still doesn't work. My model loading code looks kind of like this:
void Model::LoadModel(const fs::path& filePath)
{
Assimp::Importer importer;
std::string pathString = filePath.string();
m_Scene = importer.ReadFile(pathString, aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_CalcTangentSpace);
if (!m_Scene || m_Scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !m_Scene->mRootNode)
{
// Error handling
}
ProcessNode(m_Scene->mRootNode, m_Scene, glm::mat4(1.0f));
}
void Model::ProcessNode(aiNode* node, const aiScene* m_Scene, glm::mat4 parentTransformation)
{
glm::mat4 transformation = AiMatrix4x4ToGlm(&node->mTransformation);
glm::mat4 globalTransformation = transformation * parentTransformation;
for (int i = 0; i < node->mNumMeshes; i++)
{
aiMesh* assimpMesh = m_Scene->mMeshes[node->mMeshes[i]];
// This will just get the vertex data, indices, tex coords, etc.
Mesh neroMesh = ProcessMesh(assimpMesh, m_Scene);
neroMesh.SetTransformationMatrix(globalTransformation);
m_Meshes.push_back(neroMesh);
}
for (int i = 0; i < node->mNumChildren; i++)
{
ProcessNode(node->mChildren[i], m_Scene, globalTransformation);
}
}
glm::mat4 Model::AiMatrix4x4ToGlm(const aiMatrix4x4* from)
{
glm::mat4 to;
to[0][0] = (GLfloat)from->a1; to[0][1] = (GLfloat)from->b1; to[0][2] = (GLfloat)from->c1; to[0][3] = (GLfloat)from->d1;
to[1][0] = (GLfloat)from->a2; to[1][1] = (GLfloat)from->b2; to[1][2] = (GLfloat)from->c2; to[1][3] = (GLfloat)from->d2;
to[2][0] = (GLfloat)from->a3; to[2][1] = (GLfloat)from->b3; to[2][2] = (GLfloat)from->c3; to[2][3] = (GLfloat)from->d3;
to[3][0] = (GLfloat)from->a4; to[3][1] = (GLfloat)from->b4; to[3][2] = (GLfloat)from->c4; to[3][3] = (GLfloat)from->d4;
return to;
}
I don't think the ProcessMesh function is necessary for this, but if it is I can post it as well.
Does anyone see any issues? I am really getting desperate over this...
Turns out I am the dumbest human being on earth. I implemented Parallax Mapping in my code, but disabled it immediately after as it was not working correctly on every model. BUT I still had this line in my shader code:
if (texCoords.x > 1.0 || texCoords.y > 1.0 || texCoords.x < 0.0 || texCoords.y < 0.0)
discard;
Which ended up removing some parts of my model.
If I had to rate my stupidity on a scale from 1 to 10, I'd give it a 100000000000.

Multiple framebuffer pass in Metal

I am trying to add blur capability to my application. I found this example of blur and am now trying to implement it using Metal. What the pipeline looks like in my case:
I draw objects using raycast to offscreen texture;
Then I take this texture and make a horizontal blur, and then write the result into texture A;
I take that texture A and make a vertical blur, and write
the result into texture B;
I draw on the screen texture B.
To write to textures A and B, I use the [[color(m)]] attribute as the return value from the fragment function. And then I ran into a problem, in OpenGL, in order to apply blur to a texture, for example 10 times, you can do it like this (using ping-pong framebuffers):
bool horizontal = true, first_iteration = true;
int amount = 10;
shaderBlur.use();
for (unsigned int i = 0; i < amount; i++)
{
glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[horizontal]);
shaderBlur.setInt("horizontal", horizontal);
glBindTexture(
GL_TEXTURE_2D, first_iteration ? colorBuffers[1] : pingpongBuffers[!horizontal]
);
RenderQuad();
horizontal = !horizontal;
if (first_iteration)
first_iteration = false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
But how can this be done in Metal? I tried it like this, but it didn't give any results (I mean that with loops, that without them, the result is the same, as if there is only one pass of the blur):
blur_pass_ = 1; // horizontal blur pass
[render_encoder setFragmentBytes:&blur_pass_ length:sizeof(blur_pass_) atIndex:0];
for (std::size_t x = 0; x < 9; ++x) { // how much times I want to apply blur
[render_encoder setFragmentTexture:render_target_texture_ atIndex:0];
[render_encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:num_vertices];
}
blur_pass_ = 0; // vertical blur pass
[render_encoder setFragmentBytes:&blur_pass_ length:sizeof(blur_pass_) atIndex:0];
for (std::size_t y = 0; y < 9; ++y) { // how much times I want to apply blur
[render_encoder setFragmentTexture:x_blurry_texture_ atIndex:0];
[render_encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:num_vertices];
}
[render_encoder endEncoding];
Can you tell me how to do this correctly in Metal? Yes, I also build for iphones, so performance is important to me.

VTK: rotate a 3D model and capture its depth map

Currently, based on the VTK ZBuffer example, I iteratively rotate the 3D model and capture each time the depth map. The issue is that although the model rotates the output images contain all the first depth map.
int main(int argc, char *argv[]){
...variable declaration/initialization
//read off file
offReader->SetFileName(argv[1]);
offReader->Update();
int step = 30; std::string out;
for (int i = 0; i < 3; i++) {
mapper->NewInstance();
actor->NewInstance();
renWin->NewInstance();
renderer->NewInstance();
mapper->SetInputData(polyData);
actor->SetMapper(mapper);
out = std::to_string(i);
actor->RotateZ(step*i);
renWin->AddRenderer(renderer);
renderer->AddActor(actor);
renderer->SetBackground(1, 1, 1);
renWin->Render();
// Create Depth Map
filter->NewInstance();
scale->NewInstance();
imageWriter->NewInstance();
filter->SetInput(renWin);
filter->SetMagnification(3);
filter->SetInputBufferTypeToZBuffer(); //Extract z buffer value
filter->Update();
scale->SetOutputScalarTypeToUnsignedChar();
scale->SetInputConnection(filter->GetOutputPort());
scale->SetShift(0);
scale->SetScale(-255);
scale->Update();
std::string out1 = out + "_depth.bmp";
std::cout << " " << out1 << std::endl;
// Write surface map as a .bmp image
imageWriter->SetFileName(out1.c_str());
imageWriter->SetInputConnection(scale->GetOutputPort());
imageWriter->Update();
imageWriter->Write();
filter->RemoveAllInputs();
scale->RemoveAllInputs();
imageWriter->RemoveAllInputs();
renderer->RemoveActor(actor);
renWin->RemoveRenderer(renderer);
.... remaining script
}
The output depth maps are all identical. 0_depth.bmp, 1_depth.bmp & 2_depth.bmp
Has anyone encountered the same issue? If yes, what could be a potential solution.
Problem solved by introducing a function within the rotation took place. Apparently it was a matter of a variable content update issue, that could be solved in a more straight forward way.

Loading mtl colors using assimp

I've been trying to load a Wavefront obj model with ASSIMP. However, I can't get mtl materials colors to work (Kd rgb). I know how to load then, but, I don't know how to get the corresponding color to each vertex.
usemtl material_11
f 7//1 8//1 9//2
f 10//1 11//1 12//2
For example, the Wavefront obj snippet above means that thoose vertices uses material_11.
Q: So how can I get the material corresponding to each vertex?
Error
Wavefront obj materials aren't in the right vertices:
Original Model (Rendered with ASSIMP model Viewer):
Model renderered with my code:
Code:
Code that I use for loading mtl materials color:
std::vector<color4<float>> colors = std::vector<color4<float>>();
...
for (unsigned int i = 0; i < scene->mNumMeshes; i++)
{
const aiMesh* model = scene->mMeshes[i];
const aiMaterial *mtl = scene->mMaterials[model->mMaterialIndex];
color4<float> color = color4<float>(1.0f, 1.0f, 1.0f, 1.0f);
aiColor4D diffuse;
if (AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse))
color = color4<float>(diffuse.r, diffuse.g, diffuse.b, diffuse.a);
colors.push_back(color);
...
}
Code for creating the vertices:
vertex* vertices_arr = new vertex[positions.size()];
for (unsigned int i = 0; i < positions.size(); i++)
{
vertices_arr[i].SetPosition(positions.at(i));
vertices_arr[i].SetTextureCoordinate(texcoords.at(i));
}
// Code for setting vertices colors (I'm just setting it in ASSIMP vertices order, since I don't know how to set it in the correct order).
for (unsigned int i = 0; i < scene->mNumMeshes; i++)
{
const unsigned int vertices_size = scene->mMeshes[i]->mNumVertices;
for (unsigned int k = 0; k < vertices_size; k++)
{
vertices_arr[k].SetColor(colors.at(i));
}
}
EDIT:
Looks like that the model vertices positions aren't being loaded correctly too. Even when I disable face culling and change the background color.
Ignoring issues related to the number of draw calls and extra storage, bandwidth and processing for vertex colours,
It looks like vertex* vertices_arr = new vertex[positions.size()]; is one big array you're creating to hold the entire model (which has many meshes, each with one material). Assuming your first loop is correct and positions contains all positions for all meshes of your model. The second loop starts duplicating mesh colours for each vertex within the mesh. However, vertices_arr[k] always starts at zero and needs to begin after the last vertex of the previous mesh. Instead, try:
int colIdx = 0;
for (unsigned int i = 0; i < scene->mNumMeshes; i++)
{
const unsigned int vertices_size = scene->mMeshes[i]->mNumVertices;
for (unsigned int k = 0; k < vertices_size; k++)
{
vertices_arr[colIdx++].SetColor(colors.at(i));
}
}
assert(colIdx == positions.size()); //double check
As you say, if the geometry isn't drawing properly, maybe positions doesn't contain all vertex data. Perhaps a similar issue to the above code? Another issue could be in joining the indices for each mesh. The indices will all need to be updated with an offset to the new vertex locations within the vertices_arr array. Though now I'm just throwing out guesses.

Memory increase rapidly using gluTess*, display list and frame buffer

I'm programming with OpenGL under MSVC 2010.
One of my goal is to pick objects in the scene. I design it in the way like assigning each object a unique color, rendering them in a framebuffer, then reading the color where the cursor is, and the corresponding object can be acquired.
Now the picking is working well. However, as long as a picking happens, the memory increases rapidly. In detail, the following code render objects into a framebuffer:
for (unsigned i = 0; i < objects.size(); ++i)
{
//some code computing color;
Color color;
for (unsigned j = 0; j < objects[i].listOfPrimitives.size(); ++j)
{
objects[i].listOfPrimitives[j]->color = color;
}
objects[i].Render();
for (unsigned j = 0; j < objects[i].listOfPrimitives.size(); ++j)
{
objects[i].listOfPrimitives[j]->color = colorStorage[i][j];
}
}
where objects are objects to be rendered. Since every object has a certain number of primitives(which may be a cylinder, sphere etc.), this piece of code just changes the color of each object's primitives to a unique computed one, render the object, then change it back (colorSotrage stores the original colors). And there are some code in the following to deal with the object, which I'm sure has nothing to do with this issue.
The render method are implemented as following for most object:
glColor3ub(color[0], color[1], color[2]);
glBegin(GL_TRIANGLES);
for (unsigned i = 0; i < mesh.faces.size(); ++i)
{
glNormal3d(mesh.faces[i].normal.x, mesh.faces[i].normal.y, mesh.faces[i].normal.z);
for (unsigned j = 0; j < 3; ++j)
{
glVertex3d(mesh.vertices[mesh.faces[i].verts[j]].x,
mesh.vertices[mesh.faces[i].verts[j]].y,
mesh.vertices[mesh.faces[i].verts[j]].z);
}
}
glEnd();
But for some object, there are some concave polygons (even with holes), so I use the gluTess* group functions in GLU to render them, and to speed up the rendering procedure, I use display list to that part.
Now, as I've mentioned. this picking procedure increases the memory cost rapidly. There are two more phenomenons I can't explain:
If I comment line 8 in the first piece of code, the memory will not change at all when the piece of code runs (of course, this code will not work);
After the memory increases, if I do some refresh to the scene (I design an interactive trackball), the memory will drop off again.
So I'm wondering which part could be the reason of this issue? The display list? the gluTess*() calling? or even something related to framebuffer?