Jump to content

[1.19.2] Customised client-side only glow effect rendering


SoLegendary

Recommended Posts

My mod relies on a top-down view, which makes it very difficult to see mobs indoors and behind trees and other structures. I know that the glow effect is a thing which looked like a nice solution, however I don't want the full effect of it displayed at all times. Ideally, I want only the portion of a mob's model that is behind any block to be highlighted with the glow effect.

Here's a mockup of what I mean:

mnBsvjU.png

Additionally, I want to be able to control the thickness and colour of the effect too, with the same mob showing as different colours to different people based on my own variables.

 

EDIT:

If this turns out to be too complex, I may settle for just drawing simple lines, which I already do for my mobs (see the red square at the bottom of the villager's feet above). However, I can't seem to get those to render on the top layer (ie. in front of all other mobs and blocks). This is the code I have to render this now:

    public static void drawLineBox(PoseStack matrixStack, AABB aabb, float r, float g, float b, float a) {
        Entity camEntity = MC.getCameraEntity();
        double d0 = camEntity.getX();
        double d1 = camEntity.getY() + camEntity.getEyeHeight();
        double d2 = camEntity.getZ();

        RenderSystem.depthMask(true); // should control whether lines show behind blocks or not but has no effect whether true or false?
        VertexConsumer vertexConsumer = MC.renderBuffers().bufferSource().getBuffer(RenderType.lines());

        matrixStack.pushPose();
        matrixStack.translate(-d0, -d1, -d2);
        LevelRenderer.renderLineBox(matrixStack, vertexConsumer, aabb, r, g, b, a);
        matrixStack.popPose();
    }

 

Edited by SoLegendary
Link to comment
Share on other sites

It would probably be better to write a composite render type similar to how the normal outline does it, except this time change the depth test such that instead of applying always, it applies whenever the depth of the output rendering to the screen is greater than the depth of the villager in space.

I'm unsure on how this would be put into practice, but you may need to create a new shard. You can take a look at how the outline render type works and essentially replace it with your own.

Link to comment
Share on other sites

I think I might need to take a step back:

How can I just render this kind of entity outline on demand in the first place?

I have code like the one above to draw line boxes and lines (RenderType.lines()) and solid planes with transparency (RenderType.entityTranslucent()), but have never tried anything as complex as an entity outline.

I've found there is RenderType.outline() and I've that it accepts POSITION_COLOR_TEX vertices in the form of quads, but I have zero clue how I would even quantify the vertices and their positions, or if this is even the correct strategy for rendering entity outlines.

Link to comment
Share on other sites

11 hours ago, SoLegendary said:

What do you mean by 'create a new shard' ?

The properties of a RenderType are stored in a `RenderStateShard` which handles startup and teardown of a particular option (e.g. `RenderStateShard$DepthTestStateShard` handles depth test logic).

8 hours ago, SoLegendary said:

How can I just render this kind of entity outline on demand in the first place?

Based on what I gather in Minecraft, entity outlines are written to a separate render target which contains the same data as what is being drawn for the entity. From there, the render target applies an entity_outline program which uses the sobel vertex shader and the entity_sobel fragment shader. The fragment shader is responsible for detecting the edge of the texture and writing it to the fragment color to render around the entity. From there, it just applies it to the render target, adds a blur, and then renders it to the screen. Since the depth test is always and it is rendered almost last, you'll be able to see it in front of everything.

Since most of this can be reused, you probably can just change the depth test when rendering the outline buffer in a similar fashion since it's purely just how does it render on the screen.

If you don't understand shaders in opengl, however, I recommend learning about them first and see if you can backtrace what I have.

Link to comment
Share on other sites

I've tried replacing the DepthTestStateShard in RenderType.CompositeRenderType.OUTLINE with different variations:

I sourced the values for the 2nd param from here: https://github.com/drbrain/opengl/blob/master/ext/opengl/gl-enums.h

for the comparison operators listed here https://learnopengl.com/Advanced-OpenGL/Depth-testing

new RenderStateShard.DepthTestStateShard("always", 0x0207), // GL_ALWAYS
new RenderStateShard.DepthTestStateShard("never", 0x0200), // GL_NEVER
new RenderStateShard.DepthTestStateShard("<", 0x0201), // GL_LESS
new RenderStateShard.DepthTestStateShard("==", 0x0202), // GL_EQUAL
new RenderStateShard.DepthTestStateShard("<=", 0x0203), // GL_LEQUAL
new RenderStateShard.DepthTestStateShard(">", 0x0204), // GL_GREATER
new RenderStateShard.DepthTestStateShard("!=", 0x0205), // GL_NOTEQUAL
new RenderStateShard.DepthTestStateShard(">=", 0x0206) // GL_GEQUAL

And I assigned it like this, with the above values in myShard (and after making all the necessary fields public with access transformer)

RenderType.CompositeRenderType.OUTLINE = Util.memoize((p_173272_, p_173273_) -> {
  return RenderType.create("outline", DefaultVertexFormat.POSITION_COLOR_TEX,
    VertexFormat.Mode.QUADS, 256, RenderType.CompositeState.builder()
      .setShaderState(RenderStateShard.RENDERTYPE_OUTLINE_SHADER)
      .setTextureState(new RenderStateShard.TextureStateShard(p_173272_, false, false)).setCullState(p_173273_)
      .setDepthTestState(myShard).setOutputState(RenderStateShard.OUTLINE_TARGET)
      .createCompositeState(RenderType.OutlineProperty.IS_OUTLINE));
});

However, this didn't seem to really have the desired effect, half of them (==, !=, never, >, >=) just remove the glow entirely, except for held items (maybe since they use a different shard), while the other half have no effect at all on the glow.

Am I looking at the completely wrong thing code-wise?

 

Edited by SoLegendary
opengl stuff
Link to comment
Share on other sites

Codewise, it probably needs a lot more than this. I've been thinking about this on and off and I may have been wrong in my initial explanation on how to achieve the desired effect.

In general, here is what needs to happen:

1. The entity is drawn to a separate render target. This is such that you know where the entity is that needs to be drawn without any background noise. Preferably, this would be all one depth so it's drawn either all 0 or 1s.

2. Draw the outline of the render target using an edge detection shader. This will replace the entity and only be drawn to one depth.

2. The rest of the rendering is drawn to the render target, inverting whatever overlays with the entity outline. Anything that doesn't overlay wherever the initial entity is located is discarded. This should isolate the outline which is obscured by other items.

3. Draw the rendering to the screen using the always depth test of choice. In this case, since we expect the outline to be rendered last, we can just render it as is and it will be on the foreground of the drawn image.

Now, the issue with this solution is that it requires a substantial amount of the rendering pipeline to be injected or written to. My original solution was to mess around with the render target, but since it only contains the entity's whose outlines are going to be rendered and is rendered after the rest of the blocks, it may be unlikely to apply a correct outline with its edge detection method.

I may be overcomplicating this and there probably is a simple solution, but this is the best I can think up currently.

 

Link to comment
Share on other sites

  • 7 months later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

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