• Advertisement


  • Content count

  • Joined

  • Last visited

Community Reputation

12 Neutral


About Yxjmir

  • Rank

Personal Information

  • Interests
  1. So, I played around with the exporter this morning (I also included UV coordinates), and it seems to work, but only for simple models using glDrawElements. I also, made sure to use the same type for the indices, obviously. I think it might just be a problem with the exporter, maybe it only works with models made a specific way. I didn't show it before, but only some of the faces were rendering, I probably selected unsigned byte by accident for the exporter, and was trying to read the data back into a unsigned short vector. Some of the lines shouldn't be there on the house model below, I'm using the same draw call just a different shader that only uses the color green for the line instead of the texture color, other than that both shaders are the same. this is how it looks in blender, there are no lines in the doorway of the model.
  2. I'm trying to load data from a .gltf file into a struct to use to load a .bin file. I don't think there is a problem with how the vertex positions are loaded, but with the indices. This is what I get when drawing with glDrawArrays(GL_LINES, ...): Also, using glDrawElements gives a similar result. Since it looks like its drawing triangles using the wrong vertices for each face, I'm assuming it needs an index buffer/element buffer. (I'm not sure why there is a line going through part of it, it doesn't look like it belongs to a side, re-exported it without texture coordinates checked, and its not there) I'm using jsoncpp to load the GLTF file, its format is based on JSON. Here is the gltf struct I'm using, and how I parse the file: #define GLTF_TARGET_ARRAY_BUFFER (34962) #define GLTF_TARGET_ELEMENT_ARRAY_BUFFER (34963) #define GLTF_COMPONENT_TYPE_BYTE (5120) #define GLTF_COMPONENT_TYPE_UNSIGNED_BYTE (5121) #define GLTF_COMPONENT_TYPE_SHORT (5122) #define GLTF_COMPONENT_TYPE_UNSIGNED_SHORT (5123) #define GLTF_COMPONENT_TYPE_INT (5124) #define GLTF_COMPONENT_TYPE_UNSIGNED_INT (5125) #define GLTF_COMPONENT_TYPE_FLOAT (5126) #define GLTF_COMPONENT_TYPE_DOUBLE (5127) #define GLTF_PARAMETER_TYPE_BYTE (5120) #define GLTF_PARAMETER_TYPE_UNSIGNED_BYTE (5121) #define GLTF_PARAMETER_TYPE_SHORT (5122) #define GLTF_PARAMETER_TYPE_UNSIGNED_SHORT (5123) #define GLTF_PARAMETER_TYPE_INT (5124) #define GLTF_PARAMETER_TYPE_UNSIGNED_INT (5125) #define GLTF_PARAMETER_TYPE_FLOAT (5126) #define GLTF_PARAMETER_TYPE_FLOAT_VEC2 (35664) #define GLTF_PARAMETER_TYPE_FLOAT_VEC3 (35665) #define GLTF_PARAMETER_TYPE_FLOAT_VEC4 (35666) struct GLTF { struct Accessor { USHORT bufferView; USHORT componentType; UINT count; vector<INT> max; vector<INT> min; string type; }; vector<Accessor> m_accessors; struct Asset { string copyright; string generator; string version; }m_asset; struct BufferView { UINT buffer; UINT byteLength; UINT byteOffset; UINT target; }; vector<BufferView> m_bufferViews; struct Buffer { UINT byteLength; string uri; }; vector<Buffer> m_buffers; vector<string> m_Images; struct Material { string name; string alphaMode; Vec4 baseColorFactor; UINT baseColorTexture; UINT normalTexture; float metallicFactor; }; vector<Material> m_materials; struct Meshes { string name; struct Primitive { vector<UINT> attributes_indices; UINT indices; UINT material; }; vector<Primitive> primitives; }; vector<Meshes> m_meshes; struct Nodes { int mesh; string name; Vec3 translation; }; vector<Nodes> m_nodes; struct Scenes { UINT index; string name; vector<UINT> nodes; }; vector<Scenes> m_scenes; vector<UINT> samplers; struct Textures { UINT sampler; UINT source; }; vector<Textures> m_textures; map<UINT, string> attributes_map; map<UINT, string> textures_map; }; GLTF m_gltf; // This is actually in the Mesh class bool Mesh::Load(string sFilename) { string sFileAsString; stringstream sStream; ifstream fin(sFilename); sStream << fin.rdbuf(); fin.close(); sFileAsString = sStream.str(); Json::Reader r; Json::Value root; if (!r.parse(sFileAsString, root)) { string errors = r.getFormatedErrorMessages(); if (errors != "") { // TODO: Log errors return false; } } if (root.isNull()) return false; Json::Value object; Json::Value value; // Load Accessors array, these are referenced by attributes with their index value object = root.get("accessors", Json::Value()); // store object with key "accessors", if not found it will default to Json::Value() if (!object.isNull()) { for (Json::ValueIterator it = object.begin(); it != object.end(); it++) { GLTF::Accessor accessor; value = (*it).get("bufferView", Json::Value()); if (!value.isNull()) accessor.bufferView = value.asUINT(); else return false; value = (*it).get("componentType", Json::Value()); if (!value.isNull()) accessor.componentType = value.asUINT(); else return false; value = (*it).get("count", Json::Value()); if (!value.isNull()) accessor.count = value.asUINT(); else return false; value = (*it).get("type", Json::Value()); if (!value.isNull()) accessor.type = value.asString(); else return false; m_gltf.accessors.push_back(accessor); } } else return false; object = root.get("bufferViews", Json::Value()); if(!object.isNull()) { for (Json::ValueIterator it = object.begin(); it != object.end(); it++) { GLTF::BufferView bufferView; value = (*it).get("buffer", Json::Value()); if(!value.isNull()) bufferView.buffer = value.asUInt(); else return false; value = (*it).get("byteLength", Json::Value()); if(!value.isNull()) bufferView.byteLength = value.asUInt(); else return false; value = (*it).get("byteOffset", Json::Value()); if(!value.isNull()) bufferView.byteOffset = value.asUInt(); else return false; value = (*it).get("target", Json::Value()); if(!value.isNull()) bufferView.target = value.asUInt(); else return false; m_gltf.m_bufferViews.push_back(bufferView); } } else return false; object = root.get("buffers", Json::Value()); if(!object.isNull()) { for (Json::ValueIterator it = object.begin(); it != object.end(); it++) { GLTF::Buffer buffer; value = (*it).get("byteLength", Json::Value()); if(!value.isNull()) buffer.byteLength = value.asUInt(); else return false; // Store the filename of the .bin file value = (*it).get("uri", Json::Value()); if(!value.isNull()) buffer.uri = value.asString(); else return false; } } else return false; object = root.get("meshes", Json::Value()); if(!object.isNull()) { for(Json::ValueIterator it = object.begin(); it != object.end(); it++) { GLTF::Meshes mesh; value = (*it).get("primitives", Json::Value()); for(Json::ValueIterator value_it = value.begin(); value_it != value.end(); value_it++) { GLTF::Meshes::Primitive primitive; Json::Value attributes; attributes = (*value_it).get("attributes", Json::Value()); vector<string> memberNames = attributes.getMemberNames(); for(size_t i = 0; i < memberNames.size(); i++) { Json::Value member; member = attributes.get(memeberNames[i], Json::Value()); if(!member.isNull()) { primitive.attributes_indices.push_back(member.asUInt()); m_gltf.attributes_map[member.asUInt()] = memberNames[i]; // Each of these referes to an accessor by indice, so each indice should be unique, and they are when loading a cube } else return false; } // Indice of the accessor used for indices Json::Value indices; indices = (*value_it).get("indices", Json::Value()); primitive.indices = indices.asUInt(); mesh.primitives.push_back(primitive); } m_gltf.m_meshes.push_back(mesh); } } vector<float> vertexData; vector<USHORT> indiceData; int vertexBufferSizeTotal = 0; int elementBufferSizeTotal = 0; GLTF::Meshes mesh = m_gltf.m_meshes[0]; vector<GLTF::Meshes::Primitive> primitives = mesh.primitives; // trying to make the code easier to read for (size_t p = 0; p < primitive.size(); p++) { vector<UINT> attributes = primitives[p].attributes_indices; for(size_t a = 0; a < attributes.size(); a++) { GLTF::Accessor accessor = m_gltf.m_accessors[attributes[a]]; GLTF::BufferView bufferView = m_gltf.m_bufferViews[accessor.bufferView]; UINT target = bufferView.target; if(target == GLTF_TARGET_ARRAY_BUFFER) vertexBufferSizeTotal += bufferView.byteLength; } UINT indice = primitives[p].indices; GLTF::BufferView bufferView = m_gltf.m_bufferViews[indice]; UINT target = bufferView.target; if(target == GLTF_TARGET_ELEMENT_ARRAY_BUFFER) elementBufferSizeTotal += bufferView.byteLength; } // These have already been generated glBindVertexArray(g_pGame->m_VAO); glBindBuffer(GL_ARRAY_BUFFER, g_pGame->m_VBO); glBufferData(GL_ARRAY_BUFFER, vertexBufferSizeTotal, nullptr, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_pGame->m_EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementBufferSizeTotal, nullptr, GL_STATIC_DRAW); int offset = 0; int offset_indice = 0; for (size_t p = 0; p < primitive.size(); p++) { vector<UINT> attributes = primitives[p].attributes_indices; int pos = sFilename.find_last_of('\\') + 1; string sFolder = sFilename.substr(0, pos); for (size_t a = 0; a < attributes.size(); a++) { LoadBufferView(sFolder, attributes[a], data, offset); } UINT indice = primitives[p].indices; GLTF::BufferView bufferView_indice = m_gltf.m_bufferViews[indice]; UINT target_indice = bufferView_indice.target; bool result = LoadBufferView(sFolder, indice, data, offset_indice); if(!result) return false; } return true; } bool Mesh::LoadBufferView(string sFolder, UINT a, vector<float> &vertexData, vector<float> &indiceData, int &offset_indice) { ifstream fin; GLTF::Accessor accessor = m_gltf.m_accessors[a]; GLTF::BufferView bufferView = m_gltf.m_bufferViews[accessor.bufferView]; GLTF::Buffer buffer = m_gltf.m_buffers[bufferView.buffer]; const size_t count = accessor.count; UINT target = bufferView.target; int elementSize; int componentSize; int numComponents; string sFilename_bin = sFolder + buffer.uri; fin.open(sFilename_bin, ios::binary); if (fin.fail()) { return false; } fin.seekg(bufferView.byteOffset, ios::beg); switch (accessor.componentType) { case GLTF_COMPONENT_TYPE_BYTE: componentSize = sizeof(GLbyte); break; case GLTF_COMPONENT_TYPE_UNSIGNED_BYTE: componentSize = sizeof(GLubyte); break; case GLTF_COMPONENT_TYPE_SHORT: componentSize = sizeof(GLshort); break; case GLTF_COMPONENT_TYPE_UNSIGNED_SHORT: componentSize = sizeof(GLushort); break; case GLTF_COMPONENT_TYPE_INT: componentSize = sizeof(GLint); break; case GLTF_COMPONENT_TYPE_UNSIGNED_INT: componentSize = sizeof(GLuint); break; case GLTF_COMPONENT_TYPE_FLOAT: componentSize = sizeof(GLfloat); break; case GLTF_COMPONENT_TYPE_DOUBLE: componentSize = sizeof(GLfloat); break; default: componentSize = 0; break; } if (accessor.type == "SCALAR") numComponents = 1; else if (accessor.type == "VEC2") numComponents = 2; else if (accessor.type == "VEC3") numComponents = 3; else if (accessor.type == "VEC4") numComponents = 4; else if (accessor.type == "MAT2") numComponents = 4; else if (accessor.type == "MAT3") numComponents = 9; else if (accessor.type == "MAT4") numComponents = 16; else return false; vector<float> fSubdata; // I'm pretty sure this is one of the problems, or related to it. If I use vector<USHORT> only half of the vector if filled, if I use GLubyte, the entire vector is filled, but the data might not be right vector<GLubyte> nSubdata; elementSize = (componentSize) * (numComponents); // Only fill the vector I'm using if (accessor.type == "SCALAR") { nSubdata.resize(count * numComponents); fin.read(reinterpret_cast<char*>(&nSubdata[0]), count/* * elementSize*/); // I commented this out since I'm not sure which size the .bin is storing the indice values, and I kept getting runtime errors, no matter what type I used for nSubdata } else { fSubdata.resize(count * numComponents); fin.read(reinterpret_cast<char*>(&fSubdata[0]), count * elementSize); } switch (target) { case GLTF_TARGET_ARRAY_BUFFER: { vertexData.insert(vertexData.end(), fSubdata.begin(), fSubdata.end()); glBindBuffer(GL_ARRAY_BUFFER, g_pGame->m_VBO); glBufferSubData(GL_ARRAY_BUFFER, offset, fSubdata.size() * componentSize, &fSubdata[0]); int attribute_index = 0; // I'm only loading vertex positions, the only attribute stored in the files for now glEnableVertexAttribArray(attribute_index); glVertexAttribPointer(0, numComponents, GL_FLOAT, GL_FALSE, componentSize * numComponents, (void*)(offset)); }break; case GLTF_TARGET_ELEMENT_ARRAY_BUFFER: { indiceData.insert(indiceData.end(), nSubdata.begin(), nSubdata.end()); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_pGame->m_EBO); // This is another area where I'm not sure of the correct values, but if componentSize is the correct size for the type being used it should be correct glBufferSubData is expecting the size in bytes, right? glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, nSubdata.size() * componentSize, &nSubdata[0]); }break; default: return false; } if (accessor.type == "SCALAR") offset += nSubdata.size() * componentSize; else offset += fSubdata.size() * componentSize; fin.close(); return true; } these are the draw calls, I only use one at a time, but neither is currently display properly, g_pGame->m_indices is the same as indiceData vector, and vertexCount contains the correct vertex count, but I forgot to copy the lines of code containing where I set them, which is at the end of Mesh::Load(), I double checked the values to make sure. glBindVertexArray(g_pGame->m_VAO); glDrawElements(GL_LINES, g_pGame->m_indices.size(), GL_UNSIGNED_BYTE, (void*)0); // Only shows with GL_UNSIGNED_BYTE glDrawArrays(GL_LINES, 0, g_pGame->m_vertexCount); So, I'm asking what type should I use for the indices? it doesn't seem to be unsigned short, which is what I selected with the Khronos Group Exporter for blender. Also, am I reading part or all of the .bin file wrong? Test.gltf Test.bin
  3. DirectxTK and basic concept of drawing models

    I haven't used DirectXTK, but maybe you're calling m_shape->Draw() inbetween m_batch->Begin() and m_batch->End(). I could be wrong, but I don't think its meant to be used like that. That's the only reason I can think of for the color changing. As for the axes translation problem, I think you are changing the world matrix which I guess is effecting the other thing being drawn after it, I'm not sure how the Draw function works. In regular DirectX and OpenGL you would create a shader, and pass the same matrices as you do in m_shape->Draw(), and that would effect the entire draw call. Any changes to the matrices would effect the next draw calls, which I think might be happening with the axes. You might need to call something like SetWorld(identityMatrix) before rendering the axes, I don't know what exactly is suppose to do that, since I don't even know if m_batch has a function like that.
  4. Data Driven Item component system?

    Wurstbrot, I'm curious about how your entity works in the HashMap. The ID is a long integer that is used as a key to get another HashMap that uses a Class as the key for one AbstractComponent? It seems like there would only be one AbstractComponent for each unique class. So, do your entities not have multiple components, or is that component derived from multiple other components (I'm assuming AbstractComponent is the base class)? Menyo mentioned you could have a piece of armor (a shield) capable of being used as a weapon/doing damage, but maybe your system just doesn't need that.
  5. Sky Domes

    Well that was fast. Looks like that will work.
  6. Sky Domes

    You have to translate it to the same position as the camera. Also, here is a link to a youtube video about making skyboxes, its written in java, but its not difficult to follow for whatever language your using. Its pretty much the same steps minus the java specific stuff. https://www.youtube.com/watch?v=_Ix5oN8eC1E&index=27&list=PLRIWtICgwaX0u7Rf9zkZhLoLuZVfUksDP
  7. I don't know much about animation right now, but you can multiply the transforms for each bone and that will blend the animations with the other. I'm not sure how to do this in Assimp. Have you tried just playing the animations one after the other? If so, what was the effect? (Did it just play the first one, or the last one, or was there some other result)
  8. Do you mean the initial setting of the data is cheaper than switching shaders, or just changing them after they've been set once? If you only meant that changing the uniform after its been set once, then I wasn't referring to that, just the initial setting of each uniform. It is better to not set variables that won't be used. Even if it doesn't cost much, you can still increase performance slightly by not setting them, this is the main problem I have with using one "master shader".
  9. Setting uniform variables is expensive, but I don't know how it compares to calling glUseProgram(). If you set 10 or so boolean uniform variables, then it would probably be slower than just calling glUseProgram() and not setting as many. Let's say you set 2 uniforms and then 10 boolean uniforms for a "master shader". If you broke them down into different shaders, then each would have to set the first 2 uniforms, and let's say they each set 1 more. Then you could run 3-4 different shaders in approximately the same amount of time (assuming run time for master shader is equal to the sum of the multiple smaller shaders, and I said 3-4 since you'd have to call glUseProgram more often.) So, personally I'd break them apart, because there's no point in setting multiple uniform booleans to check for things that the shader isn't going to use. It would be like checking if you need to run, and maybe even setting up, a particle, light, and fur shader on something like a user interface. It just needs to know how to texture it and position it. Storing the shaders in a file then having to load it (either during loading a model or rendering), then link it, then run it would be slower than loading them all at the start, linking them, and then just running them as needed. It might not actually be slower, but you're in the middle of loading a file, or rendering when you start reading the shader, and linking it, so it would increase the time it took to load the file or render. So its best to do it once at the start of the game, and if you need to reload it during runtime, add the ability to do so when a key is pressed.
  10. Importing .OBJ model to OpenGL

    Just use std::vector<float> and push_back to put the vertex, uv, then normal, and use my example of interleaved VBO. You shouldn't have to worry about the amount of space a vector can support, I don't remember what the number is but it's pretty high. You would use both, the uv coordinates will range from 0.0 - 1.0 regardless of the size of the texture. (sometimes it will be out of this range, but it will just repeat starting at the opposite end, or be clipped depending on the texture settings) // You could check to make sure that the glGetUniformLocation() returns a valid location, and // display an error, or write it to file or something. glUniform1i(glGetUniformLocation("texture_0"), 0); glUniform1i(glGetUniformLocation("texture_1"), 1); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture0_id); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture1_id); your shader should have texture_0, and texture_1 as two uniform sampler2D, or as a array but then you'd have to modify my example a little bit.
  11. If you mean whether or not it exists, then it would be a good idea to check when you load the image. If you mean setup the texture then it should look similar to: GLuint id; glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); // Not sure if thses are the correct things to use with glBindImageTexture glTexImage2D(GL_TEXTURE_2D, 0, Internal_Format, width, height, 0, Image_Format, GL_UNSIGNED_BYTE, pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindImageTexture(0, id, /* Fill in the rest of the variables */);
  12. In other files the indices are grouped together (vertexIndex normalIndex uvIndex and then it repeats). I've never worked with fbx, but if each vertex index goes with the uv index in order then since they both have 30 indices you don't need more vertices. You just need the same number of indices per vertex, uv, and normal (if it wasn't using the values directly). I'm not sure why this has negative indices, but indices should be positive, maybe fbx has a specific reason for this.
  13. So, lets say we had a scene with several boxes, and chests, and maybe other static objects, was I right that it would be better to store all of that (environment included) in one VBO? Also, is there an max size that a VBO can be, or is it just the maximum number of vertices your card can support?
  14. Use the indices from the fbx to create an index buffer, you shouldn't have to duplicate any vertices in direct x. This is from Rastertek tutorials http://www.rastertek.com/dx11tut07.html , I left out the irrelevant parts: unsigned long* indices; D3D11_BUFFER_DESC indexBufferDesc; D3D11_SUBRESOURCE_DATA indexData; // Create the index array. indices = new unsigned long[m_indexCount]; if(!indices) { return false; } // Load the vertex array and index array with data. // ... // Set up the description of the static index buffer. indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; indexBufferDesc.StructureByteStride = 0; // Give the subresource structure a pointer to the index data. indexData.pSysMem = indices; indexData.SysMemPitch = 0; indexData.SysMemSlicePitch = 0; // Create the index buffer. result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer); if(FAILED(result)) { return false; } delete [] indices; indices = 0; If this doesn't work or you've already done this, then use this pseudo code, but try the above first: uv = new XMFLOAT2[numIndices]; for (int index = 0; index < numIndices; ++index) { uv[index] = filesUV[index]; }
  15. Assimp's documentation states: "An aiAnimation has a duration. The duration as well as all time stamps are given in ticks. To get the correct timing, all time stamp thus have to be divided by aiAnimation::mTicksPerSecond. Beware, though, that certain combinations of file format and exporter don't always store this information in the exported file. In this case, mTicksPerSecond is set to 0 to indicate the lack of knowledge." So first check if mTicksPerSecond is 0. The data should be in aiAnimation. I haven't used Assimp in a long time, though.
  • Advertisement