Jump to content

[SOLVED] 1.7.2 Models and Rendering mob creation


Recommended Posts

So, before the inevitable RTFM comments, I have been through google and read some out of date tutorials. This one http://www.minecraftforum.net/topic/250780-creating-mods-mob-making-modelling-08042011/ was particularly good but it is over three years old so obviously it is a bit out of date and the code it generates needs updating to the 1.7.2 specs.

 

Also, following that thread, I've successfully used Techne to create a model and export both the java code and the .png file. And Novaskin to make it look pretty. As I'm making a new quadruped I'm basing it on Cow and all its associated classes, ModelCow and RenderCow. I *can* just about figure it out by comparing my out of date code to those in the Cow classes, but the Javadocs and the API are woefully short on detail as to what all the parameters do in things like the addbox and rotationangle methods. And I haven't even got onto the structure of the assets package and how to point it at the right png file.

 

Are there any decent 1.7.2 modelling tutorials out there? (Yes, I will write my own when I get to the end, if for no other reason than to remind myself how I did it!) Or, are there any modders out there who'd be willing to point me in the right direction?

 

Thanks

 

Graham

Link to comment
Share on other sites

So... I saw some video tutorials and based on that I had a shot at MCreator.

 

Unfortunately

 

a) It didn't animate the new mob so it glided around like a demented four-legged Dalek

b) I could only get the compiled files out, not the java classes so I couldn't use it as a basis for my code

c) I could only make it work under Windows which means I have to fight my Ubuntu laptop and queue up for the family Windows PC

 

Back to code crunching tomorrow I think!

 

Graham

Link to comment
Share on other sites

This is something I've just gone through learning, and I am proud to say that I've got a fully animated slithering snake, and an elephant with flapping ears and articulated trunk.  I am planning to write a tutorial soon.  But here are a few tips that might help.

 

First of all I found that using the Java exported directly from Techne was not a good idea.  I use Techne to visualize the model and animation, and especially use it for figuring out texture map, but ultimately I ended up coding the Java myself.  And that is pretty simple because it is simply a bunch of boxes.  Actually the biggest benefit of coding it manually is that you get a good understanding of how the rotation points and offsets really work.

 

Here are some ideas to think about:

 

1) your whole model will only be manageable if you orient it the right way -- I spent a lot of time on one model which had head pointed 90 degrees to what Minecraft considers the front and while it could be fixed with some overall rotation it is much better to simply orient it correctly in the first place.  You can check the ModelCow in Techne to ensure you have the right axis orientation.

 

2) get your rotation point in proper place first, then figure out your offset.  The rotation point should be the joint for something like an arm, and should be the center for something like a body.  In particular, make sure each joint is working properly before adding the next part.  I have found that implementing some simple debug functions for spinning a part are immensely useful to help visualize that you have the rotation point and offsets correct.

 

3) use a hierarchical model by associating blocks with the addChild() method.  For examples, the ears and nose should be children of the head.  Then when the head rotates they stay in proper place, and then the animations of the ears and nose can be programmed relatively (much easier to think about than using spatial transformation).

 

4) It is extremely useful to use the entity's tickExisted property to help control the cycles through an animation loop.  I used the modulo (also called remainder function) to detect "every X ticks".  For example, parEntity.ticksExisted%60==0 will be true for one tick every 3 seconds (there are 20 ticks per second).  Even better, something like parEntity.ticksExisted%6 will work as an index through a six-step animation sequence.

 

5) don't be afraid to "hard code" an animation loop.  Just like a cartoon artist, you only need a few set postions to give the illusion of motion.  For example, for my snake I spent days trying to figure out a mathematical equation to control the slithering and then realized that with a very simple matrix of preset rotations I could achieve the same effect.

 

6) you may need to add public variables to your entities to control animations, in which case you need to ensure there are packets sent to client side (where rendering takes place) to control the animation.

 

7) a really important thing is that the default 0, 0, 0 position of an added box is on one corner, not in the center of the box.  This means you will almost always want to offset by half the dimension of the sides for two (if you're rotating from an end) or three (if you're rotating around the middle) of the sides.

 

8.) don't worry about the texture until you get the model correct.  I suggest working with a texture map that is filled in with a solid color -- then you are sure to see your whole shape, and not get distracted by pieces that are wrongly textured (or worse invisible).

 

9) for entity models, use the F3+B shortcut to show the bounding boxes of your entity.  It is really important to check that the actual bounding box is positioned correctly within the model.

 

Okay, here is my example model for the EntitySerpent:

 

package wildanimals.models;

 

import net.minecraft.client.model.ModelBase;

import net.minecraft.client.model.ModelRenderer;

import net.minecraft.entity.Entity;

 

import org.lwjgl.opengl.GL11;

 

import wildanimals.entities.serpents.EntitySerpent;

import cpw.mods.fml.relauncher.Side;

import cpw.mods.fml.relauncher.SideOnly;

 

@SideOnly(Side.CLIENT)

public class ModelSerpent extends ModelBase

{

    public ModelRenderer head;

    public ModelRenderer tongue;

    public ModelRenderer body1;

    public ModelRenderer body2;

    public ModelRenderer body3;

    public ModelRenderer body4;

    public ModelRenderer body5;

    public ModelRenderer body6;

    public ModelRenderer body7;

    public ModelRenderer body8;

    public ModelRenderer body9;

   

    public int textureWidth = 64;

    public int textureHeight = 32;

 

    // create an animation cycle

    protected int cycleIndex = 0;

    protected static float[][] undulationCycle = new float[][]{

      { 45F, -45F, -45F, 0F, 45F, 45F, 0F, -45F },

      { 0F, 45F, -45F, -45F, 0F, 45F, 45F, 0F },

      { -45F, 90F, 0F, -45F, -45F, 0F, 45F, 45F },

      { -45F, 45F, 45F, 0F, -45F, -45F, 0F, 45F },

      { 0F, -45F, 45F, 45F, 0F, -45F, -45F, 0F },

      { 45F, -90F, 0F, 45F, 45F, 0F, -45F, -45F },

    }

;

   

    protected float field_78145_g = 8.0F;

    protected float field_78151_h = 4.0F;

    // private static final String __OBFID = "CL_00000851";

 

    public ModelSerpent()

    { 

   

    head = new ModelRenderer(this, 0, 0);

    head.addBox(-2.5F, -1F, -5F, 5, 2, 5);

    head.setRotationPoint(0F, 23F, -8F);

    head.setTextureSize(textureWidth, textureHeight);

    setRotation(head, 0F, 0F, 0F);

    tongue = new ModelRenderer(this, 0, 13);

    tongue.addBox(-0.5F, -0.5F, -10F, 1, 1, 5);

    tongue.setRotationPoint(0F, 23F, -8F);

    tongue.setTextureSize(textureWidth, textureHeight);

    setRotation(tongue, 0F, 0F, 0F);

    body1 = new ModelRenderer(this, 20, 20);

    body1.addBox(-1.5F, -1F, -1F, 3, 2, 5);

    body1.setRotationPoint(0F, 23F, -8F);

    body1.setTextureSize(textureWidth, textureHeight);

    setRotation(body1, 0F, 0F, 0F);

    body2 = new ModelRenderer(this, 20, 20);

    body2.addBox(-1.5F, -1F, -1F, 3, 2, 5);

    body2.setRotationPoint(0F, 0F, 4F);

    body2.setTextureSize(textureWidth, textureHeight);

    body1.addChild(body2);

    setRotation(body2, 0F, degToRad(undulationCycle[cycleIndex][0]), 0F);

    body3 = new ModelRenderer(this, 20, 20);

    body3.addBox(-1.5F, -1F, -1F, 3, 2, 5);

    body3.setRotationPoint(0F, 0F, 4F);

    body3.setTextureSize(textureWidth, textureHeight);

    setRotation(body3, 0F, degToRad(undulationCycle[cycleIndex][1]), 0F);

    body2.addChild(body3);

    body4 = new ModelRenderer(this, 20, 20);

    body4.addBox(-1.5F, -1F, -1F, 3, 2, 5);

    body4.setRotationPoint(0F, 0F, 4F);

    body4.setTextureSize(textureWidth, textureHeight);

    setRotation(body4, 0F, degToRad(undulationCycle[cycleIndex][2]), 0F);

    body3.addChild(body4);

    body5 = new ModelRenderer(this, 20, 20);

    body5.addBox(-1.5F, -1F, -1F, 3, 2, 5);

    body5.setRotationPoint(0F, 0F, 4F);

    body5.setTextureSize(textureWidth, textureHeight);

    setRotation(body5, 0F, degToRad(undulationCycle[cycleIndex][3]), 0F);

    body4.addChild(body5);

    body6 = new ModelRenderer(this, 20, 20);

    body6.addBox(-1.5F, -1F, -1F, 3, 2, 5);

    body6.setRotationPoint(0F, 0F, 4F);

    body6.setTextureSize(textureWidth, textureHeight);

    setRotation(body6, 0F, degToRad(undulationCycle[cycleIndex][4]), 0F);

    body5.addChild(body6);

    body7 = new ModelRenderer(this, 30, 0);

    body7.addBox(-1F, -1F, -1F, 2, 2, 5);

    body7.setRotationPoint(0F, 0F, 4F);

    body7.setTextureSize(textureWidth, textureHeight);

    setRotation(body7, 0F, degToRad(undulationCycle[cycleIndex][5]), 0F);

    body6.addChild(body7);

    body8 = new ModelRenderer(this, 30, 0);

    body8.addBox(-1F, -1F, -1F, 2, 2, 5);

    body8.setRotationPoint(0F, 0F, 4F);

    body8.setTextureSize(textureWidth, textureHeight);

    setRotation(body8, 0F, degToRad(undulationCycle[cycleIndex][6]), 0F);

    body7.addChild(body8);

    body9 = new ModelRenderer(this, 22, 12);

    body9.addBox(-0.5F, -0.5F, -1F, 1, 1, 5);

    body9.setRotationPoint(0F, 0F, 4F);

    body9.setTextureSize(textureWidth, textureHeight);

    setRotation(body9, 0F, degToRad(undulationCycle[cycleIndex][7]), 0F);

    body8.addChild(body9);

 

    }

 

    /**

    * Sets the models various rotation angles then renders the model.

    */

    @Override

public void render(Entity parEntity, float parTime, float parSwingSuppress, float par4, float parHeadAngleY, float parHeadAngleX, float par7)

    {

    // best to cast to actual expected entity, to allow access to custom fields related to animation

    renderSerpent((EntitySerpent) parEntity, parTime, parSwingSuppress, par4, parHeadAngleY, parHeadAngleX, par7);

    }

   

public void renderSerpent(EntitySerpent parEntity, float parTime, float parSwingSuppress, float par4, float parHeadAngleY, float parHeadAngleX, float par7)

    {

        setRotationAngles(parTime, parSwingSuppress, par4, parHeadAngleY, parHeadAngleX, par7, parEntity);

 

        if (this.isChild)

        {

            float childScaleFactor = 0.5F;

            GL11.glPushMatrix();

            GL11.glScalef(1.0F * childScaleFactor, 1.0F * childScaleFactor, 1.0F * childScaleFactor);

            GL11.glTranslatef(0.0F, 24.0F * par7, 0.0F);

            head.render(par7);

            if (parEntity.ticksExisted%60==0 && parSwingSuppress <= 0.1F) {tongue.render(par7);} // flick tongue occasionally

            body1.render(par7); // all rest of body are children of body1

            GL11.glPopMatrix();

        }

        else

        {

            head.render(par7);

            if (parEntity.ticksExisted%60==0 && parSwingSuppress <= 0.1F) {tongue.render(par7);} // flick tongue occasionally

            body1.render(par7); // all rest of body are children of body1

        }

    }

 

    /**

    * Sets the model's various rotation angles. For bipeds, par1 and par2 are used for animating the movement of arms

    * and legs, where par1 represents the time(so that arms and legs swing back and forth) and par2 represents how

    * "far" arms and legs can swing at most.

    */

    @Override

public void setRotationAngles(float parTime, float parSwingSuppress, float par3, float parHeadAngleY, float parHeadAngleX, float par6, Entity parEntity)

    {

        // swingSuppress goes to 0 when still so gates the movement

        if (parSwingSuppress > 0.1F)

        {

            cycleIndex = parEntity.ticksExisted%6; // cycle through animations

            body2.rotateAngleY = degToRad(undulationCycle[cycleIndex][0]) ;

            body3.rotateAngleY = degToRad(undulationCycle[cycleIndex][1]) ;

            body4.rotateAngleY = degToRad(undulationCycle[cycleIndex][2]) ;

            body5.rotateAngleY = degToRad(undulationCycle[cycleIndex][3]) ;

            body6.rotateAngleY = degToRad(undulationCycle[cycleIndex][4]) ;

            body7.rotateAngleY = degToRad(undulationCycle[cycleIndex][5]) ;

            body8.rotateAngleY = degToRad(undulationCycle[cycleIndex][6]) ;

            body9.rotateAngleY = degToRad(undulationCycle[cycleIndex][7]) ; 

        }

    }

   

    protected float degToRad(float degrees)

    {

    return degrees * (float)Math.PI / 180 ;

    }

   

    protected void setRotation(ModelRenderer model, float rotX, float rotY, float rotZ)

    {

    model.rotateAngleX = degToRad(rotX);

    model.rotateAngleY = degToRad(rotY);

    model.rotateAngleZ = degToRad(rotZ);   

    }

 

    // spin methods are good for testing and debug rotation points and offsets in the model

    protected void spinX(ModelRenderer model)

    {

    model.rotateAngleX += degToRad(0.5F);

    }

   

    protected void spinY(ModelRenderer model)

    {

    model.rotateAngleY += degToRad(0.5F);

    }

   

    protected void spinZ(ModelRenderer model)

    {

    model.rotateAngleZ += degToRad(0.5F);

    }

}

 

 

The first part that I want to bring attention to is the animation cycle I hard-coded:

 // create an animation cycle
    protected int cycleIndex = 0;
    protected static float[][] undulationCycle = new float[][]{
    		  { 45F, -45F, -45F, 0F, 45F, 45F, 0F, -45F },
    		  { 0F, 45F, -45F, -45F, 0F, 45F, 45F, 0F },
    		  { -45F, 90F, 0F, -45F, -45F, 0F, 45F, 45F },
    		  { -45F, 45F, 45F, 0F, -45F, -45F, 0F, 45F },
    		  { 0F, -45F, 45F, 45F, 0F, -45F, -45F, 0F },
    		  { 45F, -90F, 0F, 45F, 45F, 0F, -45F, -45F },

 

Basically, each row is a step in the animation and each column is one of the snake's body parts.  I came up with this table by simply drawing a snake on a piece of paper and figuring out the relative angles between parts.  Note that each body part in the snake is child of the previous, so that all the parts remain connected.

 

Then for each body part, I use the following code structure to create each box:

	    head = new ModelRenderer(this, 0, 0);
    head.addBox(-2.5F, -1F, -5F, 5, 2, 5);
    head.setRotationPoint(0F, 23F, -8F);
    head.setTextureSize(textureWidth, textureHeight);
    setRotation(head, 0F, 0F, 0F);

 

For people that may not know:

- the parameters in the ModelRender() constructor are the texture offset from Techne

- the first three parameters in the addBox() method are the offset x, y, z from Techne

- the second three parameters in the addBox() method are the dimensions x, y, z from Techne

 

The next important thing is how I add children boxes.  If you have anything that should move with something else but also have its own rotation, then I strongly suggest making it a child.  Otherwise, you have to do a lot of trigonometry to keep it connected.

 

Note that if you don't want to move the piece separately, you can add multiple boxes to one ModelRenderer.

 

In any case, something like an ear should NOT be a fully separate box, but rather should be either a child or at least added to the head.  Then when you rotate the head, it will all move together.

 

In the case of the snake, I did the children thing a lot -- each segment of the snake's body is a child of the previous.  So all I have to do is set the rotations (which are relative) of each body segment and then just render only the body (which contains all the segments).

 

Next, notice that the second parameter passed in an entity render call is a float that indicates whether the entity is moving.  I called it parSwingSuppress (i.e. I use it to suppress any arm swinging), but it is really I think more like a speed and should probably be named more appropriately.  Anyway, in the case of my snake, I only wanted its body to wiggle when this float was something significant.  Basically, this parameter is quite useful for entity animation of moving versus standing still.

 

Okay, the next part I'm really proud of.  It is really easy and really powerful animating technique:

    @Override
public void setRotationAngles(float parTime, float parSwingSuppress, float par3, float parHeadAngleY, float parHeadAngleX, float par6, Entity parEntity)
    {
        // swingSuppress goes to 0 when still so gates the movement
        if (parSwingSuppress > 0.1F)
        {
            cycleIndex = parEntity.ticksExisted%6; // cycle through animations
            body2.rotateAngleY = degToRad(undulationCycle[cycleIndex][0]) ;
            body3.rotateAngleY = degToRad(undulationCycle[cycleIndex][1]) ;
            body4.rotateAngleY = degToRad(undulationCycle[cycleIndex][2]) ;
            body5.rotateAngleY = degToRad(undulationCycle[cycleIndex][3]) ;
            body6.rotateAngleY = degToRad(undulationCycle[cycleIndex][4]) ;
            body7.rotateAngleY = degToRad(undulationCycle[cycleIndex][5]) ;
            body8.rotateAngleY = degToRad(undulationCycle[cycleIndex][6]) ;
            body9.rotateAngleY = degToRad(undulationCycle[cycleIndex][7]) ;  
        }

All I'm doing is cycling through the hard-coded array of angles for the animation.  There is no trigonometry at all!  Since all the rotations are relative (the body parts are children of preceding part) and because I figured out the right angles through simply drawing what I wanted on a piece of paper (you can also position it in Techne), it just cycles through them.

 

Lastly I have a couple helper functions.  degToRad() is simply a float version of simple converter -- I just find a lot of math utils require casting if you're working in floats.  But certainly you can use another math helper function, or if you can think in radians then you're a better mind than me!

 

The spinX() etc. methods I find extremely important although they are not used in my final code.  I use them to debug my model.  I take each part in turn, and use the spin on them in the render (while disabling other rotations).  This creates an obvious visual check that your rotation point and offsets are correct.

 

Anyway, not sure if this is more confusing or helpful.

 

If I can teach one thing I do want to promote the idea of using an array of angles to control your animation though -- after days of working through complex trigonometry I suddenly realized you don't really need math to animate something through a loop with only a few steps.

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

Link to comment
Share on other sites

Thank you! That is really helpful and has enabled me to change my code so it's a lot more sane. A lot of what you did I skimmed over as I'm modifying a basic quadruped so I don't need to define my own animation or body shape (yet!).

 

But, I am stuck a stage further back than this. I *think* I've got a fairly good Render and Model class but I can't get the code right to load the model and renderer onto the Mod. When I test it out, it spawns a grey cube that runs around a moos, and even drops leather and beef if you kill it!

 

So, what goes in the mod class, and the ClientProxy?

 

Edit Fixed that now trying to map a texture to it!

 

Cheers!

 

Graham

Link to comment
Share on other sites

Do any of you know of a tutorial for adding mobs in 1.6.4? I've gotten the Techne model done but I've been searching all day for a custom mobs tutorial and still haven't been able to find one. Specifically I just need to know how to add the model to the game. Any help is greatly appreciated!

Link to comment
Share on other sites

Edit Fixed that now trying to map a texture to it!

 

Okay, the texture mapping isn't so hard but there are a couple sticky points.  Basically you just need the offset (the last two parameters in the ModelRenderer() constructor for each box, and you need the template for how it wraps around the box.

 

I use Techne to check and visualize the texture map, but there are a couple tricks.

 

1) The biggest gotcha I ran into which puzzled me for a long time is that the texture image dimensions MUST be 2:1 ratio.  So if you're trying to do a big model or if you are doing HD texture, you can't just make the y-dimension longer to make more space.  If you do, when it is mapped it will be scaled down in just the one dimension, causing weird squishing and invisibility.  So 64:32 (default) or 128:64 and so on are good, but don't do a 128:128.

 

2) The biggest benefit of Techne is that once you load a texturemap, any edits to that file are immediately applied (don't need to load it again).  So it allows quick checking.

 

3) I use GIMP (open source Photoshop type of program) for editing the texture map.  I use the pencil tool at size 1.0 pixel.  The paintbrush tool is not good because it will "blend" into neighboring pixels unless you are perfectly aligned to the pixel.

 

4) The most confusing thing with Techne is that initially all the texture offsets overlap because they're all at 0, 0 offset.  I wish there was a button to "spread out texture offsets" to automatically space them all out.  But you need to go through your blocks one by one and change the texture offsets until there is no overlap.  If you have a bunch of parts of your model that use the same texturing, you can actually let them overlap but I found that in most cases you want them separate -- even with something like entity legs that you think are all the same, they're not really if you want the texture to have a bit of change of color on the inside, or if you want claws on the front, etc.

 

5) Once you have spaced out all the texture offsets in Techne, then you want to export the texture map.  This will create a colored default texture map png file.  I usually load it again right away, because you'll see that some of the faces of the blocks have markings to help indicate orientation.  I usually put my own little markers on each face of the default texture map to get a sense of orientation.

 

6) While Techne is still up, load the png in GIMP (or similar pixel editor).  Proceed slowly, getting each block correct.  The main thing is figuring out the orientations and how the folds match up.  In most advanced photshop type programs saving the file will save it in that program's format (.xcf for GIMP) so you need to export it back to png.  If you use the same file name, it will immediately appear back in Techne.

 

7) That's about it, except when you're done you need to put it into the right asset folder and make sure the right file name is referenced in your Java code.

 

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

Link to comment
Share on other sites

Thanks for that - I didn't know about the 2:1 thing. At the moment it's set to 64x64 but the beast is purple and black so something's not right in the file location and/or java code.

 

I'm nearly there, because I've got a lang file that changes the name of the spawn egg. If you could point me in the right direction relative to the lang dir and also where to put what in the code I'd be really grateful!

 

cheers!

 

Graham

Link to comment
Share on other sites

I'm nearly there, because I've got a lang file that changes the name of the spawn egg. If you could point me in the right direction relative to the lang dir and also where to put what in the code I'd be really grateful!

 

Did you mean the lang directory, or the textures directory?  It sounds like you have lang working so it is the textures you need help with?

 

I'm at work now and am busy through the evening, so can't provide much more info today.

 

I think (I'm not at my computer to verify) so you'll probably figure it out before I get chance to check my code, but if not I'll write more when I can. 

 

You should check to see for the error in the console about the missing texture, and that might give you a clue on where it is looking for the texture currently.

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

Link to comment
Share on other sites

Okay, so for the lang file, I put it in assets/modid/lang folder under the src for my mod.  So for my wildanimals mod the full path is E:\Forge\eclipse\WildAnimals\src\assets\wildanimals\lang.

 

Similarly for my textures, I have them in folders like: E:\Forge\eclipse\WildAnimals\src\assets\wildanimals\textures\entity\serpents

 

I reference the textures in the renderer, so in my RenderSerpent class I have this:

public class RenderSerpent extends RenderLiving
{
    protected ResourceLocation serpentTexture;

    public RenderSerpent(ModelBase par1ModelBase, float par2)
    {
        super(par1ModelBase, par2);
        setEntityTexture();
        
    }

    @Override
protected void preRenderCallback(EntityLivingBase entity, float f){
    	preRenderCallbackSerpent((EntitySerpent) entity, f);
    }

    
protected void preRenderCallbackSerpent(EntitySerpent entity, float f)
{
    }

    protected void setEntityTexture()
    {
    	serpentTexture = new ResourceLocation("wildanimals:textures/entity/serpents/python.png");
    }
    
    /**
     * Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture.
     */
    protected ResourceLocation getEntityTexture(EntitySerpent par1EntitySerpent)
    {
        return serpentTexture;
    }

    /**
     * Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture.
     */
    @Override
protected ResourceLocation getEntityTexture(Entity par1Entity)
    {
        return this.getEntityTexture((EntitySerpent)par1Entity);
    }
}

 

The code is a little bit indirect in terms of having a few similar nested methods to simply get the texture resource,  but I basically followed some vanilla code and modified it and it works so that's the way I do it.

 

Note particularly how the resource location refers to the texture location -- "wildanimals:textures/entity/serpents/python.png" which uses the modid (in my case "wildanimals" and a colon then the path including the textures folder.

 

Anyway, that's how I do it.  Hope that helps.

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

Link to comment
Share on other sites

Yay! Nearly there! Now have the texture mapped really badly onto the beasty - it's all squished and out of place and transparent in places. I've got 64 different coloured squares now to see what on earth is going on. I think that I changed the texture out to 128 x 64 by increasing the canvas size and I should've stretched it.

 

More experimentation ahead...

 

Many thanks - I wouldn't have got this far without your help!

 

Graham

Link to comment
Share on other sites

Yay! Nearly there! Now have the texture mapped really badly onto the beasty - it's all squished and out of place and transparent in places. I've got 64 different coloured squares now to see what on earth is going on. I think that I changed the texture out to 128 x 64 by increasing the canvas size and I should've stretched it.

 

I think increasing canvas size should work.  But you also need to make sure the texture size in Java is set correctly -- you need to set the textureWidth and textureHeight.  Did you do that?

 

If it is squished with transparent parts it is definitely related to some problem with the 2:1 aspect ratio.

 

You could try to set the texture size in Techne to the size you want 128x64 and export that and then see if that maps properly.

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

Link to comment
Share on other sites

I've been going round in circles and I just can't see how to make this happen. I think that the real problem is that I'm trying to make a larger quadruped. I've extended ModelBase and copied across a lot of the code for ModelCow to make it work. But, it is a bit bigger than cow, so I've increased the texture size. Looking through the various render and model classes that Minecraft supplies, they all seem to hard code texture size to 64 x 32 so maybe that's the problem?

 

Graham

Link to comment
Share on other sites

So... I've been playing with this on and off trying to figure it out. As my animal is basically all black with patterns (like eyes, mouth, ears etc.) I made a 64x32 .png which was all black and then added bits to it so I could see what's going on. I've learned two things:

 

1) if there's not enough room, it wraps around from bottom to top and right to left.

 

2) This meant I ran out of room so I increased the canvas size to 128 x 64, and changed nothing else. I left all the detail in the top left corner of the image, just as before. But as soon as I loaded it up, the detail on the head which had been perfect was totally messed up. This is significant as the head texture loads from 0,0. So it is doing something weird when I increase the canvas size and I just can't see what it is.

 

It's a bit dispiriting to think that I'll have to start all over again with a bigger graphic.

 

Any help?

 

Graham

Link to comment
Share on other sites

One thing is I think it is wise to make sure that the texture size in the Java matches your actual texture file.  I'm not entirely sure what happens if these mismatch -- I think it will scale, so keeping 2:1 should still be okay -- but best to make it match.

 

Anyway, does it look correct in Techne?  Even if you've modified your model a lot directly in Java (which is my preference) you can use Techne to quickly check texture mapping.  You don't need to put the full model into Techne, just the block you're checking the mapping.

 

What you need to do is to:

1. Start a new Techne model, with ModelBase.  Set the texture size correctly for the project!

2. Create a block that matches the Java for the part of your model you care about.  Put in the rotation point, dimensions, offset and texture offset.

3. Load your texture.png into Teche

 

Then play around with it there until you get it right.  Then modify your Java (or your texture file) accordingly.

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

Link to comment
Share on other sites

When you made the model in Tecne, leave the exture the default size.

 

Shift the graphics around as needed so they have a unique spot on the graphic spot in uppper right corner. 

 

Save the file to .png at the same batch as you export the java.

 

Use that .png in your mod and see if the skin takes. 

 

If it does, then you are set.  If not, the problem is your code not how you are doing Tecne.

 

If it does work, you can scale the skin.  For example if the skin is 64x32 you can double it to 128x64 in Gimp.  Be sure to set it so it straight scales it and not the cubit junk where it will add stuff.  Modify it, save it, and export it back to .png. 

 

If you want to test that look in Tecne, when you import it DO NOT Accept changing the scales or it will screw everything up.

 

Good luck.

Long time Bukkit & Forge Programmer

Happy to try and help

Link to comment
Share on other sites

Woohoo! Thanks for all your efforts I wouldn't have got this far without you guys! I've fixed it!

 

Turns out that my ModelAurochs file extends ModelBase. And before all the complicated addBox commands, I simply added two attributions:

 

super.textureWidth=128;
super.textureHeight=64;

 

This fixed everything! As a way to say thank-you here's a unique, first time ever seen picture of the Minecraft Aurochs...

 

width=609 height=342http://i129.photobucket.com/albums/p208/graham_h_miller/Screenshotfrom2014-05-07194158_zps3edf418f.png[/img]

 

I know it just looks like a black cow with horns, but it's also ever so slightly larger than a regular cow. And it's mine, because I made it :-D

 

Graham

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.

Announcements



×
×
  • Create New...

Important Information

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