eu07 / maszyna

MaSzyna Train Simulator
http://eu07.pl
Mozilla Public License 2.0
124 stars 50 forks source link

update vertex structure to add user data for custom shader use #63

Closed wls50 closed 1 month ago

wls50 commented 3 months ago

This PR adds a four-component floating point vector to OpenGL vertices. Possible use cases are eg. per-vertex terrain painting and simple vertex animations. T3D, E3D and SBT specs had been updated accordingly without breaking backwards compatibility (in case of T3D/E3D files).

Changes to T3D format

Before NumVerts: (before NumIndices: of indexed mesh), additional key-value pair can be specified: UserData: {true|false}. If it is present, the vertex data block must be followed by a block of NumVerts * 4 values.

Example


//---------------------------------------------------------------------------------
Parent: none
Type: Mesh
Name: Plane02
Anim: false 
Ambient: 255 255 255
Diffuse: 255 255 255
Specular: 0 0 0
SelfIllum: false
Wire: false
WireSize: 1.0
Opacity: 100.0
Map: chodnik_tetka
MaxDistance: 1000
MinDistance: 0
Transform: 
           1. 0. 0. 0.
           0. 1. 0. 0.
           0. 0. 1. 0.
           0. 0. 0. 1.
UserData: true
NumIndices: 6
0 1 2
2 1 3
NumVerts: 4
//  Px    Py    Pz    Nx    Ny    Nz    Ux    Uy    Tx    Ty    Tz    Tw
    -1.   -1.   0.    0.    0.    1.    0.    0.    1.    0.    0.    1.
    1.    -1.   0.    0.    0.    1.    1.    0.    1.    0.    0.    1.
    -1.   1.    0.    0.    0.    1.    0.    1.    1.    0.    0.    1.
    1.    1.    0.    0.    0.    1.    1.    1.    1.    0.    0.    1.
//  U0    U1    U2    U3
    1.    0.    0.    1.
    0.    1.    0.    1.
    0.    0.    1.    1.
    0.    0.    0.    1.

Changes to E3D format

VTN4..7 vertex table specs have been added. The difference to VTN0..3 is that each vertex contains a four-component user data vector at the end. In case of packing being enabled, the vector is compressed to half4.

Changes to SBT format

Format header has been changed to SBT2 to signal error and regenerate the sbt if trying to load obsolete files. Each vertex in SBT2 contains the user data vector at the end.

Changes to scenery loading

Indexed meshes can now be correctly converted to shape.

Changes to material system

vertex.vert now outputs a vec4 interpolator UserData that contains the user data ordered as in t3d file.

Testing done

The example t3d file above had been placed in an empty scenery file and tested with varying visibility ranges in order to (1) render as animated model, (2) convert to shape and store in SBT and (3) load from SBT file. The associated shader file has been modified to display user data as color (not part of this commit). A short session has been played on "l053_poludnie.scn" in order to ensure that assets from SVN are not corrupted by the change to t3d.

Milek7 commented 3 months ago

I'm not sure what's the point of allowing different userdata types if they are converted to float anyway. (if necessary, having real integer attributes would be reasonable).

Overall, I'm not a fan of inflating basic_vertex by 16 bytes for all geometry for feature which will be used only by few special-purpose models. This should be attached as separate optional vertex stream that's only present for geometry that actually uses this feature.

wls50 commented 3 months ago

That's a valid point. For me, the case of an optional vertex attribute boils down to the question of whether unused input layout elements are consistently stripped at program linking stage, which in testing was not an issue for the nvidia driver but may vary with other vendors. Otherwise it all would need a larger-scale rewrite of the 3.3 renderer to accomodate for multiple choice of vertex shaders, which obviously must be done for vertex animation affairs but not really when we talk about vertex painting (which is a feature heavily requested by some scenery modelers).

wls50 commented 3 months ago

Now the presence of user data in vertex arrays changes on a per-geometrybank basis - this way the legacy renderer and userdata-less content will not be affected by an increase of VRAM usage. Type casting is also not part of the proposal anymore.

Milek7 commented 3 months ago
std::vector<world_vertex> vertices; // world space source data of the geometry
gfx::userdata_array userdata;

Does world_vertex really needs user_data, given there's separate vector for it anyway?

For me, the case of an optional vertex attribute boils down to the question of whether unused input layout elements are consistently stripped at program linking stage, which in testing was not an issue for the nvidia driver but may vary with other vendors.

It seems to me that for geometry without user_data attribute should be disabled with glDisableVertexAttribArray and default value provided with glVertexAttrib4f. It seems that core profile spec explicitly allows such usage (from E.2.2 Removed Features):

Vertex arrays and array drawing commands must be used to draw primitives. However, VertexAttrib* and the current vertex attribute state are retained in order to provide default attribute values for disabled attribute arrays.

wls50 commented 3 months ago

Does world_vertex really needs user_data, given there's separate vector for it anyway?

removed

It seems to me that for geometry without user_data attribute should be disabled with glDisableVertexAttribArray and default value provided with glVertexAttrib4f.

It's likely that we do not need to do anything if using VAO as the attributes are disabled by default and filled with (0, 0, 0, 1) as per Khronos wiki. I also increased the max. number of vertex attribs that are disabled when using global vertex array so that we do not end up with buffers being erroneously bound across successive draws.