Design Alternative block mesh functionality

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
This has come up from time to time: a desire to change the mesh or texture of a block away from its default block(family) settings. I personally connect that to a block animation system of some sort but this post mostly consists of a chat log talking about just static block updates with the primary example being two kinds of fences (one wood, one stone) able to connect seamlessly maybe even without a block family definition at all (as that gets tied to a single block so it might be hard to translate / connect between types)

The idea would be to add a mesh override in a component and if present let the tesselator use the alternative and potentially trigger an event to update the chunk mesh. Don't ask me how any of that would work and don't count on me having gotten the details right! :) A potential added extra would be the ability for a block to be decorated with a secondary mesh/texture/shape such as a small forcefield surrounding it.

May also be of interest to @Immortius from a general architecture perspective and to @manu3d and @tdgunes from a rendering perspective, mostly from a "would this clash with any of the GSOC refactoring?" or "could this clash with a future optimized approach somehow?" not so much the "Help write some code while you're already drowning in more important stuff!" :)

The chat log below mostly contains suggestions from @Marcin Sciesinski who I poked repeatedly until some sample code fell out :) He also included a link to a relevant TerasologyPrime class. @Skaldarnar may be interested in helping implement it.

I made a public link to the code patch from ChunkTessellator here with minimal syntax highlighting but am unsure if that would disappear after it goes to the 10k item archive on Slack.

Slack log said:
skaldarnar [17:36]
imho, one problem with current block families is that they are tied to a specific block - if you want to have another block type with the same features (say, connecting fences) you need to define a new block family. No easy "stone fences" and such

marcinsc [17:49]
Yup, if we get rid of having the block rendering being bound to block (as opposed to entity), we can get rid of the families altogether.

cervator [17:56]
any of you want to write up an initial design doc of some sort? :slightly_smiling_face:

marcinsc [18:02]
Here is one approach:
https://github.com/MarcinSc/TerasologyPrime/blob/master/core/src/main/java/com/gempukku/terasology/graphics/environment/mesh/ListsChunkGeometryAndMeshGenerator.java

[18:02]
But you can also make an event approach rather than registry...

cervator [18:02]
want to submit a Suggestions thread or GitHub issue with some ideas, links, potential approaches, etc?

marcinsc [18:04]
Here it is. "When generating a mesh, if a block prefab has 'EventBasedMeshGenerationComponent', instead of normally adding mesh of the block, send an event on the BlockType entity with all the info that might be needed to generate the mesh for the block, including position in chunk, chunk position, and the mesh to append it to."

cervator [18:06]
i imagine there are probably more details and ideas related to that :slightly_smiling_face: it won't do much for me to post that somewhere since i don't know it well enough to be able to answer any follow-up questions - i know you're not a big fan of larger write-ups, but maybe?

marcinsc [18:06]
BlockType entity (or the entity for the block if it has one)

cervator [18:07]
and would that relate to / lead to better animated block rendering support as well?

marcinsc [18:07]
No, this is for static mesh block rendering.

[18:08]
animated blocks would require to be rendered separately from the terrain mesh.

[18:08]
Also, there is no need for followup questions, it explains everything. Someone should just pick it up from there and write it.

cervator [18:09]
hehe, i wish :slightly_smiling_face: i can throw it in a Suggestions thread but expect it might just sit there without the right eyes having found it - more detail can help broaden the potential audience

marcinsc [18:11]
The only more details one could add, is the place in the code where this sits, and I'm afraid it's deep in a "There Be Dragons" land of the legacy code, I do not even dare to go into.

[18:11]
It probably is original begla code.

cervator [18:12]
i wonder if our newer age 3d wizards could give it a spin

marcinsc [18:12]
It really shouldn't be difficult, it's like 5 lines of code added at the right place.

[18:13]
if (entity.hasComponent(EventBasedMeshGenerationComponent.class)) {
entity.send(new AppendMeshForBlock(parameters....));
} else {
... current code
} (edited)

cervator [18:14]
so that allows an entity to provide an override mesh, essentially

marcinsc [18:14]
Yes

[18:14]
The only thing missing is to allow (using events) to regenerate chunk mesh.

[18:14]
That would be called, when the block figures it has changed its look.

cervator [18:15]
so in the case of a former block family fence piece, it is configured with such an override, if an adjacent block is placed that causes the first piece to change then trigger a regen

marcinsc [18:19]
added a Diff snippet: Dynamic_generate_mesh_from_block.patch
Index: engine/src/main/java/org/terasology/rendering/primitives/ChunkTessellator.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- engine/src/main/java/org/terasology/rendering/primitives/ChunkTessellator.java (date 1450928393000)
+++ engine/src/main/java/org/terasology/rendering/primitives/ChunkTessellator.java (revision )
@@ -19,6 +19,7 @@
import gnu.trove.iterator.TIntIterator;
import org.lwjgl.BufferUtils;
import org.terasology.engine.subsystem.lwjgl.GLBufferPool;
+import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.math.Direction;
import org.terasology.math.TeraMath;
import org.terasology.math.geom.Vector3f;
@@ -54,8 +55,13 @@
for (int z = 0; z < ChunkConstants.SIZE_Z; z++) {
for (int y = verticalOffset; y < verticalOffset + meshHeight; y++) {
Block block = chunkView.getBlock(x, y, z);
- if (block != null && block.getMeshGenerator() != null) {
+ if (block != null) {
+ EntityRef blockEntity = block.getEntity();
+ if (blockEntity.hasComponent(EventBasedMeshGenerationComponent.class)) {
+ blockEntity.send(new AppendBlockMesh(chunkView, mesh, x, y, z));
+ } else if (block.getMeshGenerator() != null) {
- block.getMeshGenerator().generateChunkMesh(chunkView, mesh, x, y, z);
+ block.getMeshGenerator().generateChunkMesh(chunkView, mesh, x, y, z);
+ }
}
}
}
Add Comment Collapse

marcinsc [18:19]
Here you go, a patch for the hooking into current chunk generation. What is left, is adding the component and the event. :slightly_smiling_face:

[18:20]
But these are really simple :slightly_smiling_face:

cervator [18:20]
thanks! how many more minutes do you imagine for adding those two and all of it wrapped in a nice PR? :wink:

marcinsc [18:20]
Too busy/lazy :]

cervator [18:20]
hehe

marcinsc [18:21]
But at that point anyone should be able to pick this up, including @Skaldarnar :wink:

cervator [18:21]
hint hint, wink wink, etcetera!

marcinsc [18:21]
yup

[18:22]
maybe you can convince @michaelpollind to do that, since he wants to change rendering of "redstone" if it gets signal :smile: (edited)

[18:22]
He'd just have to modify the component for the entity to have "hasSignal=true" and then send an event to world to regenerate the chunk

cervator [18:23]
maybe :slightly_smiling_face: or @manu3d or @tdgunes could have an interest in it as part of overall refactoring of rendering - after GSOC tho so dunno when it might get attention

manu3d [18:24]
I think we are a bit swamped right now. And for the next century... :tired_face: (edited)

cervator [18:24]
yeah :smile:

marcinsc [18:24]
Here is a code to regenerate the chunks after modifying the block at position "worldPos":
for (Vector3i pos : ChunkMath.getChunkRegionAroundWorldPos(worldPos, 1)) {
RenderableChunk dirtiedChunk = chunkProvider.getChunk(pos);
if (dirtiedChunk != null) {
dirtiedChunk.setDirty(true);
}
}

cervator [18:25]
would that also be for ChunkTessellator ?

marcinsc [18:26]
No, this has to live somewhere else, maybe WorldProvider::blockMeshModified(Vector3i worldPos)

[18:27]
as in, this new method should be added to interface, with the WorldProviderCoreImpl having this method implemented in the way I have given above.

[18:27]
Of course an event would have to be sent to all clients about this as well...

[18:28]
Which is why I'd rather have this event-styled.

cervator [18:28]
so many nice added details :slightly_smiling_face:

marcinsc [18:33]
That would also allow to do some other cool stuff, that was not possible before, like generating two different mesh elements per entity (block). :]

cervator [18:33]
as in, more sophisticated block shapes?

marcinsc [18:34]
For example, if a block entity has "ForceFieldComponent", in addition to normal block rendering, it could also render a spherical translucent force field.

skaldarnar [18:34]
I'd like to get my hands on it... is there a good way to archive this conversation of the last hours?

[18:34]
:wink:

cervator [18:34]
copy paste :smile:

skaldarnar [18:34]
:disappointed:

manu3d [18:34]
Isn't the history of the discussion permanent? If so you can star some items @Skaldarnar

cervator [18:35]
if nothing else i'd do that in a forum thread, but maybe you could interpret and edit it some first @Skaldarnar :slightly_smiling_face:

[18:35]
@manu3d: unfortunately free Slack has a limit of the latest 10k items (messages etc) - i don't know if starring things bypasses that

[18:36]
(technically everything stays even beyond the 10k items but we can't access any of that unless we pay)

[18:36]
or get a free premium plan as a non-profit, which i'm going to attempt soon :slightly_smiling_face:

manu3d [18:36]
How much does it cost?

marcinsc [18:37]
I think it was quite a bit, since even my company was very hesitant in getting the premium.

cervator [18:37]
like $8/user/month - it adds up fast when you do a very inclusive open source project thing, while Slack is really aimed at enterprises where that cost is like petty cash

manu3d [18:37]
wow.

[18:38]
So, 10K items... that's like... a week of time you have for the no-profit filing? :laughing:

cervator [18:38]
i have sometimes wondered how long that actually lasts us, i have no real idea :slightly_smiling_face:

[18:39]
we submitted a request for a really nice looking IRC logging site with some extras, that way we could cut items from Slack by not logging here, but that was months ago by now

[18:40]
i'm hoping to do some non-profit org naming discussion toward our project birthday in a month plus change, then maybe have a filing done before the end of the year

[18:40]
brb

skaldarnar [18:41]
@marcinsc: is there anything one needs to be aware for dropped blocks with special mesh?

[18:41]
dropped blocks are not part of the chunk mesh generation, are they?

marcinsc [18:42]
I don't think so. Basically the standard logic you'd have in the ChunkTesselator, could be replaced by the system that handles that specific block rendering.

[18:42]
Ahh, you mean the item blocks?

[18:42]
on the ground?

[18:42]
They are not part of the chunk mesh generation.

skaldarnar [18:44]
yes, I mean the item blocks.

[18:45]
just to repeat it for me, a fence block would be normal block with some fence shape, and an attached component handling the shape changes when placed (e.g., EventBasedMesh)

marcinsc [18:47]
Yes, you could get rid of the block family for fence, and just have the block have EventBasedMeshGenerationComponent, and ConnectsToOtherFencesComponent with 'texture: wood' property.

[18:47]
So that it could event connect to stone fences :]

skaldarnar [18:47]
and the item block (dropped block) would be the fence block as defined in block definition

marcinsc [18:47]
Yeah

skaldarnar [18:48]
perfect... I'll try to user my after-thesis freetime wisely :smile:

marcinsc [18:48]
haha

cervator [18:48]
@Skaldarnar: you'll grab this stuff to work on it later or keep it safe then? or should i still do a Suggestions post to dump a chat log? :slightly_smiling_face:

marcinsc [18:50]
If you specify blockTile in the block (like texture: 'wood'), you can add many different fence types, without writing any code, by adding blocks with different values for the "texture".

skaldarnar [18:52]
@Cervator: I copied the chat log, but if you are up for a quick suggestion post I'll appreciate it.

cervator [18:52]
i can sum it up and dump the log a little later, sure - it won't have a lot of intelligence added by me tho :smile: you understand it way better than i

skaldarnar [18:53]
I need to get some sleep now, would be good if someone could make some notes who's not overly tired :tired_face:

cervator [18:53]
we can always go over it again at some point in the future, i bet Marcin would be around and up for another question or two later as well :slightly_smiling_face:

marcinsc [18:55]
:slightly_smiling_face:
 

manu3d

Active Member
Contributor
Architecture
May also be of interest to @Immortius from a general architecture perspective and to @manu3d and @tdgunes from a rendering perspective, mostly from a "would this clash with any of the GSOC refactoring?" or "could this clash with a future optimized approach somehow?"
I know very little (read: nothing really) of how block rendering actually works. The rendering engine renders the same block (chunk really) a number of times during different rendering passes (i.e. shadow map, reflections, ambient occlusions, etc). But the actual details of how this happens are hidden (in plain sight) in the Mesh and Chunk-related classes rather than in the rendering engine itself. The rendering engine just enables the shader, sets a number of parameters and iterates over the chunks to render them. The actual rendering happens in the single line: chunk.getMesh().render(phase); within WorldRendererImpl.renderChunks(...). So rendering is delegated to the mesh implementations rather than being handled directly by the renderer by, say, feeding 3D data to it. So, as long as the changes you are discussing remain compatible with these lines of code the GSOC project won't be affected.
 
Top