-
Posts
23,103 -
Joined
-
Last visited
Content Type
Blogs
Forums
Store
Gallery
Videos
Posts posted by Josh
-
-
I am not able to produce this bug in a new project, using the player robot model, on my Nvidia card.
-
I added some code that automatically decompresses the pixmap to another format, resizes it, and compresses it again.
- 1
-
This will be fixed in the next build. The command is now called Camera::SetUniform, and it accepts the following values:
int, ivec2, ivec3, ivec4, float, vec2, vec2, vec4, textureTextures will be passed as a uvec2 bindless handle. The texture will be kept in memory while it is used by a camera.
-
- Map loading from asset browser now supported.
- Added clear button in world settings environment map fields (icon has the wrong path, will be fixed in next update)
- 1
- 1
-
Quote
E.2.1 Deprecated But Still Supported Features The following features are deprecated, but still present in the core profile. They may be removed from a future version of OpenGL, and are removed in a forwardcompatible context implementing the core profile. • Wide lines - LineWidth values greater than 1.0 will generate an INVALID_- VALUE error.
https://registry.khronos.org/OpenGL/specs/gl/glspec46.core.pdf
- 1
-
This extension automatically converts images to DDS format, taking the best guess at what type of compression to use.
Build 598 or greater is required.
- 1
-
Yes. Some programs do saving a little differently. They'll do things like write the file somewhere else, and then copy it over once writing is finished, to prevent a file from getting corrupted. Some of these actions can trigger the file system watcher multiple times, and I do my best to prevent it.
- 1
-
1 minute ago, SpiderPig said:
That frag shader file? Just a text editor.
Which one?
-
What program are you editing it in, VSCode?
-
The camera cannot render on top of the background, because it has to render to an MSAA texture.
You don't want to use MSAA on GUI cameras for a few reasons.
- Text is already antialiased.
- Edges will become blurry.
There may be other situations where you do want to use multiple cameras with MSAA, but this is probably not one of them.
- 1
-
I am attaching the last version of my assimp model loader class so you can experiment with it if you want to.
- 1
-
The PBR shader family gets loaded by default when a new material is created, and when the world is initialize (because it is used as the default shader family for the default material, when no material exists).
- 1
-
Update is available now which I believe fixes this. I tested on the standalone.
- 2
-
Okay, building from the engine source works, but from the lib does not. It probably is interfering with assimp...let me do another build without it. (I only updated the editor last time.)
- 1
-
What example is not working in this example? When I run it, it loads the folder and finds a file called "è¿a¿½½¿µá.txt" in the RU folder.
-
I guess just go without whatever format is in use. The fact that nobody understand or even knows what BC7 is probably means it isn't that important in the grand scheme of things. If someone wants BC7, we can do an auto-converter in the editor from an image file.
It would be better to have something simple and reliable that works now than to have something that produces perfect results but breaks easily.
- 1
-
Yeah, but if we got a static exporter set up, that would cover 95% of use cases.
-
15 hours ago, SpiderPig said:
I dare say it's not hard, its just time consuming. The main issue I had was finding out the right stuff to access in blender from python, but google was the answer there. There's also the Leadwerks mdl exporter for blender. Maybe that could be converted to suit this rather than starting again?
I thought you had a working exporter your wrote yourself?
-
- 1
-
6 hours ago, SpiderPig said:
Can this please be looked asap, I can no longer package and update my game.
Yes
- 1
-
How hard would it be to export to this format from Blender?
-
I am considering implementing our own file format and using a pipeline more like Leadwerks, where glTF and FBX models get automatically converted by the editor. You can still use glTF files for your final game files if you wish, and the converter can be disabled in the program settings if you wish.
The file format is designed to be very simple to read and write, while loading fast enough for game use.
Features:
- LODs
- Skeletal animation
- External material files
- Vertex morphs
- User-defined entity properties
- Embedded collider
- Embedded picking structure
I think it is easiest to understand the file format just by looking at the loading code:
#include "UltraEngine.h" using namespace UltraEngine; namespace UltraEngine::Core { String G3DModelLoader::ReadText(shared_ptr<Stream> stream) { int len = stream->ReadInt(); auto pos = stream->GetPosition(); String s; if (len) { s = stream->ReadString(len); stream->Seek(pos + len); } return s; } bool G3DModelLoader::Reload(shared_ptr<Stream> stream, shared_ptr<Object> o, const LoadFlags flags) { auto modelbase = o->As<ModelBase>(); if (modelbase == NULL) return false; modelbase->model = CreateModel(NULL); auto model = modelbase->model->As<Model>(); if (stream->ReadString(4) != "G3D") return false; int version = stream->ReadInt(); if (version != 100) { Print("Error: G3D version " + String(version) + " not supported"); return false; } return LoadNode(stream, model, flags); } bool G3DModelLoader::LoadNode(shared_ptr<Stream> stream, shared_ptr<Model> model, const LoadFlags flags) { Vec3 pos, scale; Quat rot; String s; if (stream->ReadString(4) != "NODE") return false; model->name = ReadText(stream); model->properties = ParseJson(ReadText(stream)); ParseJson(ReadText(stream)); pos.x = stream->ReadFloat(); pos.y = stream->ReadFloat(); pos.z = stream->ReadFloat(); rot.x = stream->ReadFloat(); rot.y = stream->ReadFloat(); rot.z = stream->ReadFloat(); rot.w = stream->ReadFloat(); scale.x = stream->ReadFloat(); scale.y = stream->ReadFloat(); scale.z = stream->ReadFloat(); model->SetPosition(pos); model->SetRotation(rot); model->SetScale(scale); int countlods = stream->ReadInt(); for (int level = 0; level < countlods; ++level) { if (not LoadLod(stream, model, level, flags)) return false; } int countkids = stream->ReadInt(); for (int n = 0; n < countkids; ++n) { auto child = CreateModel(NULL); child->SetParent(model); if (not LoadNode(stream, child, flags)) return false; } // Animations int animcount = stream->ReadInt(); for (int n = 0; n < animcount; ++n) { stream->ReadInt();// length stream->ReadFloat();// speed auto name = ReadText(stream); } // Skeleton int bones = stream->ReadInt(); if (bones) { if (model->GetParent()) { Print("Error: Skeleton can only appear in the model root node"); return false; } if (bones != 1) { Print("Error: Skeleton root must have one bone"); return false; } auto skeleton = CreateSkeleton(nullptr); model->SetSkeleton(skeleton); for (int n = 0; n < bones; ++n) { auto bone = std::make_shared<Bone>(nullptr, skeleton); LoadBone(stream, skeleton, bone, animcount, flags); } skeleton->UpdateSkinning(); model->SetSkeleton(skeleton); } // Collider int partscount = stream->ReadInt(); model->UpdateBounds(); return true; } bool G3DModelLoader::LoadLod(shared_ptr<Stream> stream, shared_ptr<Model> model, const int level, const LoadFlags flags) { if (stream->ReadString(4) != "LOD ") return false; if (level >= model->lods.size()) model->AddLod(); float loddistance = stream->ReadFloat(); int countmeshes = stream->ReadInt(); for (int m = 0; m < countmeshes; ++m) { if (not LoadMesh(stream, model, level, flags)) return false; } return true; } bool G3DModelLoader::LoadMesh(shared_ptr<Stream> stream, shared_ptr<Model> model, const int level, const LoadFlags flags) { if (stream->ReadString(4) != "MESH") return false; MeshPrimitives type = MeshPrimitives(stream->ReadInt()); if (type < 1 or type > 4) { Print("Error: Mesh type must be between one and four"); return false; } auto mesh = model->AddMesh(type, level); mesh->name = ReadText(stream); WString mtlpath = ReadText(stream); if (not mtlpath.empty()) { if (mtlpath.Left(2) == "./" and not stream->path.empty()) { mtlpath = ExtractDir(stream->path) + "/" + mtlpath; } auto mtl = LoadMaterial(mtlpath); if (mtl) mesh->SetMaterial(mtl); } int vertexstride = stream->ReadInt(); if (vertexstride != 84) return false; int vertexcount = stream->ReadInt(); mesh->m_vertices.resize(vertexcount); for (int v = 0; v < vertexcount; ++v) { mesh->m_vertices[v].position.x = stream->ReadFloat(); mesh->m_vertices[v].position.y = stream->ReadFloat(); mesh->m_vertices[v].position.z = stream->ReadFloat(); mesh->m_vertices[v].normal.x = stream->ReadFloat(); mesh->m_vertices[v].normal.y = stream->ReadFloat(); mesh->m_vertices[v].normal.z = stream->ReadFloat(); mesh->m_vertices[v].texcoords.x = stream->ReadFloat(); mesh->m_vertices[v].texcoords.y = stream->ReadFloat(); mesh->m_vertices[v].texcoords.z = stream->ReadFloat(); mesh->m_vertices[v].texcoords.w = stream->ReadFloat(); mesh->m_vertices[v].color.r = float(stream->ReadByte()) / 255.0f; mesh->m_vertices[v].color.g = float(stream->ReadByte()) / 255.0f; mesh->m_vertices[v].color.b = float(stream->ReadByte()) / 255.0f; mesh->m_vertices[v].color.a = float(stream->ReadByte()) / 255.0f; mesh->m_vertices[v].displacement = stream->ReadFloat(); mesh->m_vertices[v].tangent.x = stream->ReadFloat(); mesh->m_vertices[v].tangent.y = stream->ReadFloat(); mesh->m_vertices[v].tangent.z = stream->ReadFloat(); mesh->m_vertices[v].bitangent.x = stream->ReadFloat(); mesh->m_vertices[v].bitangent.y = stream->ReadFloat(); mesh->m_vertices[v].bitangent.z = stream->ReadFloat(); mesh->m_vertices[v].boneindices[0] = stream->ReadShort(); mesh->m_vertices[v].boneindices[1] = stream->ReadShort(); mesh->m_vertices[v].boneindices[2] = stream->ReadShort(); mesh->m_vertices[v].boneindices[3] = stream->ReadShort(); mesh->m_vertices[v].boneweights.x = float(stream->ReadByte()) / 255.0f; mesh->m_vertices[v].boneweights.y = float(stream->ReadByte()) / 255.0f; mesh->m_vertices[v].boneweights.z = float(stream->ReadByte()) / 255.0f; mesh->m_vertices[v].boneweights.w = float(stream->ReadByte()) / 255.0f; } int indicesize = stream->ReadInt(); int indicecount = stream->ReadInt(); uint32_t index; switch (indicesize) { case 2: mesh->m_indices.reserve(indicecount); for (int i = 0; i < indicecount; ++i) mesh->AddIndice(stream->ReadShort()); break; case 4: mesh->m_indices.resize(indicecount); stream->Read(mesh->m_indices.data(), indicecount * sizeof(mesh->indices[0])); break; default: return false; } // Pick structure cache int pickcachesize = stream->ReadInt(); if (pickcachesize) stream->Seek(stream->GetPosition() + pickcachesize); //Vertex morphs int morphcount = stream->ReadInt(); for (int m = 0; m < morphcount; ++m) { if (stream->ReadString(4) != "MORP") return false; if (stream->ReadInt() != 48) return false; for (int v = 0; v < vertexcount; ++v) { // Position stream->ReadFloat(); stream->ReadFloat(); stream->ReadFloat(); // Normal stream->ReadFloat(); stream->ReadFloat(); stream->ReadFloat(); // Tangent stream->ReadFloat(); stream->ReadFloat(); stream->ReadFloat(); // Bitangent stream->ReadFloat(); stream->ReadFloat(); stream->ReadFloat(); } } mesh->UpdateBounds(); return true; } bool G3DModelLoader::LoadBone(shared_ptr<Stream> stream, shared_ptr<Skeleton> skeleton, shared_ptr<Bone> bone, const int animcount, const LoadFlags flags) { bone->name = ReadText(stream); bone->position.x = stream->ReadFloat(); bone->position.y = stream->ReadFloat(); bone->position.z = stream->ReadFloat(); bone->quaternion.x = stream->ReadFloat(); bone->quaternion.y = stream->ReadFloat(); bone->quaternion.z = stream->ReadFloat(); bone->quaternion.w = stream->ReadFloat(); bone->scale = stream->ReadFloat(); stream->ReadFloat();// scale y stream->ReadFloat();// scale z int count = stream->ReadInt(); if (count != animcount) { Print("Error: Bone animation count must match that of the root node"); return false; } for (int anim = 0; anim < count; ++anim) { if (stream->ReadString(4) != "ANIM") return false; int keyflags = stream->ReadInt(); int keyframes = stream->ReadInt(); if (keyflags) { for (int k = 0; k < keyframes; ++k) { if ((1 & keyflags) != 0) { stream->ReadFloat(); stream->ReadFloat(); stream->ReadFloat(); } if ((2 & keyflags) != 0) { stream->ReadFloat(); stream->ReadFloat(); stream->ReadFloat(); stream->ReadFloat(); } if ((4 & keyflags) != 0) { stream->ReadFloat(); stream->ReadFloat(); stream->ReadFloat(); } } } } return true; } }
- 2
-
Seems to cause problems of its own. According to this, the Godot developers gave up and implemented their own FBX converter:
https://github.com/assimp/assimp/issues/2498 -
This might be the solution, maybe:
https://github.com/assimp/assimp/issues/4035#issuecomment-1497239561
Release Notes
in General Discussion
Posted