Jump to content

Elix_x

Members
  • Posts

    878
  • Joined

  • Last visited

Posts posted by Elix_x

  1. 1 hour ago, diesieben07 said:

    I am sorry, but this is precisely what not to do. Blockstate properties (unlisted or not) may be passed off to a rendering thread, which must not interact with the main game objects like the world. This is precisely why block states work the way they work. If you must pass custom data through unlisted properties, you must grab it all in getExtendedState and then pass it into the block state as an immutable (or immutable-like, i.e. not changing anymore) object. An IBlockState object should never suddenly change it's contents, which yours does, since the World can and will change.

    I understand that concurrency is an issue that can occur at any time. But what's the other way of passing required information to the model? You could compile everything you need into immutable objects to be passed, and that work on that in tessellation, but that creates compilation (+decompilation) overhead.

  2. Yep, you have to declare them in block class to make MC know about them, and actually provide/update them.

    FYI: This is similar for saved, actual and extended props. The declaration of all 3 is in createBlockState, saved props are handled by meta<->state methods, actuals by getActualState and extended - by getExtendedState. The difference between actual and extended, is that actual is used on server and client, has a limited number of serializeable values it can take and can be used in state mapping (~json model). Extended state is used only on client, can take any values of any type, and cannot be used for state mapping - aka only custom IBaked models.

     

    FYI 2: Actually, if you can create a single unlisted property for tile entity and pass it directly, instead of world and position. I'm just using 2 separate props, because i'm using them for other blocks too, which don't always have a tile entity, or i simply don't need it.

  3. If you won't be animating, use custom IBakedModel. If you do want to animate, as Draco said, use Fast TESR.

     

    By creating custom implementation of IBakedModel, you can override getQuads. In order to provide tile's data to get quads, pass unlisted properties from your block to model (override unlisted prop methods in your block class). getQuads is called each time model is drawn (item / in-world render update). So, in there, get baked models for all your parts, stream all the quads transforming accordingly, collect into a list and that list (considering your frame is rather a non-full block, you should do it only when side arg is null - side arg is for adjacency culling - ).

     

    Example (might be too many files to all link here) : IBaked, Helper, Uses client baked lib and client baked pipeline (and here), Model reg manager for using loaded & mapped json/obj/baked models for custom stuff, and a lot more...

  4. Just as Draco said, you have to translate the lid such that it's origin is world origin, rotate, then translate it back.

    Notice GlStateManager.translate(x, y, z) in the beginning of the method. This method translates tile entity in the world view space. Now the origin (0,0,0) is "actually" the XYZ of the tile entity, AKA you're working in local coordinates - coordinates relative to the origin of tile/model. So you have to translate the lid by it's local model coordinates to local origin and back. Ex: GL.trans(-lidModelCoords).rot(rot).trans(lidModelCoords).

  5. 2 minutes ago, ctbe said:

    In step 3, all the axes of reference get rotated. Meaning that any translation in the x axis afterwards, will be diagonal. This is 2D, but in minecraft, all 3 axes of reference get rotated together with  the object (x, y, z).

    This is the definition of matrices. Understanding matrices will definitely help you solve this. I recommend watching this:

    Linear transformations and matrices | Essence of linear algebra, chapter 3*

    Spoiler

     

     

    As for how to rotate around an axis, in 3D, you can look at how utility method is implemented in JOML:

    https://github.com/JOML-CI/JOML/blob/c312304fefbe757e3d37cba866f5742b3448a85c/src/org/joml/Matrix4f.java#L11379

     

    This is generic use case, but now i have to correct you. What you put in the "What is happening" is not correct. Because in both translation, rotation and scaling, coordinates do "the same" what the model does (it is actually the opposite - model does whatever you do to the coordinate system).

    That said, the transformations you apply further down in the stack, actually apply to the already transformed coordinates as a whole, so

    multiplication_order.jpg

     

    • Like 1
  6. The texture UVs you have are actually the global UV coordinates on the texture atlas. So what you will need is figure out a way to access the texture atlas sprite that was used to bake the quad. In the sprite, you will find min & max global UV coordinates. Now just do some math, and apply the values.

    Note: if you're trying to reduce the resolution of the texture, you have to do it completely differently.

     

    As for manipulating quads data, you can't just do it on that raw data. Because quads for blocks and quads for items are in a different VertexFormat - the index defining each format element is different. You'll have unpack the quad first (into forge's UnpackedBakedQuad), then manipulate the more conveniently, but still not very, stored vertex data.

    Take a look at the VertexFormat class to see how it is constructed.

     

    PS: I have a library i use to unpack models, quads & vertices into Java friendly format (easy get&set operations). If you want, you can check it out here.

    • Like 1
  7. Considering above, there is a way to render based on ticks, and it is used by Vanilla entities, chests, etc... Very often in the render/draw method, you get a float parameter partialTick. It is between 0 and 1 and it represents how much in-between 2 ticks the current frame is. Use it to interpolate between previous and next tick and you get smooth transitions / animations.

  8. 21 minutes ago, Matryoshika said:

    And yes, you told me to use an IBakedModel, but how the hell would I be able to provide the data (IBlockState & byte) that exists in the Tile, to the model?

    The data is only stored in the Tile & ItemStack.
    An ICustomModelLoader only provides a ResourceLocation.

    First, ICustomModelLoader has nothing to do with this. Custom IBakedModels should be replaced in the registry in the ModelBake event.

    Second, to provide data to custom unbaked you can use IUnlistedProperties. Just like block has properties, it also has unlisted properties. While normal properties are both server and client, can be use for logic and require fixed amount of allowed values, unlisted properties are only used for rendering and can hold absolutely any values (even Worlds!).

    You have to implement (similarly named methods) getUnlistedState&Container in the block class and cast IBlockState to unlisted state container (don't remember exact class name, sorry) to be able to retrieve unlisted properties.

     

  9. 5 hours ago, TLHPoE said:

    public void chunkLoad(ChunkDataEvent.Save e)

    o_0

    So... which one?

    5 hours ago, TLHPoE said:
    
    NBTTagCompound chunks = nbt.getCompoundTag(Reference.WORLD_DATA_CHUNKS);
    for(String string : chunks.getKeySet()) {
      chunkData.put(new ChunkPos(string), chunks.getCompoundTag(string));
    }
    
    NBTTagCompound chunks = new NBTTagCompound();
    
    for(ChunkPos chunk : chunkData.keySet()) {
    	chunks.setTag(chunk.toString(), chunkData.get(chunk));
    }
    
    nbt.setTag(Reference.WORLD_DATA_CHUNKS, chunks);

     

    WorldSavedData is not a correct place to store per chunk data.  You have access to chunk NBT in both chunk load a save events for a reason ;).

    5 hours ago, TLHPoE said:

    public class ChunkPos

    Did you know, that vanilla already has a ChunkPos class?

     

    Also, hash maps won't work if you don't implement hashCode and equals (use your IDE to generate them).

    • Like 1
  10. First, when i helped you previously i told you how to render these models without TESR. On top of that you told me you don't really like neither tile entities neither TESR. And now you are using TESR.. o_0 ??? ? ? ?

    (Hint: it is using custom IBakedModel, which will also resolve current transparency issues).

     

    Second, i am pretty sure it has to do with the render pass. Try rendering it in pass 0 instead.

  11. 16 minutes ago, Matryoshika said:

    I am aware of TileEntity no longer ticking off of the bat in 1.8+, but my... disdain for them, stems more from the rendering perspectives of TESR's, than the actual usage of TileEntities. I believed you were advising me to use TE's merely for rendering, which I now stand corrected in.

    Well, tile entities can even be as simple data storage things now. Not be used for ticking nor for rendering.

    16 minutes ago, Matryoshika said:

     

    I never stated I wanted to add compressed blocks for each and every block there is, merely support the option of adding new compressed blocks, based on other. I know some pack-maker's are painfully diligent, but I do not see anyone adding 100+ of these blocks.

     

    I merely stated that storing data can be done in the block, not that I am doing so for every little tidbit, though I cannot fault you on that. I do believe I need to work on making myself more clear in these matters.

    Ok. I see now.

    I'd still personally prefer tiles for this, but at this point it does not matter much.

     

    16 minutes ago, Matryoshika said:

    Yes, I am well aware I am using a byte instead of integer. Why? Essentially, why not. Don't see anyone managing to get 20¹²⁷+ blocks of anything, not that I'm implementing such high compression.

    Because java's native/default type is integer?

  12. 9 minutes ago, Matryoshika said:

    Thanks, but you are jumping the gun a bit there at least.
    I am talking about a mere block, that is based on another, and is nothing more than storage (Think ExtraUtilities compressed blocks, for example).

    I never stated, nor implied that I was using a TileEntity in conjunction with these blocks, and I do not feel inclined to do so, unless I am forced to do so, due to rendering issues etc.

    Storing data (original block|blockstate etc) can be done in the block, here, as the data is not meant to ever be changed.

     

    Thanks for the rendering pointers though.

    1. I forgot to mention -  since 1.8, Tile Entity =/= Lag. Because since 1.8, tile entities can be not tickable (aka not require update). Just look at Chisel & Bits - the great example.

    2. This way, you will never support all the blocks. Minecraft Forge is limited to 4096 block ids and 16 states/block... In 70% of modpacks, amount of used up block ids can be easily beyond 60%. You just can't create duplicate for every variation in the space that is left.

    3. Just don't tell me you store your data in a block like this:
     

    public class CompressedBlock extends Block {
      
      public Block unCompressedVariant;
      
    }

     

  13. 5 hours ago, Matryoshika said:

    Thanks.
    As far as I can see, you mean that I should merely use the base quads, and merely "clamp" them together into one model, translating them by a*n*0.33 where a equals axii, and n equals iterations per side, and jump over iterations [5, 11, 13,14,15, 17 & 22]
    This brings up the issue with "find the model of the "original" block".

    I never mentioned this in the OP, but I wanted to add the functionality of allowing full configurability for this compression, allowing any block to be compressed.
    I keep to the preferred RegistryEvent, though most mods still use preInit for content-registration, so of course, there'll be nullpointers even if I used "after:*" in dependencies.
    As such, I believe this can be surpassed by defining a block in-game (when the server is up), get the blockstate, get textures from it, serialize it (to a file), then after the next restart, actually add the new compressed blocks to the game, and have the new block invoke the original blocks methods (for consistency).

     

    Anyone seeing any issues in doing it this way?

    I did understand that you wanted to make support for all blocks, but i though that you have already set up the tile entity. Apparently you did not.

     

    Tile Entities can be used to store additional data with blocks that is not serializeable in 4 bytes of metadata. And it is what you want to use to store the original block (or even IBlockState;) ). Just implement load/save to NBT methods to make sure that it is saved (Block can be saved by saving its' registry name, simple/meta-serializeable IBlockStateby saving block and serializing it into metadata and complex/not-serializeable IBlockState can be saved by saving block and than a map of properties to serialized values).

     

    How to pass original block/state from tile to model? Implement Block#getUnlistedProperties (or similarly named method) - it allows to pass unlisted properties (properties that can store absolutely any values) to the IBaked. Now just create a (static) unlisted property holding original block/state and then in the method (you have both world and pos) retrieve tile, get original and store it in unlisted prop.

    Now in the IBaked, you can back the original by retrieving value of unlisted property from state you have as param.

     

    Getting model of the original: (i don't remember exact methods, so) Look through model classes - ModelLoader, ModelBakery. All models (items and blocks) should be cached there somewhere. Just find how to get to them.

     

    PS: Try using this method of quads "clamping". If there will be important FPS drops, i have an idea on how to make it a lot better. But it involves interaction with Open GL directly (without MC engine & wrappers) and a lot of infrastructure. So if it is not required, there's no need in implementing it.

  14. Use custom IBakedModel for your block.

    In the getQuads method, find model of the "original" block and retrieve its' quads. Now, just re-add these qauds applying necessary transforms as many times as you want. You can find the basics of applying transformation matrices to quads here: https://github.com/Elix-x/EXCore/blob/rendering--vertex-pipeline/src/main/java/code/elix_x/excore/utils/client/render/pipeline_old/MatVecApplicator.java#L52.

     

    And you probably also want to cache models to not recalculate quads each time (RIP FPS). I have a model cache here, it is free to use. Just register it as a reload listener and you're good to go.

  15. 10 hours ago, Kaiodenic said:

    Fair enough, I'm alright with that. Would you happen to know where Minecraft initially pushes things to OpenGL based on what it is (block type, or block/entity)?

    Unless it uses the same settings for everything, in which case I'll probably have to pass. I feel like changing that would make it incompatible with a lot of mods.

    It would not make it incompatible with other mods. Just make sure to "save" GL state before you start rendering with shaders to restore it after.

     

    First, create custom shader helper class, that sets all uniforms, uploads shader, binds, etc... Now, if you want your shader to be customizable with resource packs, implement and register IResourceManagerReloadListener, in which you load/reload shaders. Otherwise, just upload it in post init.

     

    Now, when your TESR is called, bind your shader, render OBJ model and then unbind the shader.

    Seems easy? It isn't.

     

    For the rendering part, as i said previously, you can either change how you upload things to shader or how you shader reads things.

    The first option is easier. Just create all necessary classes using modern GL functions - Mesh, Matrix Handler, etc... For the mesh, it is recommended to use VAO with indexed position VBO and non-indexed texture & normal VBOs, because that's how OBJ model is encoded. Now you just have to write your own OBJ reader and compiler (which compiles it into a mesh). There are plenty of tutorials online on how to do this.

    Read, compile and upload your model into mesh either in resource reload listener or post init and render this mesh in TESR.

     

    Now just make sure that you inform users of your mod that at least GL3 support is required ;) (all modern graphics cards support it, so no much worries).

     

    Note: Rendering performance can be improved very much, by binding shader once... But i'll let you think on how that can be done :) .

    • Like 1
  16. 1 hour ago, Kaiodenic said:

    As for the other points, does anyone know how to the renderer to use a custom shader? The code I've seen thus far was pure Java and only enabled/disabled effects used by vanilla, not using fully custom-written shaders. For my project I specifically need to override the fragment shader.

    Vanilla does not support custom shaders by itself (except ones activated when you spectate as a spider/creeper/enderman). So you have to use LWJGL and Open GL directly. But be ready to either completely change the way you draw model in-code or the way your shaders accept data. Because how vanilla MC pushes stuff to GL and how shaders normally work do not match at all.

  17. 9 hours ago, aw_wolfe said:

    I also still can't get my forest biome to replace the standard forest.  Is there a good biome tutorial for 1.11.2 ? All biomes tuts I've seen so far are for older version where most of the functions approaches are deprepricated.

    Because biomes use forge registries now (just like item and blocks), you can replace them using substitution aliases.

    First, read up on forge registries here - http://mcforge.readthedocs.io/en/latest/concepts/registries/.

    Now, to replace forest biome, register your own forest biome just like you would a new biome, then retrieve biome registry (either trough Biome or GameRegistry) and call #addSubstitutionAlias(String modid, ResourceLocation nameToReplace, Biome replacement).

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.