Ragna.roBrowser icon indicating copy to clipboard operation
Ragna.roBrowser copied to clipboard

Sprites & Effects don't show behind glass walls

Open MrAntares opened this issue 2 years ago • 6 comments

This is a rendering order type of issue.

When playing on the map kh_dun02 I noticed that there are some transparent glass walls. If I stand behind them, the sprites/effects don't show through, only the ground, because the map is rendered first and everything else is later.

This can be very problematic to fix, because the map is read into one huge mesh with one gigantic texture (as I understand, might be wrong) to save performance and rendered all at once, but in order to fix this, the glass walls needs to be separate objects that are rendered after anything behind it, again, rendering order needs to be sorted by depth. This can be also problematic, when later we try to animate map models like shops with moving parts or machines or airship wings and propellers moving, because we need to be able to move the components separately from the rest of the world..

MrAntares avatar Apr 21 '22 07:04 MrAntares

Why merge the terrain with the models? The standard approach is to use hardware instantiation and keep them as separate instances, all of which can be animated on their own by changing the position, rotation, and scale.

You also can't implement advanced features like the texture animations used in some RSM2 models if there's just one mesh (and texture) to work with.

rdw-software avatar Apr 21 '22 11:04 rdw-software

Dunno. This is how I got it. Ask @vthibault :D I am way too dummy dumm dumm for this.

MrAntares avatar Apr 21 '22 11:04 MrAntares

Btw I can be completely wrong about this, I base this solely on comments in files, like: Models.js @140

		// Fetch all images, and draw them in a mega-texture

and

MapLoader.js @359

	MapLoader.prototype.compileModels = function CompileModels( objects )
	{
		var i, j, count, size, bufferSize;
		var object, nodes, meshes;
		var index;
		var progress = this.progress;
		var models = [];

		bufferSize = 0;

		for (i = 0, count = objects.length; i < count; ++i) {

			object = objects[i].compile();
			nodes  = object.meshes;

			for (j = 0, size = nodes.length; j < size; ++j) {

				meshes = nodes[j];

				for (index in meshes) {
					models.push({
						texture: 'data\\texture\\' + object.textures[index],
						alpha:   objects[i].alpha,
						mesh:    meshes[index]
					});

					bufferSize += meshes[index].length;
				}
			}

			this.setProgress( progress + (100-progress) / count * (i+1) / 2 );
		}

		// Merge mesh
		this.mergeMeshes( models, bufferSize);
	};

MrAntares avatar Apr 21 '22 11:04 MrAntares

But regardless of all this, rendering order is still an issue, because it is still based on manual calls:

MapRenderer.js @372

		// Spam map effects
		Effects.spam( Session.Entity.position, tick);

		Ground.render(gl, modelView, projection, normalMat, fog, light );
		Models.render(gl, modelView, projection, normalMat, fog, light );

		if (Mouse.intersect && Altitude.intersect( modelView, projection, _pos)) {
			x = _pos[0];
			y = _pos[1];
			// Walkable
			if (Altitude.getCellType( x, y ) & Altitude.TYPE.WALKABLE) {
				GridSelector.render( gl, modelView, projection, fog, x, y );
				Mouse.world.x =  x;
				Mouse.world.y =  y;
				Mouse.world.z =  Altitude.getCellHeight( x, y );
			}
		}

		// Display zone effects and entities
		Sky.render( gl, modelView, projection, fog, tick );
		EffectManager.render( gl, modelView, projection, fog, tick, true);
		EntityManager.render( gl, modelView, projection, fog );

		// Rendering water
		Water.render( gl, modelView, projection, fog, light, tick );

		// Rendering effects
		Damage.render( gl, modelView, projection, fog, tick );
		EffectManager.render( gl, modelView, projection, fog, tick, false);

		// Play sounds
		Sounds.render( Session.Entity.position, tick );

With this method I see no way to fix the transparency issues. EVERYTING has to be rendered in depth order from back to front otherwise it just won't work. This is a big issue right now.

Anyone feel free to play with this, because there is effectively 0 chance that I could fix it.

MrAntares avatar Apr 21 '22 11:04 MrAntares

Why merge the terrain with the models? The standard approach is to use hardware instantiation and keep them as separate instances, all of which can be animated on their own by changing the position, rotation, and scale.

Hi, just noticed this mention !

It was 2012/2013, so:

  • WebGL just started landed in some browsers (not optimized at all)
  • All GPU calls was potentially converted to DirectX using Angle project resulting into poor performance (each GPU calls was slows, so it was better to merge them to avoid slowing down the app).
  • Javascript JIT performance was not so great yet.

Merging everything by shaders and textures helped to reach 30/60fps at the time and avoided to do the following and costly operations (leading to really poor performance) :

  • Getting all objects
  • Doing frustum culling at render to avoid processing non visible objects (slowing down CPU)
  • Getting all objects and sorting them by depth (slowing done CPU)
  • For each 3d model
    • For each meshes
    • Calculate animation (slowing done CPU)
    • For each textures
      • Change shader (slowing done GPU)
      • Change texture (slowing done GPU)
      • Render

At the time, it was better to send the whole 3D stuff to the GPU so it handles it, and let the CPU handle critical things (A Star, mouse ray casting, file loading, effects, sprites, ...).

But we are no longer on the same era. Computers are faster, WebGL has instanced drawing, Javascript JIT compilation is faster than ever. Maybe time to change this code, would require some rewrites (as the whole project) !

Related to #53, #96

vthibault avatar Jun 06 '22 15:06 vthibault

@vthibault Thank you for the input :) If you are interested, feel free to peek into our discussion ;) https://discord.gg/8JdHwM4Kqm

MrAntares avatar Jun 07 '22 07:06 MrAntares