Giter Club home page Giter Club logo

qodot-plugin's Introduction

Quake .map file support for Godot 3.x. For the Godot 4.x plugin, see Qodot 4.

Documentation

Hosted here: https://qodotplugin.github.io/

Overview

Qodot extends the Godot editor to import Quake .map files, and provides a data-driven framework for converting the entities and brushes contained therein into a custom node hierarchy.

Features

  • Natively import .map files into Godot and convert them into a usable scene tree
  • Supports
    • Brush geometry
    • Textures and customized UVs
    • Convex and concave collision volumes
    • Gameplay entities
    • FGD (Forge Game Data) export for custom game definitions
  • Configurable scene population
    • Leverages the map format's classname and key/value property systems
    • Spawn and configure custom Godot scenes and scripts based on entities defined in the map editor
    • Define the visual and collision properties of brush entities on a per-classname basis
  • TrenchBroom Integration
    • Simple, intuitive map editor with a strong feature set
    • TrenchBroom game configurations can be exported for tighter workflow integration
    • Nested TrenchBroom groups can be used to build a tree hierarchy from the format's standard flat structure

Showcase

Assorted props by @SunkPer

Summer Island by @SunkPer

Thesis

Qodot was created to solve a long-standing problem with modern game engines: The lack of simple, accessible level editing functionality for users without 3D modeling expertise.

Unity, Unreal and Godot are all capable of CSG to some extent or other with varying degrees of usability, but lack fine-grained direct manipulation of geometry, as well as per-face texture and UV manipulation. It's positioned more as a prototyping tool to be used ahead of a proper art pass than a viable methodology.

Conversely, dedicated 3D modeling packages like Maya or Blender are very powerful and can iterate fast in experienced hands, but have an intimidating skill floor for users with a programming-focused background that just want to build levels for their game.

Enter the traditional level editor: Simple tools built for games like Doom, Quake and Duke Nukem 3D that operate in the design language of a video game and are created for use by designers, artists and programmers alike. Thanks to years of community support, classic Quake is still alive, kicking, and producing high-quality content and mapping software alike. This continued popularity combined with its simplicity means the Quake .map format presents a novel solution.

Example Content

Various example scenes with inline README nodes are available inside the plugin folder to demonstrate each aspect of Qodot's functionality.

Extra Content

The Qodot extra content repository contains a set of additional resources, such as map editor plugins, logo graphics, showcase content and screenshots.

Qodot Elsewhere

Discord - Qodot

Reddit - Qodot

Godot Forums - Qodot

Godot Asset Library - Qodot

Shifty's Twitter

Credits

Kristian Duske - For creating TrenchBroom and inspiring the creation of Qodot

Arkii - For example code and handy documentation of the Valve 220 format

TheRektafire - For a variety of useful tidbits on the .map format

Ember - For creating the user guide

Calinou - For making Qodot work on case-sensitive systems

SunkPer - For showcase screenshots

lordee, DistractedMOSFET and winadam - For laying the groundwork of the FGD export and entity scripting systems.

fossegutten - For a typed GDScript pass

Corruptinator - For the idea of using TrenchBroom groups as a scene tree.

grenappels - For implementing smoothed brush normal edge splitting

FreePBR.com - For royalty-free PBR example textures

qodot-plugin's People

Contributors

auzfox avatar benbeshara avatar calinou avatar davidegiovannini avatar deadhostdave avatar deertears avatar distractedmosfet avatar focusjosh avatar fossegutten avatar lordee avatar matoking avatar mrezai avatar shfty avatar sunkper avatar zaraka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

qodot-plugin's Issues

Fully modular QodotMap generation functionality

All node-creation functionality within QodotMap should eventually be modular, to support a variety of rendering workflows.

Case in point from Arkii:
"I'd like to play with rendering it all as one draw call, without culling it might be fine even on decent modern hardware"

Right now that'd require directly inheriting from QodotMap and copy-pasting a ton of existing code around, which isn't a great way to extend. The geo generation stuff needs a refactor anyway since it's getting tall enough to tip over, so might as well do this at the same time.

Test TrenchBroom texture shearing

As far as I know the per-face data in the .map file isn't sufficient to infer texture shear since UVs are by-plane instead of by-vertex.

Need to figure out the black magic TrenchBroom uses to encodes this and make sure it's properly supported.

Texture WAD support

Most (if not all) existing Quake-format maps use WAD files instead of loose textures, so Qodot should support a texture import workflow at the very least, and full import/export if possible.

ShaderMaterial Support

Need to implement face properties in the TrenchBroom game config and parser, then output ShaderMaterial instances in the geo generator.

Texture seams with atlased mesh

The atlased mesh pipeline has small texture wrapping seams on certain edges, visible in the first room of E1M1.

Need to figure out the cause of the misalignment and account for it.

Optimize atlas shader mip levels

The atlas shader mip levels are imperfect right now, which causes some slight pixelation artifacting when moving the camera toward an unfiltered texture. Visible with the door across the bridge in the second room of E1M1.

Need to figure out how to manipulate the mip level optimally and minimize or eliminate artifacting.

Configurable mesh / collision split overrides

Specifically func_group and func_detail. From therektafire:

since func_groups are technically worldspawn as far as QBSP is concerned (and as far as qodot should be concerned as well), func_groups, func_details etc should be combined into single meshes since they are meant to be static level geometry. On the other hand other types of entities would probably be better suited for being imported on a per brush basis, like func_breakable. So what I would do is either add a cfg file to the plugin or an array entry to qodotmap which lists some defaults for which types of things should be imported in which way, and the user can edit it if they want different behavior
Oh and the same goes for collision as well as the visual model

This mainly seems like it would affect the per-entity node spawning pipeline, since the worldspawn no longer exists after the map file has been parsed into other kinds of geo.

Occlusion Culling

Should Qodot have its own system for this, since Godot doesn't have anything built-in as of 3.1?

My initial reaction is that building a solution to operate in more general Godot terms would be a better time investment, since each brush gets converted into a standard MeshInstance using an ArrayMesh to hold vertex data.

However, under the current model culling would have to be AABB / Box-Sphere based based, since you can't toggle visibility per face.

A better solution, and one that would take advantage of the .map format in a similar way Quake does, would be to instead create one mesh per brush face. That way each face could update its visibility separately based on simple point-in-frustum + normal-dot-camera checks.

It would be better if ArrayMesh offered the ability to selectively show/hide its component surfaces, but that doesn't appear to be a thing. Could store the vertices in an array somewhere and filter them into the ArrayMesh based on visibility, but that seems like it would be a lot of data-thrashing vs the multiple mesh solution.

Main thread is blocked by .map file parsing

While this isn't an issue for smaller maps, it becomes noticeable for denser and larger ones such as ad_chapters.

This should run on a thread, much like the geometry generation.

Significantly slower tree attach in newer versions

Tree attachment time has increased to the point where ad_sepulcher is no longer feasible to load. My initial suspicion is that NodePath is slowing things down, though that may not be the case given that the aggregated build steps are also affected.

If this is the case, attach paths need to be converted back into indices. There are wrapper functions for generating attach paths now, which should make it less painful.

Proper SpatialMaterial support

Currently brushes locate a texture asset directly, create a new SpatialMaterial, and then assign the texture to its Albedo property. This is fine for basic stuff, but doesn't allow the user to provide a custom material.

Couple of options to fix this:

  • Make Qodot speak Material instead of Texture
    • User would have to prepare a material for every texture (nope nope nope)
  • Expose a default material otion
    • Would force all textures to share a single material (also nope)
  • Use a Dictionary to store texture key -> material maps, and provide a fallback material param for textures without a material specified
    • Allows for full per-texture material control
    • Could make it hierarchical by texture subdirectory, or use regex matching on names
    • Should this be a new resource type, perhaps tying into .WAD support?

Optimize all existing build steps for threading

Certain build steps currently run in single mode, when they could be better-paralellized by running in per-entity or per-brush mode to take advantage of pool threads.

Need to sweep through and rewrite where necessary.

Automatic map format recognition

Errors are spammed to the console for every face in the map, causing the editor to lock until they finish.

Ideally the distinction between valve-format UVs and everything else should be automatic, but the practical solution right now is to have the geo generation process cancel itself and print a warning to the user.

Main thread is blocked by editor tree population

When the multithreaded generation process completes, QodotMap recursively traverses its children and sets their owned to the active editor tree to make them appear in the scene tree.

This process is expensive and causes the editor to hang momentarily. Much like .map file parsing, it's fine for smaller maps but becomes noticeable for more complex ones like ad_chapters.

If possible this should be done in a threaded manner, and failing that it should be timesliced.

CLIP and SKIP support

From theratikfire on the TrenchBroom discord:

  • SKIP and CLIP are special textures used to remove faces from brushes
  • SKIP is called 'nodraw' in source (VMF)
  • Faces with SKIP should be skipped completely
  • Faces with CLIP should be ignored by the visual geo generator, but still considered for collision

Support full range of Quake map formats

The first step toward supporting formats- need to save out the test geometry in each different map format, then run text diffs to compare them and determine how the formats are differentiated.

Option for automatic BakedLightmap building

Should be part of the Static Lighting build options. Create BakedLightmap volume based on AABBs.

Ideally should be available in single, per-entity and per-brush flavours, dependent on how the 'build from node' functionality in the BakedLightmap GDScript interface behaves.

Check the Godot source for the default from-node used when invoking a bake from the editor UI. Will probably shed some light on its behaviour re. Node parents breaking it out of the hierarchy.

Multi-threaded geometry generation

Single-threaded generation will cause maps to stall on load, and will only get worse with scale.

It should be possible to multithread on a per-entity and/or per-brush basis. I read about some caveats to using SurfaceTool off the main thread (need to pass null ArrayMesh to commit() and use return value instead).

PBR support for atlased mesh pipeline

Need to create one TextureArray per PBR channel. Is it preferable to minimize space wasted by non-PBR textures's blank spots in these arrays, or preferable to index them symmetrically for GPU-friendliness?

TextureLayeredMesh is not compatible with light baking

This is presumably due to the MeshInstance it maintains not being present in the editor tree, and thus not being exposed to the BakedLightmap node.

BakedLightmap appears to have a bake() function that takes a Node to bake from, but I'm not sure if that means it'll be able to see a MeshInstance that doesn't live in the editor tree. Need to experiment.

Port business logic to a native C++ DLL and integrate with GDNative

Since the geometry generation code is a brute-force algorithm across potentially large datasets (a.k.a. complex many-faced brushes), porting it to GDNative would be good for performance. This also opens up the possibility for the GDScript-side code to be strictly engine integration, making prospective ports to other engines easier.

This might conflict with the #4? Unsure of the status of multi-threading + GDNative, though I suppose the DLL could handle all of that native-side without involving Godot.

Separate texture array tiling out from QodotTextureLayeredMesh

This feature is specific to Qodot's atlas implementation, and should generate the tiled images in a build step before passing them to the QodotTextureLayeredMesh for direct application.

Once that's done, the improvements made to QodotTextureLayeredMesh can be migrated back to the base TextureLayeredMesh repo.

Build pipeline class

QodotMap should export a script class property that allows the user to select a set of build steps.

It should also define the initial state of the build context, for things like texture loading.

TrenchBroom game definition export from Godot

Ideally the user should be able to export a ready-to-go TrenchBroom config for their game, complete with a custom set of entity and face definitions defined within the editor.

This would require a custom resource for the game definition containing an icon (to be resized to 32x32), the data for GameConfig.cfg, and the data for a game-specific .fgd file.

FGD stands for 'Forge Game Data' and is an extension for Hammer's game definition files. Spec is available here:
https://developer.valvesoftware.com/wiki/FGD

CSG build pipeline

Spawn a top-level CSG combiner node, then populate it with CSGMesh nodes in Union mode using brush vertex data.

This should cull away any unnecessary internal faces, but might be a bit performance-heavy at build time and subject to edge cases.

Fix import of large maps

Currently importing a map of modest size (E1M1 from Quake, for example) will lock the editor as soon as the file has been saved.

The hang is down to some hacky code left in the import plugin that calls load() immediately after saving the map to a .tres in an attempt to force an update of scene instances that reference it. I don't think that code does anything useful since the asset IDs change on every reimport at the moment anyway, so will likely be removing it.

The problem may extend further than that though- I had the editor lock up upon selecting the imported E1M1.map last night, which may point to Godot having issues with massive .tres files. Need to do some more research.

Import fails in Godot 3.2 beta 2

I added the plugin to the 3.2 beta to see if any updates will be required for, and it appears to fail currently:

ERROR: Cannot get class 'QuakeMap'.
   At: core/class_db.cpp:343

Split main documentation out of README

The README.md is already becoming a bit bloated, so any hard documentation that isn't necessary for a glance-read understanding of the project should be moved onto the wiki.

Intermittent crashes during generation

This looks like it could be a race condition with assembling the geo tree structure, more research is needed into Godot's renderer threading modes.

Actually this looks like a more general-purpose error condition that may or may not crash.
So far most occurrences have been with the renderer in single-safe mode, but having done some research it doesn't seem like it should be effected.

This is backed up by being able to generate ad_chapters semi-reliably on it, whereas I'd expect more consistent issues if multi-threading alongside a single-threaded renderer was fundamentally unsafe.

Error sample:

ERROR: body_attach_object_instance_id: Condition ' !body ' is true.
   At: modules/bullet/bullet_physics_server.cpp:574
ERROR: get: Condition ' !id_map.has(p_rid.get_data()) ' is true. returned: __null
   At: ./core/rid.h:154
ERROR: body_add_shape: Condition ' !body ' is true.
started thread job 0 / 4
   At: modules/bullet/bullet_physics_server.cpp:504
started thread job 0 / 4
ERROR: get: Condition ' !id_map.has(p_rid.get_data()) ' is true. returned: __null
   At: ./core/rid.h:154
ERROR: body_set_shape_transform: Condition ' !body ' is true.
   At: modules/bullet/bullet_physics_server.cpp:524
ERROR: get: Condition ' !id_map.has(p_rid.get_data()) ' is true. returned: __null
   At: ./core/rid.h:154
ERROR: body_set_shape_disabled: Condition ' !body ' is true.
   At: modules/bullet/bullet_physics_server.cpp:553

From the look of it, the physics server doesn't have a resource ID for whatever body is being attached. Must be an issue with one of the add_child calls during geo generation.

Manually-calculated vertex tangents

The autogenerated tangents from SurfaceTool are broken for all Qodot faces, and cause the deep parallax depth mapping functionality of the SpatialMaterial to crash the engine, and in some cases the GPU driver.

Adding custom tangents during the SurfaceTool building process makes it work, though I don't know if my algorithm is valid.

I'm getting some extreme texture warping from certain angles, but enabling deep parallax makes that stop so I'm unsure if it's simply a known aspect of non-parallax depth mapping on heavily-zoomed textures.

Probably worth reporting the hard crash to the Godot repo too, time allowing.

More intuitive class layout for build pipelines

Since the setup / visuals / static collision / area collision / lighting build steps already form natural groups, the build pipelines should either be split appropriately (since QodotMap assembles on-demand anyway) or arranged with a new BuildStepGroup class.

I think avoiding a new class is preferable, maybe pipelines themselves need to be renamed to something befitting a smaller group of steps.

Either way, also need to refactor pipeline assembly with a function for combining groups.

Build profiling option

Should be implemented as a checkbox on QodotMap and cause information to be printed to the log during build.

Possible data:

  • Entity / brush / face / vertex counts
  • Map / entity / brush / face build times
  • Custom node spawn count
  • Loaded texture count
  • Generated material count

Feel free to drop extra ideas in here if you have any @Calinou

Aggregate brush CollisionShapes by CollisionObject type

Similar to the recent visual geo generation refactor, a new collision shape build process needs to be implemented that uses a single CollisionObject with many CollisionShape nodes at its children, rather than one CollisionObject per brush.

Areas will still need to be done per-brush, as they represent triggers and thus should not be shared.

Proper wiki documentation

Need to create proper step-by-step guides that break down various Qodot features and use-cases, preferably including screenshots for context.

Areas to cover:

  • Setup
  • Basic map building
  • Automatic material / texturing
  • Extending the build system via build step classes and build pipelines

Light support

Lighting functionality varies game-by-game, so I don't want to standardize Qodot around a single existing implementation.

However, it would be much less useful to ignore light entities completely, given that there are creators deep into the Quake map ecosystem who've already done a lot of lighting work for maps they might want to use.

Current thoughts:

  • Game-specific support can be implented through an EntityMapper subclass
  • Having basic support for light params shared across all games would be good - position, intensity, etc
  • Being able to spawn the lights outside the tree so they don't get nuked on reload would be a good optional pipeline for doing the broad strokes in TB, then tightening them up in Godot
  • Could implement Godot-specific light definitions in the TB game profile that feed directly into the types and parameters available, so the option for full TB is available despite its lack of light rendering

Possible pipelines:

  • Don't place any lights in the .map, do it all in Godot
  • Use .map lights as a rough prepass, then manually tighten them up in Godot
  • Use .map lights exclusively

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.