-
Notifications
You must be signed in to change notification settings - Fork 178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
👼Script: OGRE bindings for editing scene, meshes and textures - with examples #3030
Conversation
It doesn't work this way. I'm comitting anyway because the extra node in the hierarchy will be useful for RigsOfRods#3030 and I think origin + rel. positions in simbuffer will also become handy later. Otherwise I'll just drop this commit.
Tested & works fine! |
End goal: improve terrain performanceOur terrains suffer of low FPS due to overly high batch count (= number of draw calls). This is because we use many low-poly meshes and materials. The graphics chips and drivers like large meshes with a single material containing a big texture atlas. Number of polygons or texture size doesn't matter - one mesh with single material counting 1M polygons will render faster than multiple meshes (different material each) counting 1K polygons together. The way to go is to simply ditch our existing meshes and generate new ones from their geometry and textures, merging them together for optimal rendering. There are
I've finally dealt with the Tuning branch and I'm back on this. The tuning branch is now merged and brings project support - the ability to create subdirs under Documents/My Games/Rigs of Rods/projects and populate them with files from an existing mod. The intended use was vehicles, but it will work with terrains just the same. New feature: arbitrary mesh generationThe screenshot below showcases a new example script 'example_ogre_MeshedConcrete.as' (run it using |
note that Ogre already provides an API to do this, given you can use the same material for all of the entities: |
I'm aware, except that's a no go given the state of our community. We have loads of separate meshes, many using multiple submeshes with separate materials, and a long history of doing stuff exclusively this way. Writing a custom batching tool is really the only viable way:
|
my point was that you can use StaticGeometry inside your tool to take care of merging the meshes. It already handles SubMeshes and LOD. Your tool would then just have to merge the materials beforehand. |
Point taken, thanks, but I'm determined to try by hand first, to explore and demonstrate the possibilities of the script bindings. Our terrain system already relies on generating meshes (procedural roads) and I intend to improve and extend these. PS: also LODs are mostly non present on meshes produced by our community:D |
you might want to consider LOD in the design of this and auto generate them at some point though: https://ogrecave.github.io/ogre/api/latest/meshlod-generator.html |
Task 3/3 from RigsOfRods#3030. This means I can start writing a script to batch together terrain objects (meshes+textures) for performance - especially for Community Map New script API: * objects: `MeshPtr, SubMesh, MeshManager` * to get vert positions, use "array<vector3>@ __getVertexPositions()" on SubMesh * ditto for vert texcoords, note the extra index param because mesh can have more than 1 texcoord layer: "array<vector2>@ __getVertexTexcoords(uint index)" See example script "example_ogre_vertexData.as"
Task 3/3 from RigsOfRods#3030. This means I can start writing a script to batch together terrain objects (meshes+textures) for performance - especially for Community Map New script API: * objects: `MeshPtr, SubMesh, MeshManager` * to get vert positions, use "array<vector3>@ __getVertexPositions()" on SubMesh * ditto for vert texcoords, note the extra index param because mesh can have more than 1 texcoord layer: "array<vector2>@ __getVertexTexcoords(uint index)" See example script "example_ogre_vertexData.as"
This introduces 'example_ogre_terrnBatcher.as' which shows how Mesh/Material API works and will evolve into a production tool. this will conclude RigsOfRods#3030. THE INTENDED USE of the future completed TERRN BATCHER: 1. You start with a list of OGRE SceneNodes - see green box. 2. you pick those you want to batch together - see orange box. 3. [WIP] The tool generates one mesh which contains all those picked (keeping position, scale and rotation) and cover them in single material containing all the textures. 4. [TBD] The tool remembers what batches were done as a 'schedule', and allows saving/loading the schedule as file. Modders can share and improve the schedules. 5. [TBD] Modders can launch the tool directly from .terrn2 and auto-execute a schedule on map load. 6. Profit
Added OGRE Mesh/Material bindings + exampleThis introduces 'example_ogre_terrnBatcher.as' which shows how Mesh/Material API works and will evolve into a production tool. THE INTENDED USE of the future completed TERRN BATCHER:
|
This has no effect on rendering, it just helps users to diagnose the scene graph.
Prettier and more uniform object names - Helper func `ActorSpawner::ComposeName()` is now smarter, outputs nicer IDs and is used even more. This has no effect on rendering, it just helps users to diagnose the scene graph using the inspector script.
2 new example scripts. New script API: * `enum Ogre::RenderOperation` * `class Ogre::ManualObject` REF | NOCOUNT object type. This is castable to MovableObject. Official tutorial for Ogre::ManualObject: https://ogrecave.github.io/ogre/api/latest/manual-mesh-creation.html * Functions in OGRE SceneManager: `createManualObject()`, `getManualObject()`, `destroyManualObject()` * Extra feature: function `TerrainClass::getHeightAt()` for the MeshedConcrete example to work.
NOTE: the example script only blits to topmost mipmap, so to see the effect, you must be close to the object! This will be improved. New Angelscript API: * `game.loadImageResource(filename, rg)` - see GameScript.cpp & GameScriptAngelscript.cpp * `ImDrawList::AddImage()` - see ImGuiAngelscript.cpp * Ogre objects: `box; PixelBox; HardwarePixelBufferSharedPtr`, Texture functions `getBuffer(); getNumMipmaps()` Example code: ``` // src image Ogre::Image gSrcImg = game.loadImageResource("sign-roadnarrows.dds", "TexturesRG"); // dst texture Ogre::TexturePtr gDstTex = Ogre::TextureManager::getSingleton().load("character.dds", "TexturesRG"); // let the MAGIC happen Ogre::HardwarePixelBufferPtr pixbuf = gDstTex.getBuffer(/*cubemap face index:*/0, /*mipmap:*/0); Ogre::PixelBox srcPixbox = gSrcImg.getPixelBox(0,0); // getPixelBox(cubemapFaceIndex, mipmapIndex); box gDstBox; // where you want to put it. pixbuf.blitFromMemory(srcPixbox, gDstBox); ``` New/updated scripts: * new 'example_ogre_textureBlitting.as' - draws UI using GridViewer and lets user mouse-draw destination pixelbox. Hardcoded to use character.dds as destination. * 'gridviewer_utils.as' - added 'zoomMin' config, new func `screenToLocalPos()` to enable mouse-interactions with the viewed data.
… empty. The OGRE version we use (11.6) crashes anyway when normalheight parameter is blank, although for OGRE13+ it's supposed to be okay (regarding to Paroj @ GitterChat)
There are now 2 funcs: * `localToScreenPos()` - originally `projectPos()`, renamed to align with the below. * `screenToLocalPos()` - added recently to make texture-blitting example work.
Task 3/3 from RigsOfRods#3030. This means I can start writing a script to batch together terrain objects (meshes+textures) for performance - especially for Community Map New script API: * objects: `MeshPtr, SubMesh, MeshManager` * to get vert positions, use "array<vector3>@ __getVertexPositions()" on SubMesh * ditto for vert texcoords, note the extra index param because mesh can have more than 1 texcoord layer: "array<vector2>@ __getVertexTexcoords(uint index)" See example script "example_ogre_vertexData.as"
If you loaded a document with regions, their recorded character count would be stuck on the original value, so if you added/removed characters the folding would break. This was fixed. There is still a bug - orphan regions don't resurface as expected.
Problem: The `restoreRegionFoldStates()` didn't actually modify buffer, just restored the flag.
This introduces 'example_ogre_terrnBatcher.as' which shows how Mesh/Material API works and will evolve into a production tool. this will conclude RigsOfRods#3030. THE INTENDED USE of the future completed TERRN BATCHER: 1. You start with a list of OGRE SceneNodes - see green box. 2. you pick those you want to batch together - see orange box. 3. [WIP] The tool generates one mesh which contains all those picked (keeping position, scale and rotation) and cover them in single material containing all the textures. 4. [TBD] The tool remembers what batches were done as a 'schedule', and allows saving/loading the schedule as file. Modders can share and improve the schedules. 5. [TBD] Modders can launch the tool directly from .terrn2 and auto-execute a schedule on map load. 6. Profit
Problem: The character offsets weren't updated, so when you edited text above a folded region, it's content would come out corrupted after unfolding. This also factors out helper function `mergeCollectedFoldingRegionsWithExisting()` with extra commentary.
I really suspected the `array<dictionary> bufferLinesMeta` to be the culprit. When that was disproved, I thought collecting regions or merging region info could be it. Both were disproved too. To my surprise it was the `isChar()` helper. Profiling results [in microseconds] opening 'example_ogre_terrnBatcher.as': * Before: PROFILING analyzeBuffer(): total 205834us (CPU 206000us) regions 324us (CPU 0us) dict 15805us (CPU 17000us) merging 151us (CPU 1000us) * After: PROFILING analyzeBuffer() : total 32313us (CPU 32000us) regions 280us (CPU 0us) dict 15653us (CPU 16000us) merging 146us (CPU 0us)
// New Script API: // -- `BeamClass.getManagedMaterialNames()` -> `array<string>@` // -- `BeamClass.getManagedMaterialInstance()` -> `Ogre::MaterialPtr` // -- `Ogre::Pass.__getNamedConstants()` -> `array<string>@` // -- `Ogre::Pass.getFragmentProgramParameters()` -> `Ogre::GpuProgramParametersPtr` New internal API, `class Actor`: - getManagedMaterialInstance(const std::string& orig_name); --> Ogre::MaterialPtr - getManagedMaterialNames(); --> std::vector<std::string>
The 'example_ogre_terrnBatcher.as' script was updated - Use the new indexBuffer bindings - Perform merging of selected meshes (buggy at the moment) - Display an inline control for scene node visibility - useful to compare original vs. generated meshes
Script 'example_ogre_terrnBatcher.as' updates: - Added [dump] button to inspector scenegraph - tested to work also for ManualObjects - Fixed mesh generation (I forgot to offset indices for every new appended mesh) - Reduced debug outputs Code changes: - added RGN_LOGS, auto-created at startup (along with other resource groups) - the actor-dump code now uses RGN_LOGS - moved RGN_ defs from ResourceManager.h to Application.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I've just reverted the title of this PR from the intermediate "TerrnBatcher - terrain optimzation tool" to the original "AngelScript bindings for OGRE scene and stuff" because that's really what the bulk of the code here does, and I want to merge it already because lately I've been mentioning it almost in every my response in the sense "The PR 3030 would let you do this...", so let's not hold all those ideas back any longer. I'll create a new, dedicated branch for the TerrnBatcher script. |
Task 3/3 from #3030. This means I can start writing a script to batch together terrain objects (meshes+textures) for performance - especially for Community Map New script API: * objects: `MeshPtr, SubMesh, MeshManager` * to get vert positions, use "array<vector3>@ __getVertexPositions()" on SubMesh * ditto for vert texcoords, note the extra index param because mesh can have more than 1 texcoord layer: "array<vector2>@ __getVertexTexcoords(uint index)" See example script "example_ogre_vertexData.as"
This introduces 'example_ogre_terrnBatcher.as' which shows how Mesh/Material API works and will evolve into a production tool. this will conclude #3030. THE INTENDED USE of the future completed TERRN BATCHER: 1. You start with a list of OGRE SceneNodes - see green box. 2. you pick those you want to batch together - see orange box. 3. [WIP] The tool generates one mesh which contains all those picked (keeping position, scale and rotation) and cover them in single material containing all the textures. 4. [TBD] The tool remembers what batches were done as a 'schedule', and allows saving/loading the schedule as file. Modders can share and improve the schedules. 5. [TBD] Modders can launch the tool directly from .terrn2 and auto-execute a schedule on map load. 6. Profit
EDIT: This branch grew much beyond the original scope; see The End Goal See also updates at the end of this post.
Also remember:
~~~~Following text is the original opening post:~~~~
Work smarter, not harder.
This started as a Discord debate about shift stick animation and how to make it smooth. I half-jokingly suggested to use skeletal animation in the prop which would be controlled from scripting, and to my surprise that idea was supported. So, the primary goal of this PR is to bind OGRE's skeletal animation controls to AngelScript, for smoother shifting :)
The strong point of OGRE renderer is that the internal API is very well organized and documented. To display a 3D model in scene, you load
Ogre::Mesh
, useOgre::SceneManager
to createOgre::Entity
of the mesh and attach it toOgre::SceneNode
. To do the skeletal anim, you getOgre::AnimationState
from the entity and that's it - you callsetTimePosition()
oraddTime()
to play it. It's all in the docs: https://ogrecave.github.io/ogre/api/1.11/. Basically this is something modders could easily do directly, if it just wasn't C++. Since I already need to bindOgre::Entity
and so on for the primary goal, why not do it from the ground up... so the secondary goal here is to let modders load an arbitrary mesh, position/rotate/scale it in scene ... and play skeletal anims.Finally, I love diagnostic tools, and OGRE also allows user to enumerate all it's objects and traverse hierarchies. Since I already had to bind
Ogre::SceneManager
for the secondary goal, the only extra step for complete OGRE integration is to bindOgre::Root
global object. I did so, with a syntax that mimics the C++ side almost indistinguishably. This is a screenshot of the ogre demo script which shows it in action:Before you ask... yes, our scene hierarchy is a complete mess. We have 2 scene managers (technically legit but what's the other for?), the root scene node has 148 direct children and there's an unnamed node with 341 children (WTF? you need 1 node for each prop/flexbody/character/static objects ... but I'm on an empty map with 1 Mini!). Of course, the important point here is that now this internal mess which isn't normally seen (in C++ you use pointers, that's why names are mostly empty) had been brought to daylight.
UPDATE (Corrected 2023-04-01): Secondary goal is met.
You can now load/position/rotate/animate an arbitrary mesh from just AngelScript. The bundled script 'ogre_demo.as' now has 2 sections: Inspector (the above screenshot) and Pose Demo (the below screenshot). To run the script, open in-game console and say
loadscript ogre_demo.as
.UPDATE 2 (2023-04-01):
I just realized I'm not done here yet. The primary goal explicitly refers to stick shift animation, and even though the animation bit is in place, a data source for the shift status is missing. I'm going to need to add bindings for it, and that means binding the
RoR::EngineSim
object, which encapsulates engine+gearbox+differential and it's going to be a piece of work by itself. I'm going to create a separate branch for it so I can properly describe and present it, complete with demo script.UPDATE 3 (2023-05-28):
I decided to separate out the shiftstick/engine part to #3048 and get this merged because I already have other ideas of building on top of this, and it's large enough already.
UPDATE 4 (2023-09-18):
I ended up dealing with the shift stick the simple way: #3065 and in the meantime I also developed more OGRE-AngelScript bindings in the script_editor branch: #3074 (comment) and just now I moved them here.
UPDATE 5 (2024-02-11)
I've finally dealt with the Tuning branch and I'm back on this. I've set an end goal of this branch to optimize performance of our terrains, especially "Community map", and in the process add the ability to generate meshes and textures. See #3030 (comment)
UPDATE 6 (2024-02-26)
All the necessary script extensions are in place, I'm working on the tool
UPDATE 7 (2024-03-14)
I decided to merge this PR "early" (while the advertised TerrnBatcher tool is still in alpha stage) because the bulk of this PR is really the script extensionsw would that enable this tool to happen - but those have a vastly greater potential and opportunities to use it have been springing up all over the place lately.