Jump to content

[solved]EntityFX Movements


N247S

Recommended Posts

Hey,

 

I have been struggling with this problem for a rather long time, and I can't get my hands on it. Bassicly I want to spawn in Particles, who needs to stay at their exact location (exact pixel 0.00 movement!). that would be rather easy right? setting this.motionX to 0! But sadly it aint that easy.

 

there are 4 FXLayers for Particles.

0 - for regular Vanilla particles.

1 - for blockBreaking particles

2 - for effects like thunder, raindrops (not rain particles!) etc.

3 - basicly the rest (e.g. custom particles)

 

For all FXLayers, except Layer 3,  there is an texture bound to it, and the tess. codes are already made for you. But for FXLayer 3, you need to do a lot of the rendering yourself. No problems here! The srange part is that the particles on FXLayer 3 don't stay at their exact location, but they move around when the player moves as well! Also they can't collide with walls(unlike an FXLayer 0 particle)

when I use the same methods on FXLayer 0, it doesn't move. But since the texture is already bound, your texture will either override, or blend with the vanilla particles on FXLayer 0!

so for example, when it rains. there will be bright quads in the place of the usual rain particles!

 

So my question is, how can I make the Particle dont move with the player on FXLayer 3(Since binding to an other FXLayer will cause trouble!)?

 

Thanks in advanced!

N247S

 

current codes

package mechanical_crafting_table.client.particles.entityfx;

import static org.lwjgl.opengl.GL11.*;
import mechanical_crafting_table.Main;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.client.ForgeHooksClient;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

@SideOnly(Side.CLIENT)
public class EntityWellFlashFX extends EntityFX
{
private static final ResourceLocation WellingFXTexture = new ResourceLocation(Main.MODID, "textures/particles/WellingFlash.png");

public EntityWellFlashFX(World world, double x, double y, double z)
{
	super(world, x, y, z);
	this.particleScale = 5.0F;
	this.particleMaxAge = 2;
	this.particleGravity = 1F;
	this.particleAlpha = 1/255F;
	this.noClip = false;
}

@Override
 public void renderParticle(Tessellator tess, float particleTicks, float x, float y, float z, float u, float v)
 {
	if(this.particleAge < this.particleMaxAge)
	{
		Minecraft.getMinecraft().renderEngine.bindTexture(WellingFXTexture);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		tess.startDrawingQuads();
		float f10 = 0.1F * this.particleScale;
		float f11 = (float)(this.prevPosX + (this.posX - this.prevPosX) * particleTicks - interpPosX);
        	float f12 = (float)(this.prevPosY + (this.posY - this.prevPosY) * particleTicks - interpPosY);
        	float f13 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * particleTicks - interpPosZ);
        
        	tess.setBrightness(getBrightnessForRender(1));
                        tess.addVertexWithUV((double)(f11 - x * f10 - u * f10), (double)(f12 - y * f10), (double)(f13 - z * f10 - v * f10), 0, 0);
       		tess.addVertexWithUV((double)(f11 - x * f10 + u * f10), (double)(f12 + y * f10), (double)(f13 - z * f10 + v * f10), 0, 1);
        	tess.addVertexWithUV((double)(f11 + x * f10 + u * f10), (double)(f12 + y * f10), (double)(f13 + z * f10 + v * f10), 1, 1);
        	tess.addVertexWithUV((double)(f11 + x * f10 - u * f10), (double)(f12 - y * f10), (double)(f13 + z * f10 - v * f10), 1, 0);
        	tess.draw();

		glDisable(GL_BLEND);
	}
}

public void onUpdate()
{
	this.prevPosX = this.posX;
	this.prevPosY = this.posY;
	this.prevPosZ = this.posZ;

	if (this.particleAge++ >= this.particleMaxAge)
	{
		this.setDead();
	}

	if (this.particleAge > this.particleMaxAge)
	{
		this.setAlphaF(this.particleAlpha / 2);
	}

	this.moveEntity(this.motionX, this.motionY, this.motionZ);
	this.motionX *= 0.0D;
	this.motionY *= 0.0D;
	this.motionZ *= 0.0D;
}

public int getBrightnessForRender(float brightnessFR)
{
	return 15728880/2;
}

public float getBrightness(float brightness)
{
	return 1.0F;
}
    
    public int getFXLayer()
    {
        return 3;
    }
}

Projects:

Discontinued:

- N2ConfigAPI

- Meachanical Crafting Table

 

Latest:

- CollectionUtils

 

Coöperations:

- InGameConfigManager

Link to comment
Share on other sites

As far as I can see, your code looks pretty good. The EntityFX methods are not well documented, so I'm not sure how you figured out what the layers mean exactly -- it wasn't as clear to me, but I agree your list looks probably. The number 3 seems to be the layer rendered with the renderLitParticles() method. 0 and 1 are rendered in the renderParticles() method with 0 binding the particleTextures (vanilla particles) and 1 binding the texture map for blocks.

 

Okay, so that's just to say I think you're correct about layer 3 being the one you want to use.

 

The code in the renderWorld() method that calls both renderLitParticles() and renderParticles() looks like this:

 

        if (!this.debugView)

        {

            this.enableLightmap();

            this.mc.mcProfiler.endStartSection("litParticles");

            effectrenderer.renderLitParticles(entity, partialTicks);

            RenderHelper.disableStandardItemLighting();

            this.setupFog(0, partialTicks);

            this.mc.mcProfiler.endStartSection("particles");

            effectrenderer.renderParticles(entity, partialTicks);

            this.disableLightmap();

        }

 

 

 

Which shows they are called close together and without any translation or movement between them.

 

However, there is one area I'm suspicious about. The renderParticles() method itself includes some updates to the interpPosX, interpPosY, interpPosZ, whereas the renderLitParticles() does not. I'm not sure what the significance of that is, as I think the positions are still calculated separately in the renderParticle() method called by both methods.

 

Anyway, I think you need to go back to debugging basics -- trace your code to see what the entity position is at the time it is being rendered. Put your IDE into debug mode and trace the behavior through the rendering.

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

Link to comment
Share on other sites

Thanks for the reply!

 

Yea I did some good research before posting here (again). And the only differencs I can find is the additional Entity data what renderParticle() is using in compairison to renderLitParticle(). Though I can't find any important info, nor an way to prevent the movements from happening.

 

The problem with debugging is, that there is only movement when the player is moving. Rather difficult to  debug ;). And debug messages isnt that handy either, since there is about 12 differnt positions for the EntityFX. So, whats the best solution for this?

Projects:

Discontinued:

- N2ConfigAPI

- Meachanical Crafting Table

 

Latest:

- CollectionUtils

 

Coöperations:

- InGameConfigManager

Link to comment
Share on other sites

Hi

 

I think your best bet is the

System.out.println("renderParticle:" + this + " at [" + x + ", " + y + ", " + z + "]");

in the renderParticle method

and the same for f11, f12, f13, interpX etc

 

That should show you pretty quickly what is happening and where to look next.

 

-TGG

Link to comment
Share on other sites

Hey, thanks for your reply

 

Luckly I know how to debug :D, but because I was in a hurry I didnt explain the real problem verry well. my apologize for that!

 

The problem is that an interpretation is rather hard, if not impossible to do. So to break this down for you I will explain what results I got.

One big note, for all the coords (X, Y, Z) are the results simular!

 

The following CoordsTypes are used by the EntityFX, but only a few of them are changing when the particle is NOT moving. I tried to find a correct word for it, though since my foreign language isn't English, I tried the best option for me. (correct me if you wish :P)

 

Dynamic = changing when the player is moving

nonDynamic = oposite

 

posX          = nonDynamic

prevPosX       = nonDynamic

interpPosX      = Dynamic (offset with a max offset 1.0D)

particleTicks    = Dynamic (offset with a max offset 1.0F)

lastTickPosX  = nonDynamic

motionX          = nonDynamic

 

these results seems logical if you look at it this way:

 

posX = actual position of the particle (absolute Coord. Although I put in a int, and I got an random but static offset lower than 0.1!)

prevPosX = lastTickPosX = posX from previous Tick

motionX = 0 (no motion set...)

 

the only 2 left are:

interpPosX = the exact player Position

particleTicks =  something I realy can't get my fingers behind.

 

 

so my actual calculation of the position for the UV was this:

(this.prevPosX + (this.posX - this.prevPosX) * particleTicks - interpPosX)

 

The Bold part of this formula will always be 0, since this.posX = this.prevPosX. So my new formula is:

(this.prevPosX - interpPosX)

 

which is simply explained the relative coordinate of the particle to the Player. But why gives it different outcomes on the different FXLayers?!?

What I found in the renderer.Class is the following lines:

        float f1 = ActiveRenderInfo.rotationX;
        float f2 = ActiveRenderInfo.rotationZ;
        float f3 = ActiveRenderInfo.rotationYZ;
        float f4 = ActiveRenderInfo.rotationXY;
        float f5 = ActiveRenderInfo.rotationXZ;

       entityfx.renderParticle(tessellator, p_78874_2_, f1, f5, f2, f3, f4);

 

This are the 5 parameters (with tesselator and particleTicks) for the renderParticle() methode inside an EntityFX.Class!

Note that on FXLayer 3 there are 2 methods form the renderer.Class that are Calling the renderParticle() methode, renderParticles() and renderLitParticles()

 

The parameters of the renderLitParticles() method look like this:

        float f1 = 0.017453292F;
        float f2 = MathHelper.cos(p_78872_1_.rotationYaw * 0.017453292F);
        float f3 = MathHelper.sin(p_78872_1_.rotationYaw * 0.017453292F);
        float f4 = -f3 * MathHelper.sin(p_78872_1_.rotationPitch * 0.017453292F);
        float f5 = f2 * MathHelper.sin(p_78872_1_.rotationPitch * 0.017453292F);
        float f6 = MathHelper.cos(p_78872_1_.rotationPitch * 0.017453292F);

        entityfx.renderParticle(tessellator, p_78872_2_, f2, f6, f3, f4, f5);

 

So from what I can see, the only difference is that on FXLayer 3, there are 2 separate Calls (relativily close after each other, following jabelar) from which the real difference is that there is an rotation being set.(why not on FXLayer 0-2?)

 

So again my question, does anybody know's what is going on here, or how I could encounter this?

 

@Jabelar

I got the FXLayers a bit wrong. FXLayer 2 is for Items? What I typed first is what I recalled from what I read a long time ago. Where I got it from?, the Renderer.Class :D:

       return i == 0 ? "MISC_TEXTURE" : (i == 1 ? "TERRAIN_TEXTURE" : (i == 2 ? "ITEM_TEXTURE" : (i == 3 ? "ENTITY_PARTICLE_TEXTURE" : "Unknown - " + i)));

 

notice that the FXLayer3 is officialy for Entity Particle Textures, but the CritHit particle, and the villagerParticles etc. are all on FXLayer 0 for some reason.

 

Projects:

Discontinued:

- N2ConfigAPI

- Meachanical Crafting Table

 

Latest:

- CollectionUtils

 

Coöperations:

- InGameConfigManager

Link to comment
Share on other sites

You're digging into it as well as I could.

 

In case you didn't know, the 0.017453292F is just for the conversion between degrees and radians (pi / 180 = 0.017453292).

 

The trigonometry in the second case looks pretty equivalent to the first case. The cosine of the yaw gives the "rotationX", the sine of the yaw gives the "rotationZ", etc.

 

When you run the debugger, can you watch the values of the f1, f2, etc. to see if they make sense when used by the render method?

 

 

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

Link to comment
Share on other sites

Hi

 

Just a quick comment, will look more later:

 

partialTicks (not particleTicks) is used to smooth out animations between ticks

 

i.e. a tick happens every 50 microseconds (20 times/second), but if you have a reasonably fast machine, you can render frames much more frequently than that.  partialTicks is fractions of a tick.

 

So for example, if my rendering routine is running at 80 frames per second, that is four calls per tick, so your renderer will see:

 

tickCount = 0, partialTicks = 0

tickCount = 0, partialTicks = 0.25

tickCount = 0, partialTicks = 0.5

tickCount = 0, partialTicks = 0.75

tickCount = 1, partialTicks = 0

etc

 

partialTicks is used to smooth out the animations by linearly interpolating between (say) the X value at the previous tick and the X value at the current tick.

 

-TGG

 

 

Link to comment
Share on other sites

Both Thank you verry much for your replies.

 

@TGG

That explanation makes a lot more sense to me indeed :D. I got the other name from an outdated (but one of the few good) tutorials. He explained it as a distance expressed in a certain travel time ?? Anyway I didn't got one bit of it, and it doesn't make sense while the value is changing even when the Player isn't moving, so thank you verry much for that one :D.

 

@jabelar

I tried to debug it before, but its only passing values round 1.0 and lower. Actualy only rotations in radians. Thats why this all doesn't make any sense to me whatsoever. Why would there be 2 separate calls for one Particle.(both for rotation), but more important, why is there a difference in position while the rotation is the only difference between these 2?

 

 

A suggestion

I looked at the activeRenderInfo, and it seems that is a place where the position and rotation of the player is stored. which means that there might be a discrepancy between the first, and second call of the renderParticle() method.

While the Values of the rendering is set according the Player's position and rotation form the ActiveRenderInfo inside the renderParticles(), it is using the position and rotation of an entitylivingbase (checked as EntityPlayer) inside the renderLitParticles(). which may explain an slight offset, but that shouldn't be vissible since rendering happens way more often than a tickloop(Following TGG).

 

So that leaves me again with the question unfortunatly.

Projects:

Discontinued:

- N2ConfigAPI

- Meachanical Crafting Table

 

Latest:

- CollectionUtils

 

Coöperations:

- InGameConfigManager

Link to comment
Share on other sites

I trying (again) to find a way around this problem, and I found something which might lead to a solution

 

The way I calculate the renderPos is as follows

this.prevPosX - interpPosX

 

Basicly this is calculating the offset relative to the Player. Though if the interpPosX isn't correct, that would cause an offset (visible on FXLayer 3)

That being said, there is no other position from the renderer Class which refference the playerCoordinates. So I think the problem would be solved if there is a way to get the actual/better playerPos. Though I have no idea what the best way ,to get the exact player position, is.(especialy because the method is likely called more than once a tick)

 

And appart from this, why would there be such a huge difference between the 2 method calls?

Projects:

Discontinued:

- N2ConfigAPI

- Meachanical Crafting Table

 

Latest:

- CollectionUtils

 

Coöperations:

- InGameConfigManager

Link to comment
Share on other sites

Oke, after some busy days I tried to use other playerdata, like this:

Entity player = Minecraft.getMinecraft().thePlayer;

 this.interpPosX = player.lastTickPosX + (player.posX - player.lastTickPosX) * (double)partialTicks;
 this.interpPosY = player.lastTickPosY + (player.posY - player.lastTickPosY) * (double)partialTicks;
 this.interpPosZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * (double)partialTicks;

 

And it works!

 

But it feels dirty to me. So if anyone has a better suggestion, feel free to post it :D.

Projects:

Discontinued:

- N2ConfigAPI

- Meachanical Crafting Table

 

Latest:

- CollectionUtils

 

Coöperations:

- InGameConfigManager

Link to comment
Share on other sites

Hi

 

After fiddling with EntityFX for a couple of days, I think you might be better putting your EntityFX onto layer 1, and adding your WellingFXTexture to the texture map using

TextureStitchEvent.Pre

 

eg

  public static void preInitClientProxyOnly()
  {
    MinecraftForge.EVENT_BUS.register(new TextureStitcherBreathFX());
  }

public class TextureStitcherBreathFX
{
  @SubscribeEvent
  public void stitcherEventPre(TextureStitchEvent.Pre event) {
    ResourceLocation flameRL = new ResourceLocation("minecraftbyexample:entity/flame_fx");
    event.map.registerSprite(flameRL);
  }
}

and
    public FlameFX(World world, double x, double y, double z, double a, double b, double c, float size, int age) {
      super(world, x, y, z, a, b, c);
      // set the texture to the flame texture, which we have previously added using TextureStitchEvent
      TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("minecraftbyexample:entity/flame_fx");
      func_180435_a(sprite);

    @Override
    public int getFXLayer() {
        return 1;
    }

 

-TGG

Link to comment
Share on other sites

I solved it through (re)setting the interpPos which is working perfectly fine.

But this is indeed a second option, though have you tried it already? Because I have my doubts about this method.

 

First of all the texture map is one single texture(FXLayer 0), not a map unfortunatlly. Second, using the FXLayer 1 will apply a colourFilter(brown) over your texture, which kinda messes tings up. (FXLayer 1 is used for blockBreak particles, therefore it uses a colour filter to make a contrast with the block)

 

Anyway, many thanks for thinking with me, and for the time you spend on testing of course! I mentioned before that I would like to create a tutorial/wiki of the particle (for the tuts. you were setting up) if I could figure out one thing. Which is this :D. So it on its way!

 

Again, many thanks!(both)

Projects:

Discontinued:

- N2ConfigAPI

- Meachanical Crafting Table

 

Latest:

- CollectionUtils

 

Coöperations:

- InGameConfigManager

Link to comment
Share on other sites

Hi

 

Yeah I tried it just the other day (in 1.8), seemed to work fine - my particle whites were still white.  FXLayer 1 only seems to affect which texture is bound (i.e. the block texture for layer 1).  Any colour filtering you're seeing might be happening in the EntityDiggingFX or similar?  Or alternatively, because world lighting is being applied?  If you don't want that to happen, your EntityFX must override    public int getBrightnessForRender(float p_70070_1_)

 

Keen looking forward to your tutorial :)

 

-TGG

 

 

 

 

 

Link to comment
Share on other sites

I re-tested it, and you are right. though there is some strange behavior I can't explain.

 

first, the particle Alpha gets ignored when its brightness isn't 0 or 15728880(max). instead of blending in and addapting the alpha, it will just overrule the bound texture...

 

second, I made a copy of the tessellator class, and modified it so it was capable to render triangles instead. everything works fine, till the brightness gets messed upp. (I don't think its completly onto this topic, though it fits with the wierd behaviour)

 

To clarify I've posted an link to an image on the bottom of this post. what you see is an grey model rendered through a tileEntity renderer class.(cutted out the unnesecery parts, Left is by night, Right is by day) all of it has the same texture bound to it, and yet you still se a difference. but only when the block is facing north or south! In this case I didnt pass through any light value, if I did it would make matters even worse.

 

image example: http://imgur.com/kU5wZoy;

codes: Traingle tess. + model

Projects:

Discontinued:

- N2ConfigAPI

- Meachanical Crafting Table

 

Latest:

- CollectionUtils

 

Coöperations:

- InGameConfigManager

Link to comment
Share on other sites

I re-tested it, and you are right. though there is some strange behavior I can't explain.

 

first, the particle Alpha gets ignored when its brightness isn't 0 or 15728880(max). instead of blending in and addapting the alpha, it will just overrule the bound texture...

 

second, I made a copy of the tessellator class, and modified it so it was capable to render triangles instead. everything works fine, till the brightness gets messed upp. (I don't think its completly onto this topic, though it fits with the wierd behaviour)

 

To clarify I've posted an link to an image on the bottom of this post. what you see is an grey model rendered through a tileEntity renderer class.(cutted out the unnesecery parts, Left is by night, Right is by day) all of it has the same texture bound to it, and yet you still se a difference. but only when the block is facing north or south! In this case I didnt pass through any light value, if I did it would make matters even worse.

 

image example: http://imgur.com/kU5wZoy;

codes: Traingle tess. + model

That's odd.  I don't get that alpha behaviour.

 

I don't think you need to modify the Tessellator to draw triangles.  Just use .startDrawing(GL11.GL_TRIANGLES) instead of .startDrawingQuads();  Then add points in groups of three instead of groups of four.

 

It sounds like you need to set up the lighting properly before rendering.  This link has a bit of info.  http://greyminecraftcoder.blogspot.com.au/2014/12/lighting-18.html

You generally need to properly set the lighting on/off, the multitexturing "mixedBrightness" (blocklight/skylight), and sometimes also the render colour depending on how you're doing the rendering.

 

This class might also help with some ideas:

https://github.com/TheGreyGhost/MinecraftByExample/blob/master/src/main/java/minecraftbyexample/mbe21_tileentityspecialrenderer/TileEntitySpecialRendererMBE21.java

 

-TGG

 

 

 

 

 

Link to comment
Share on other sites

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.