Jump to content

[SOLVED] [1.12.2] Replacing weather renderer, raining blood!


Recommended Posts

Posted (edited)

I've been fiddling around with seasons and weather stuff, and I'm trying to change when precipitation is rendered as rain vs. snow. I don't want it to be controlled solely by biome temperature. After a bit of research, it seemed like creating my own weather renderer might be the thing to do, so I can sidestep the way vanilla relies on biome temperature to decide whether to render rain or snow. I created a class that extends IRenderHandler and just copied the vanilla code for EntityRenderer#renderRainSnow. However, the vanilla code contains a reference to a private variable called rendererUpdateCount. I don't really understand what the variable does—any insight into that would be appreciated. In vanilla, it gets updated in EntityRenderer#updateRenderer, and I assume I would need to use that value as it gets updated. Or can I, like, create my own variable and update it somehow...?

Edited by Daeruin
Updated title to reflect new problem
Posted

I think that field is being used to help animate the motion of the rain/snow.

 

It is your class so you can just make your own field with the same name. But you'll also need to update it similarly so you'll need something like the updateRenderer() method.

 

Also, note that there is also an addRainParticles() method you probably need to implement as well.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)

I created a rendererUpdateCount field in my ClientTickEvent and update it once a tick. That seemed to be the right thing to do, since the original gets updated during Minecraft#runTick. (I didn't bother with addRainParticles() since it's already called from EntityRenderer#updateRenderer.) I'm not getting any crashes or errors. However, when it rains and snows the particles are red, like it's raining blood.

 

I'm guessing this is a problem with renderUpdateCount not being the right value. At first I thought it was a problem with the texture, but after fiddling with that for a while I couldn't fix it. I also tried implementing addRainParticles()  in my ClientTickEvent, but it didn't seem to do anything.

 

Here's my IRenderHandler code, if it helps:

 

Spoiler

public class PrimalWeatherRenderer extends IRenderHandler
{

    private final Random random = new Random();
    private final float[] rainXCoords = new float[1024];
    private final float[] rainYCoords = new float[1024];
    private static final ResourceLocation RAIN_TEXTURES = new ResourceLocation("textures/environment/rain.png");
    private static final ResourceLocation SNOW_TEXTURES = new ResourceLocation("textures/environment/snow.png");

    public PrimalWeatherRenderer()
    {
        for (int i = 0; i < 32; ++i)
        {
            for (int j = 0; j < 32; ++j)
            {
                float f = (float)(j - 16);
                float f1 = (float)(i - 16);
                float f2 = MathHelper.sqrt(f * f + f1 * f1);
                this.rainXCoords[i << 5 | j] = -f1 / f2;
                this.rainYCoords[i << 5 | j] = f / f2;
            }
        }
    }

    @Override
    public void render(float partialTicks, WorldClient world, Minecraft minecraft)
    {
        float f = minecraft.world.getRainStrength(partialTicks);

        if (f > 0.0F)
        {
            this.enableLightmap(minecraft);
            Entity entity = minecraft.getRenderViewEntity();
            assert entity != null;
            int i = MathHelper.floor(entity.posX);
            int j = MathHelper.floor(entity.posY);
            int k = MathHelper.floor(entity.posZ);
            Tessellator tessellator = Tessellator.getInstance();
            BufferBuilder bufferbuilder = tessellator.getBuffer();
            GlStateManager.disableCull();
            GlStateManager.glNormal3f(0.0F, 1.0F, 0.0F);
            GlStateManager.enableBlend();
            GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
            GlStateManager.alphaFunc(516, 0.1F);
            double d0 = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * (double)partialTicks;
            double d1 = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * (double)partialTicks;
            double d2 = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * (double)partialTicks;
            int l = MathHelper.floor(d1);
            int i1 = 5;

            if (minecraft.gameSettings.fancyGraphics)
            {
                i1 = 10;
            }

            int j1 = -1;
            float f1 = (float)PrimalClientTickEvent.rendererUpdateCount + partialTicks;
            bufferbuilder.setTranslation(-d0, -d1, -d2);
            GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
            BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();

            for (int k1 = k - i1; k1 <= k + i1; ++k1)
            {
                for (int l1 = i - i1; l1 <= i + i1; ++l1)
                {
                    int i2 = (k1 - k + 16) * 32 + l1 - i + 16;
                    double d3 = (double)this.rainXCoords[i2] * 0.5D;
                    double d4 = (double)this.rainYCoords[i2] * 0.5D;
                    blockpos$mutableblockpos.setPos(l1, 0, k1);
                    Biome biome = world.getBiome(blockpos$mutableblockpos);

                    if (biome.canRain() || biome.getEnableSnow())
                    {
                        int j2 = world.getPrecipitationHeight(blockpos$mutableblockpos).getY();
                        int k2 = j - i1;
                        int l2 = j + i1;

                        if (k2 < j2)
                        {
                            k2 = j2;
                        }

                        if (l2 < j2)
                        {
                            l2 = j2;
                        }

                        int i3 = j2;

                        if (j2 < l)
                        {
                            i3 = l;
                        }

                        if (k2 != l2)
                        {
                            this.random.setSeed((long)(l1 * l1 * 3121 + l1 * 45238971 ^ k1 * k1 * 418711 + k1 * 13761));
                            blockpos$mutableblockpos.setPos(l1, k2, k1);
                            float f2 = biome.getTemperature(blockpos$mutableblockpos);

                            if (world.getBiomeProvider().getTemperatureAtHeight(f2, j2) >= 0.15F)
                            {
                                if (j1 != 0)
                                {
                                    if (j1 >= 0)
                                    {
                                        tessellator.draw();
                                    }

                                    j1 = 0;
                                    minecraft.getTextureManager().bindTexture(RAIN_TEXTURES);
                                    bufferbuilder.begin(7, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP);
                                }

                                double d5 = -((double)(PrimalClientTickEvent.rendererUpdateCount + l1 * l1 * 3121 + l1 * 45238971 + k1 * k1 * 418711 + k1 * 13761 & 31) + (double)partialTicks) / 32.0D * (3.0D + this.random.nextDouble());
                                double d6 = (double)((float)l1 + 0.5F) - entity.posX;
                                double d7 = (double)((float)k1 + 0.5F) - entity.posZ;
                                float f3 = MathHelper.sqrt(d6 * d6 + d7 * d7) / (float)i1;
                                float f4 = ((1.0F - f3 * f3) * 0.5F + 0.5F) * f;
                                blockpos$mutableblockpos.setPos(l1, i3, k1);
                                int j3 = world.getCombinedLight(blockpos$mutableblockpos, 0);
                                int k3 = j3 >> 16 & 65535;
                                int l3 = j3 & 65535;
                                bufferbuilder.pos((double)l1 - d3 + 0.5D, (double)l2, (double)k1 - d4 + 0.5D).tex(0.0D, (double)k2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                                bufferbuilder.pos((double)l1 + d3 + 0.5D, (double)l2, (double)k1 + d4 + 0.5D).tex(1.0D, (double)k2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                                bufferbuilder.pos((double)l1 + d3 + 0.5D, (double)k2, (double)k1 + d4 + 0.5D).tex(1.0D, (double)l2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                                bufferbuilder.pos((double)l1 - d3 + 0.5D, (double)k2, (double)k1 - d4 + 0.5D).tex(0.0D, (double)l2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                            }
                            else
                            {
                                if (j1 != 1)
                                {
                                    if (j1 >= 0)
                                    {
                                        tessellator.draw();
                                    }

                                    j1 = 1;
                                    minecraft.getTextureManager().bindTexture(SNOW_TEXTURES);
                                    bufferbuilder.begin(7, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP);
                                }

                                double d8 = (double)(-((float)(PrimalClientTickEvent.rendererUpdateCount & 511) + partialTicks) / 512.0F);
                                double d9 = this.random.nextDouble() + (double)f1 * 0.01D * (double)((float)this.random.nextGaussian());
                                double d10 = this.random.nextDouble() + (double)(f1 * (float)this.random.nextGaussian()) * 0.001D;
                                double d11 = (double)((float)l1 + 0.5F) - entity.posX;
                                double d12 = (double)((float)k1 + 0.5F) - entity.posZ;
                                float f6 = MathHelper.sqrt(d11 * d11 + d12 * d12) / (float)i1;
                                float f5 = ((1.0F - f6 * f6) * 0.3F + 0.5F) * f;
                                blockpos$mutableblockpos.setPos(l1, i3, k1);
                                int i4 = (world.getCombinedLight(blockpos$mutableblockpos, 0) * 3 + 15728880) / 4;
                                int j4 = i4 >> 16 & 65535;
                                int k4 = i4 & 65535;
                                bufferbuilder.pos((double)l1 - d3 + 0.5D, (double)l2, (double)k1 - d4 + 0.5D).tex(0.0D + d9, (double)k2 * 0.25D + d8 + d10).color(1.0F, 1.0F, 1.0F, f5).lightmap(j4, k4).endVertex();
                                bufferbuilder.pos((double)l1 + d3 + 0.5D, (double)l2, (double)k1 + d4 + 0.5D).tex(1.0D + d9, (double)k2 * 0.25D + d8 + d10).color(1.0F, 1.0F, 1.0F, f5).lightmap(j4, k4).endVertex();
                                bufferbuilder.pos((double)l1 + d3 + 0.5D, (double)k2, (double)k1 + d4 + 0.5D).tex(1.0D + d9, (double)l2 * 0.25D + d8 + d10).color(1.0F, 1.0F, 1.0F, f5).lightmap(j4, k4).endVertex();
                                bufferbuilder.pos((double)l1 - d3 + 0.5D, (double)k2, (double)k1 - d4 + 0.5D).tex(0.0D + d9, (double)l2 * 0.25D + d8 + d10).color(1.0F, 1.0F, 1.0F, f5).lightmap(j4, k4).endVertex();
                            }
                        }
                    }
                }
            }

            if (j1 >= 0)
            {
                tessellator.draw();
            }

            bufferbuilder.setTranslation(0.0D, 0.0D, 0.0D);
            GlStateManager.enableCull();
            GlStateManager.disableBlend();
            GlStateManager.alphaFunc(516, 0.1F);
            this.disableLightmap();
        }
    }

    private void enableLightmap(Minecraft minecraft)
    {
        GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
        GlStateManager.matrixMode(5890);
        GlStateManager.loadIdentity();
        // float f = 0.00390625F;
        GlStateManager.scale(0.00390625F, 0.00390625F, 0.00390625F);
        GlStateManager.translate(8.0F, 8.0F, 8.0F);
        GlStateManager.matrixMode(5888);
        final ResourceLocation locationLightMap = minecraft.getTextureManager().getDynamicTextureLocation("lightMap", new DynamicTexture(16, 16));
        minecraft.getTextureManager().bindTexture(locationLightMap);
        GlStateManager.glTexParameteri(3553, 10241, 9729);
        GlStateManager.glTexParameteri(3553, 10240, 9729);
        GlStateManager.glTexParameteri(3553, 10242, 10496);
        GlStateManager.glTexParameteri(3553, 10243, 10496);
        GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
        GlStateManager.enableTexture2D();
        GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
    }

    private void disableLightmap()
    {
        GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
        GlStateManager.disableTexture2D();
        GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
    }

}

 

 

snow particles.png

Edited by Daeruin
Posted

By playing around with the color values on the lines that look like this:

 

bufferbuilder.pos((double) l1 - d3 + 0.5D, (double) l2, (double) k1 - d4 + 0.5D).tex(0.0D, (double) k2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, 

 

I have gotten the color to change to dark red and black. Which makes me reasonably sure these lines are not the issue. I've gone back to the theory that it's some kind of texture error. Like, it can't find the textures or something. I had originally left the texture fields the same as they are in vanilla:

 

private static final ResourceLocation SNOW_TEXTURES = new ResourceLocation("textures/environment/snow.png");

 

I then tried copying the PNG files into my mod's texture folder and adding my own mod id, but that didn't work. I double checked the spelling on the folders and file names.

 

private static final ResourceLocation SNOW_TEXTURES = new ResourceLocation("primalcraft:textures/environment/snow.png");

 

Any other ideas what's going on here? I don't WANT to muck around with particles and renderers. I just want to make snow appear at reasonable times.

Posted

That's pretty cool actually. One thing about red is that it is a primary display color so makes me think that somewhere that it should be white FFFFFF is somehow FF0000 through shifting or something. But I can't see anything there.

 

I don't think it is a problem with finding the texture since the shapes of the snowflakes are correct.

 

As far as I can think, it can be a blending issue (maybe even blending from before the renderer is called if the GLState has something left over, so look at that GL stuff at the top. Secondly, it could be direct color methods but your color() methods seem to be white. Lastly it could maybe be a lighting issue, although I'm not aware of lighting changing color, but you could look at how it get lighting.

 

I'm most suspicious that the GLState is somehow blending red due to something left over in the state. However, the state is explicitly set to white with the GLStateManager.color() method call, so it is very curious as to how you're getting red. I do feel that it has something to do with blending though. Did you try to disable the blending? You can use GLStateManager.disableBlend() early on in your code (probably right after the enable call). Don't just comment out the enable call because it can possibly already be enabled and you need to make sure it is disabled.

 

One other thing for debug, when I copy code with a lot of fields with obfuscated names like j1, f3, and such, I like to go through and figure out what they do and refactor the name to something meaningful. You might find a clue as you do that.

  • Like 1

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted (edited)

Thank you so much for your help! I was starting to despair. I'm totally new to this rendering stuff and have very little idea what most of the code does. I've been trying to figure it out, but it's quite a learning curve for what I thought was going to be something simple.

 

I tried disabling blending, but there was no change.

 

I then commented out the line where the light map is enabled (enableLightmap), and like magic the rain turned blue.

 

Which makes me wonder what I'm getting out of it. Why use that method at all? I did have to replicate the light map code, because I couldn't refer to the vanilla method statically. The only thing I had to change was the reference to the lightMap texture, since the variable was private, which also forced me to create a new DynamicTexture for the light map. I've never heard of dynamic textures before, but it appears to get updated in updateLightMap(), which only seems to be used when updateTorchFlicker() sets lightmapUpdateNeeded to true. So I'm not sure why that would affect what I'm doing. Unless I need to refer to the exact DynamicTexture created in EntityRenderer?

 

I have been slowly working on refactoring the variable names, but some of the code is pretty obscure. For example, I think I have the variable names used in this line of code figured out:

 

double d5 = -((double) (PrimalClientTickEvent.rendererUpdateCount + xDistFromEntity * xDistFromEntity * 3121 + xDistFromEntity * 45238971 + zDistFromEntity * zDistFromEntity * 418711 + zDistFromEntity * 13761 & 31) + (double) partialTicks) / 32.0D * (3.0D + this.random.nextDouble());

 

But I have no idea what the math is really doing. Based on where d5 is used—in a BufferBuilder.tex() call—I think it's something to find the right part of the texture to render? But the math itself is very obscure, and I'm mostly guessing on the purpose of tex() so I don't really know what to change d5 to.

Edited by Daeruin
Posted

Sorry I don't know much about the lighting or texture buffers. I do suspect you ran into trouble when you couldn't reference the static lightmap -- I have a feeling you can't just create your own instance since I expect it contains information from a bunch of previous lighting calculations.

 

In terms of refactoring all the fields, I agree sometimes it is almost "impossible". In particular when they are randomizing in things like world generators it takes a lot of investigation to figure out why they're doing things. So don't worry about refactoring everything, but I just suggest always refactoring what you can as then you will understand more and it becomes more properly "your" code.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Well, I'm going to mark this one solved for now. Hopefully it doesn't cause trouble in the future to go without the light map enabled.

 

Thanks again for your help. I probably wouldn't have stumbled upon the answer to this one without you.

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.

Announcements



×
×
  • Create New...

Important Information

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