Соединить несколько текстур в один атлас и изменить UV в OBJ модели

Agravaine

Золотая лига
Сообщения
3,858
Лучшие ответы
135
Симпатии
372
#1
Вопрос в заголовке.
Есть модель, у нее есть группы и на каждую группу отдельный файл текстуры. Это неудобно, да и рисовать в игре плохо, ибо постоянно нужно щелкать текстуру...
Есть ли утилитка, которая упакует несколько текстур в один атлас + изменит UV координаты в модельке на правильные для атласа?
Ибо моделек таких много и вручную очень геморно все это переделывать...
 

timaxa007

Команда форума
Сообщения
5,154
Лучшие ответы
307
Симпатии
409
#2
Текстуры блоки по отдельности, а в игре это единый атлас.
Java:
    //tessellator.setColorOpaque_I(clr);
    public static void boxOnIcon(Tessellator tessellator, IIcon icon, double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
        if (icon == null) return;
        double icon_minX = (minX < 0D ? 0D : minX) * 16D;
        double icon_minY = (minY < 0D ? 0D : minY) * 16D;
        double icon_minZ = (minZ < 0D ? 0D : minZ) * 16D;
        double icon_maxX = (maxX > 1D ? 1D : maxX) * 16D;
        double icon_maxY = (maxY > 1D ? 1D : maxY) * 16D;
        double icon_maxZ = (maxZ > 1D ? 1D : maxZ) * 16D;
        tessellator.startDrawingQuads();
        //Top
        tessellator.addVertexWithUV(maxX, maxY, minZ,
                (double)icon.getInterpolatedU(icon_maxX),
                (double)icon.getInterpolatedV(icon_minZ)
                );
        tessellator.addVertexWithUV(minX, maxY, minZ,
                (double)icon.getInterpolatedU(icon_minX),
                (double)icon.getInterpolatedV(icon_minZ)
                );
        tessellator.addVertexWithUV(minX, maxY, maxZ,
                (double)icon.getInterpolatedU(icon_minX),
                (double)icon.getInterpolatedV(icon_maxZ)
                );
        tessellator.addVertexWithUV(maxX, maxY, maxZ,
                (double)icon.getInterpolatedU(icon_maxX),
                (double)icon.getInterpolatedV(icon_maxZ)
                );
        //Bottom
        tessellator.addVertexWithUV(maxX, minY, maxZ,
                (double)icon.getInterpolatedU(icon_maxX),
                (double)icon.getInterpolatedV(icon_maxZ)
                );
        tessellator.addVertexWithUV(minX, minY, maxZ,
                (double)icon.getInterpolatedU(icon_minX),
                (double)icon.getInterpolatedV(icon_maxZ)
                );
        tessellator.addVertexWithUV(minX, minY, minZ,
                (double)icon.getInterpolatedU(icon_minX),
                (double)icon.getInterpolatedV(icon_minZ)
                );
        tessellator.addVertexWithUV(maxX, minY, minZ,
                (double)icon.getInterpolatedU(icon_maxX),
                (double)icon.getInterpolatedV(icon_minZ)
                );
        //North
        tessellator.addVertexWithUV(maxX, minY, minZ,
                (double)icon.getInterpolatedU(icon_minX),
                (double)icon.getInterpolatedV(icon_maxY)
                );
        tessellator.addVertexWithUV(minX, minY, minZ,
                (double)icon.getInterpolatedU(icon_maxX),
                (double)icon.getInterpolatedV(icon_maxY)
                );
        tessellator.addVertexWithUV(minX, maxY, minZ,
                (double)icon.getInterpolatedU(icon_maxX),
                (double)icon.getInterpolatedV(icon_minY)
                );
        tessellator.addVertexWithUV(maxX, maxY, minZ,
                (double)icon.getInterpolatedU(icon_minX),
                (double)icon.getInterpolatedV(icon_minY)
                );
        //South
        tessellator.addVertexWithUV(maxX, maxY, maxZ,
                (double)icon.getInterpolatedU(icon_maxX),
                (double)icon.getInterpolatedV(icon_minY)
                );
        tessellator.addVertexWithUV(minX, maxY, maxZ,
                (double)icon.getInterpolatedU(icon_minX),
                (double)icon.getInterpolatedV(icon_minY)
                );
        tessellator.addVertexWithUV(minX, minY, maxZ,
                (double)icon.getInterpolatedU(icon_minX),
                (double)icon.getInterpolatedV(icon_maxY)
                );
        tessellator.addVertexWithUV(maxX, minY, maxZ,
                (double)icon.getInterpolatedU(icon_maxX),
                (double)icon.getInterpolatedV(icon_maxY)
                );
        //West
        tessellator.addVertexWithUV(minX, maxY, maxZ,
                (double)icon.getInterpolatedU(icon_maxY),
                (double)icon.getInterpolatedV(icon_minZ)
                );
        tessellator.addVertexWithUV(minX, maxY, minZ,
                (double)icon.getInterpolatedU(icon_minY),
                (double)icon.getInterpolatedV(icon_minZ)
                );
        tessellator.addVertexWithUV(minX, minY, minZ,
                (double)icon.getInterpolatedU(icon_minY),
                (double)icon.getInterpolatedV(icon_maxZ)
                );
        tessellator.addVertexWithUV(minX, minY, maxZ,
                (double)icon.getInterpolatedU(icon_maxY),
                (double)icon.getInterpolatedV(icon_maxZ)
                );
        //East
        tessellator.addVertexWithUV(maxX, minY, maxZ,
                (double)icon.getInterpolatedU(icon_minY),
                (double)icon.getInterpolatedV(icon_maxZ)
                );
        tessellator.addVertexWithUV(maxX, minY, minZ,
                (double)icon.getInterpolatedU(icon_maxY),
                (double)icon.getInterpolatedV(icon_maxZ)
                );
        tessellator.addVertexWithUV(maxX, maxY, minZ,
                (double)icon.getInterpolatedU(icon_maxY),
                (double)icon.getInterpolatedV(icon_minZ)
                );
        tessellator.addVertexWithUV(maxX, maxY, maxZ,
                (double)icon.getInterpolatedU(icon_minY),
                (double)icon.getInterpolatedV(icon_minZ)
                );

        tessellator.draw();
    }
//----------------------------------------------------------------------------------------------------
    public static void renderAllOnIcon(WavefrontObject obj, IIcon icon, Tessellator tessellator) {
        if (obj.groupObjects.size() > 0)
            for (GroupObject go : obj.groupObjects) {
                renderOnIcon(go, icon, tessellator);
            }
    }

    public static void renderPartOnIcon(WavefrontObject obj, String partName, IIcon icon, Tessellator tessellator) {
        if (obj.groupObjects.size() > 0)
            for (GroupObject go : obj.groupObjects) {
                if (partName.equals(go.name)) {
                    renderOnIcon(go, icon, tessellator);
                    break;
                } else continue;
            }
    }

    private static void renderOnIcon(GroupObject go, IIcon icon, Tessellator tessellator) {
        tessellator.startDrawing(GL11.GL_TRIANGLES);//GL_QUADS - напоминание.
        for (Face f : go.faces) {
            Vertex vf = f.faceNormal;
            tessellator.setNormal(vf.x, vf.y, vf.z);
            for (int i = 0; i < f.vertices.length; ++i) {
                Vertex v = f.vertices[i];
                if (f.textureCoordinates != null && f.textureCoordinates.length > 0) {
                    TextureCoordinate tc = f.textureCoordinates[i];
                    tessellator.addVertexWithUV(
                            (double)v.x, (double)v.y, (double)v.z,
                            (double)icon.getInterpolatedU((double)(tc.u * 16.0F)),
                            (double)icon.getInterpolatedV((double)(tc.v * 16.0F))
                            );
                } else {
                    //Плохо если код доходит до этого.
                    tessellator.addVertex((double)v.x, (double)v.y, (double)v.z);
                }
            }
        }
        tessellator.draw();
    }
 

Agravaine

Золотая лига
Сообщения
3,858
Лучшие ответы
135
Симпатии
372
#3
Тут вообще с майном никак не связано, это не то.
 

timaxa007

Команда форума
Сообщения
5,154
Лучшие ответы
307
Симпатии
409
#4
 

Dahaka

Золотая лига
Сообщения
2,312
Лучшие ответы
81
Симпатии
247
#5
Наверное, нет такого.
Простых то атлас генераторов вагон, а вот чтобы еще и параллельно obj парсил...
Самое простое будет написать самому скриптик на пайтоне, взяв за основу какой-нибудь готовый атлас генератор и obj ридер.
 

Agravaine

Золотая лига
Сообщения
3,858
Лучшие ответы
135
Симпатии
372
#6
Атлас генератор взял майновский, Stitcher который, вполне хорошо работает.
Не знаю как координаты uv преобразовать.
 

Dahaka

Золотая лига
Сообщения
2,312
Лучшие ответы
81
Симпатии
247
#7
Дак ты смотри, куда поместился регион, и вырази изменение через функцию (скейл и смещение). Затем на каждую uv модели примени эту функцию.
Т.к. у исходных текстур регион всегда (0f, 0f, 1f, 1f), то это должно работать правильно:
Kotlin:
val uScale = u2 - u1
val uOffset = u1
...
uVertex  = uVertex * uScale + uOffset
 
Последнее редактирование:

Agravaine

Золотая лига
Сообщения
3,858
Лучшие ответы
135
Симпатии
372
#8

Dahaka

Золотая лига
Сообщения
2,312
Лучшие ответы
81
Симпатии
247
#9
Это u региона в атласе.
 

Agravaine

Золотая лига
Сообщения
3,858
Лучшие ответы
135
Симпатии
372
#10
Java:
                    int atlasWidth = atlas.getCurrentWidth();
                    int atlasHeight = atlas.getCurrentHeight();
                    float atlasU = 1.0F / (float)atlasWidth;
                    float atlasV = 1.0F / (float)atlasHeight;
                    
                    float uScale = atlasU - (texture.getOriginX() * atlasU);
                    float uOffset = texture.getOriginX() * atlasU;
                    float uVertex = face.textureCoordinates[i].u * uScale + uOffset;
                    
                    float vScale = atlasV - (texture.getOriginY() * atlasV);
                    float vOffset = texture.getOriginY() * atlasV;
                    float vVertex = face.textureCoordinates[i].v * vScale + vOffset;
Чот не выходит, туплю.
 

Dahaka

Золотая лига
Сообщения
2,312
Лучшие ответы
81
Симпатии
247
#11
Ты же когда подаешь атласу текстуру, должен получить иконку. А у этой иконки есть getMinU и т.п. А то что ты написал, это вообще дичь какая-то.
 

Agravaine

Золотая лига
Сообщения
3,858
Лучшие ответы
135
Симпатии
372
#12
Так?
Java:
float uScale = texture.getMaxU() - texture.getMinU();
float uOffset = texture.getMinU();
float uVertex = face.textureCoordinates[i].u * uScale + uOffset;
 

fane4qa

Каменная лига
Сообщения
510
Лучшие ответы
5
Симпатии
19
#13
ТС дико плюсую, такая же проблема
Можешь потом фул решение скинуть?
 

Agravaine

Золотая лига
Сообщения
3,858
Лучшие ответы
135
Симпатии
372
#15
Неа, не пашет.
 

Dahaka

Золотая лига
Сообщения
2,312
Лучшие ответы
81
Симпатии
247
#16
Ну приведение, вроде, правильное. Так что, скорее всего, ты там чета накосячил.
 

Agravaine

Золотая лига
Сообщения
3,858
Лучшие ответы
135
Симпатии
372
#17
Решено.
Java:
int x = texture.getOriginX();
int y = texture.getOriginY();
int w = texture.getIconWidth();
int h = texture.getIconHeight();
                
float scaleX = w / (float)stitcher.getCurrentWidth();
vertex.getTextureCoords().x *= scaleX;
vertex.getTextureCoords().x += texture.getMinU();

float scaleY = h / (float)stitcher.getCurrentHeight();
vertex.getTextureCoords().y = 1.0F - vertex.getTextureCoords().y;
vertex.getTextureCoords().y *= scaleY;
vertex.getTextureCoords().y += texture.getMinV();
texture достал из Stitcher, а stitcher - собственно сам объект Stitcher из майна.
 
Последнее редактирование:

fane4qa

Каменная лига
Сообщения
510
Лучшие ответы
5
Симпатии
19
#18
Оу, это с чем и как есть?
Стичер достается из mc как я понял?
 

Agravaine

Золотая лига
Сообщения
3,858
Лучшие ответы
135
Симпатии
372
#19
Ну я просто скопировал майновский класс и чуточку подправил.
Stitcher:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.google.common.collect.Lists;

import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.util.MathHelper;

public class AtlasStitcher{

    private final int mipmapLevelStitcher;
    private final Set setStitchHolders = new HashSet(256);
    private final List stitchSlots = new ArrayList(256);
    private int currentWidth;
    private int currentHeight;
    private final int maxWidth;
    private final int maxHeight;
    private final boolean forcePowerOf2;
    /** Max size (width or height) of a single tile */
    private final int maxTileDimension;
    private static final String __OBFID = "CL_00001054";
    public boolean rotate = false;

    public AtlasStitcher(int p_i45095_1_, int p_i45095_2_, boolean p_i45095_3_, int p_i45095_4_, int p_i45095_5_){
        this.mipmapLevelStitcher = p_i45095_5_;
        this.maxWidth = p_i45095_1_;
        this.maxHeight = p_i45095_2_;
        this.forcePowerOf2 = p_i45095_3_;
        this.maxTileDimension = p_i45095_4_;
    }

    public int getCurrentWidth(){
        return this.currentWidth;
    }

    public int getCurrentHeight(){
        return this.currentHeight;
    }

    public void addSprite(Texture p_110934_1_){
        AtlasStitcher.Holder holder = new AtlasStitcher.Holder(p_110934_1_, this.mipmapLevelStitcher);

        if(this.maxTileDimension > 0){
            holder.setNewDimension(this.maxTileDimension);
        }

        this.setStitchHolders.add(holder);
    }

    public void doStitch(){
        AtlasStitcher.Holder[] aholder = (AtlasStitcher.Holder[])this.setStitchHolders.toArray(new AtlasStitcher.Holder[this.setStitchHolders.size()]);
        Arrays.sort(aholder);
        AtlasStitcher.Holder[] aholder1 = aholder;
        int i = aholder.length;

        for(int j = 0; j < i; ++j){
            AtlasStitcher.Holder holder = aholder1[j];

            if(!this.allocateSlot(holder)){
                String s = String.format("Unable to fit: %s - size: %dx%d - Maybe try a lowerresolution resourcepack?", new Object[]{holder.getAtlasSprite().getIconName(), Integer.valueOf(holder.getAtlasSprite().getIconWidth()), Integer.valueOf(holder.getAtlasSprite().getIconHeight())});
            }
        }

        if(this.forcePowerOf2){
            this.currentWidth = MathHelper.roundUpToPowerOfTwo(this.currentWidth);
            this.currentHeight = MathHelper.roundUpToPowerOfTwo(this.currentHeight);
        }
    }

    public List getStichSlots(){
        ArrayList arraylist = Lists.newArrayList();
        Iterator iterator = this.stitchSlots.iterator();

        while(iterator.hasNext()){
            AtlasStitcher.Slot slot = (AtlasStitcher.Slot)iterator.next();
            slot.getAllStitchSlots(arraylist);
        }

        ArrayList arraylist1 = Lists.newArrayList();
        Iterator iterator1 = arraylist.iterator();

        while(iterator1.hasNext()){
            AtlasStitcher.Slot slot1 = (AtlasStitcher.Slot)iterator1.next();
            AtlasStitcher.Holder holder = slot1.getStitchHolder();
            Texture textureatlassprite = holder.getAtlasSprite();
            textureatlassprite.initSprite(this.currentWidth, this.currentHeight, slot1.getOriginX(), slot1.getOriginY(), rotate ? holder.isRotated() : false);
            arraylist1.add(textureatlassprite);
        }

        return arraylist1;
    }

    private static int getMipmapDimension(int p_147969_0_, int p_147969_1_){
        return p_147969_0_;//(p_147969_0_ >> p_147969_1_) + ((p_147969_0_ & (1 << p_147969_1_) - 1) == 0 ? 0 : 1) << p_147969_1_;
    }

    /**
     * Attempts to find space for specified tile
     */
    private boolean allocateSlot(AtlasStitcher.Holder p_94310_1_){
        for(int i = 0; i < this.stitchSlots.size(); ++i){
            if(((AtlasStitcher.Slot)this.stitchSlots.get(i)).addSlot(p_94310_1_)){
                return true;
            }

            if(rotate){
                p_94310_1_.rotate();

                if(((AtlasStitcher.Slot)this.stitchSlots.get(i)).addSlot(p_94310_1_)){
                    return true;
                }

                p_94310_1_.rotate();
            }
        }

        return this.expandAndAllocateSlot(p_94310_1_);
    }

    /**
     * Expand stitched texture in order to make space for specified tile
     */
    private boolean expandAndAllocateSlot(AtlasStitcher.Holder p_94311_1_){
        int i = Math.min(p_94311_1_.getWidth(), p_94311_1_.getHeight());
        boolean flag = this.currentWidth == 0 && this.currentHeight == 0;
        boolean flag1;
        int j;

        if(this.forcePowerOf2){
            j = MathHelper.roundUpToPowerOfTwo(this.currentWidth);
            int k = MathHelper.roundUpToPowerOfTwo(this.currentHeight);
            int l = MathHelper.roundUpToPowerOfTwo(this.currentWidth + i);
            int i1 = MathHelper.roundUpToPowerOfTwo(this.currentHeight + i);
            boolean flag2 = l <= this.maxWidth;
            boolean flag3 = i1 <= this.maxHeight;

            if(!flag2 && !flag3){
                return false;
            }

            boolean flag4 = j != l;
            boolean flag5 = k != i1;

            if(flag4 ^ flag5){
                flag1 = !flag4;
            }else{
                flag1 = flag2 && j <= k;
            }
        }else{
            boolean flag6 = this.currentWidth + i <= this.maxWidth;
            boolean flag7 = this.currentHeight + i <= this.maxHeight;

            if(!flag6 && !flag7){
                return false;
            }

            flag1 = flag6 && (flag || this.currentWidth <= this.currentHeight);
        }

        j = Math.max(p_94311_1_.getWidth(), p_94311_1_.getHeight());

        if(MathHelper.roundUpToPowerOfTwo((flag1 ? this.currentHeight : this.currentWidth) + j) > (flag1 ? this.maxHeight : this.maxWidth)){
            return false;
        }else{
            AtlasStitcher.Slot slot;

            if(flag1){
                if(p_94311_1_.getWidth() > p_94311_1_.getHeight()){
                    if(rotate){
                        p_94311_1_.rotate();
                    }
                }

                if(this.currentHeight == 0){
                    this.currentHeight = p_94311_1_.getHeight();
                }

                slot = new AtlasStitcher.Slot(this.currentWidth, 0, p_94311_1_.getWidth(), this.currentHeight);
                this.currentWidth += p_94311_1_.getWidth();
            }else{
                slot = new AtlasStitcher.Slot(0, this.currentHeight, this.currentWidth, p_94311_1_.getHeight());
                this.currentHeight += p_94311_1_.getHeight();
            }

            slot.addSlot(p_94311_1_);
            this.stitchSlots.add(slot);
            return true;
        }
    }

    @SideOnly(Side.CLIENT)
    public class Holder implements Comparable{

        private final Texture theTexture;
        private final int width;
        private final int height;
        private final int mipmapLevelHolder;
        private boolean rotated;
        private float scaleFactor = 1.0F;
        private static final String __OBFID = "CL_00001055";

        public Holder(Texture p_i45094_1_, int p_i45094_2_){
            this.theTexture = p_i45094_1_;
            this.width = p_i45094_1_.getIconWidth();
            this.height = p_i45094_1_.getIconHeight();
            this.mipmapLevelHolder = p_i45094_2_;
            this.rotated = rotate ? AtlasStitcher.getMipmapDimension(this.height, p_i45094_2_) > AtlasStitcher.getMipmapDimension(this.width, p_i45094_2_) : false;
        }

        public Texture getAtlasSprite(){
            return this.theTexture;
        }

        public int getWidth(){
            return rotate ? (this.rotated ? AtlasStitcher.getMipmapDimension((int)((float)this.height * this.scaleFactor), this.mipmapLevelHolder) : AtlasStitcher.getMipmapDimension((int)((float)this.width * this.scaleFactor), this.mipmapLevelHolder)) : AtlasStitcher.getMipmapDimension((int)((float)this.width * this.scaleFactor), this.mipmapLevelHolder);
        }

        public int getHeight(){
            return rotate ? (this.rotated ? AtlasStitcher.getMipmapDimension((int)((float)this.width * this.scaleFactor), this.mipmapLevelHolder) : AtlasStitcher.getMipmapDimension((int)((float)this.height * this.scaleFactor), this.mipmapLevelHolder)) : AtlasStitcher.getMipmapDimension((int)((float)this.height * this.scaleFactor), this.mipmapLevelHolder);
        }

        public void rotate(){
            if(rotate){
                this.rotated = !this.rotated;
            }
        }

        public boolean isRotated(){
            return rotate ? this.rotated : false;
        }

        public void setNewDimension(int p_94196_1_){
            if(this.width > p_94196_1_ && this.height > p_94196_1_){
                this.scaleFactor = (float)p_94196_1_ / (float)Math.min(this.width, this.height);
            }
        }

        public String toString(){
            return "Holder{width=" + this.width + ", height=" + this.height + '}';
        }

        public int compareTo(AtlasStitcher.Holder p_compareTo_1_){
            int i;

            if(this.getHeight() == p_compareTo_1_.getHeight()){
                if(this.getWidth() == p_compareTo_1_.getWidth()){
                    if(this.theTexture.getIconName() == null){
                        return p_compareTo_1_.theTexture.getIconName() == null ? 0 : -1;
                    }

                    return this.theTexture.getIconName().compareTo(p_compareTo_1_.theTexture.getIconName());
                }

                i = this.getWidth() < p_compareTo_1_.getWidth() ? 1 : -1;
            }else{
                i = this.getHeight() < p_compareTo_1_.getHeight() ? 1 : -1;
            }

            return i;
        }

        public int compareTo(Object p_compareTo_1_){
            return this.compareTo((AtlasStitcher.Holder)p_compareTo_1_);
        }
    }

    @SideOnly(Side.CLIENT)
    public static class Slot{

        private final int originX;
        private final int originY;
        private final int width;
        private final int height;
        private List subSlots;
        private AtlasStitcher.Holder holder;
        private static final String __OBFID = "CL_00001056";

        public Slot(int p_i1277_1_, int p_i1277_2_, int p_i1277_3_, int p_i1277_4_){
            this.originX = p_i1277_1_;
            this.originY = p_i1277_2_;
            this.width = p_i1277_3_;
            this.height = p_i1277_4_;
        }

        public AtlasStitcher.Holder getStitchHolder(){
            return this.holder;
        }

        public int getOriginX(){
            return this.originX;
        }

        public int getOriginY(){
            return this.originY;
        }

        public boolean addSlot(AtlasStitcher.Holder p_94182_1_){
            if(this.holder != null){
                return false;
            }else{
                int i = p_94182_1_.getWidth();
                int j = p_94182_1_.getHeight();

                if(i <= this.width && j <= this.height){
                    if(i == this.width && j == this.height){
                        this.holder = p_94182_1_;
                        return true;
                    }else{
                        if(this.subSlots == null){
                            this.subSlots = new ArrayList(1);
                            this.subSlots.add(new AtlasStitcher.Slot(this.originX, this.originY, i, j));
                            int k = this.width - i;
                            int l = this.height - j;

                            if(l > 0 && k > 0){
                                int i1 = Math.max(this.height, k);
                                int j1 = Math.max(this.width, l);

                                if(i1 >= j1){
                                    this.subSlots.add(new AtlasStitcher.Slot(this.originX, this.originY + j, i, l));
                                    this.subSlots.add(new AtlasStitcher.Slot(this.originX + i, this.originY, k, this.height));
                                }else{
                                    this.subSlots.add(new AtlasStitcher.Slot(this.originX + i, this.originY, k, j));
                                    this.subSlots.add(new AtlasStitcher.Slot(this.originX, this.originY + j, this.width, l));
                                }
                            }else if(k == 0){
                                this.subSlots.add(new AtlasStitcher.Slot(this.originX, this.originY + j, i, l));
                            }else if(l == 0){
                                this.subSlots.add(new AtlasStitcher.Slot(this.originX + i, this.originY, k, j));
                            }
                        }

                        Iterator iterator = this.subSlots.iterator();
                        AtlasStitcher.Slot slot;

                        do{
                            if(!iterator.hasNext()){
                                return false;
                            }

                            slot = (AtlasStitcher.Slot)iterator.next();
                        }while(!slot.addSlot(p_94182_1_));

                        return true;
                    }
                }else{
                    return false;
                }
            }
        }

        /**
         * Gets the slot and all its subslots
         */
        public void getAllStitchSlots(List p_94184_1_){
            if(this.holder != null){
                p_94184_1_.add(this);
            }else if(this.subSlots != null){
                Iterator iterator = this.subSlots.iterator();

                while(iterator.hasNext()){
                    AtlasStitcher.Slot slot = (AtlasStitcher.Slot)iterator.next();
                    slot.getAllStitchSlots(p_94184_1_);
                }
            }
        }

        public String toString(){
            return "Slot{originX=" + this.originX + ", originY=" + this.originY + ", width=" + this.width + ", height=" + this.height + ", texture=" + this.holder + ", subSlots=" + this.subSlots + '}';
        }
    }
}
Texture:
import com.google.common.collect.Lists;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.data.AnimationFrame;
import net.minecraft.client.resources.data.AnimationMetadataSection;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.util.IIcon;
import net.minecraft.util.ReportedException;
import net.minecraft.util.ResourceLocation;

@SideOnly(Side.CLIENT)
public class Texture implements IIcon{

    private final String iconName;
    public BufferedImage data;
    private AnimationMetadataSection animationMetadata;
    protected boolean rotated;
    private boolean useAnisotropicFiltering;
    protected int originX;
    protected int originY;
    protected int width;
    protected int height;
    private float minU;
    private float maxU;
    private float minV;
    private float maxV;
    protected int frameCounter;
    protected int tickCounter;
    private static final String __OBFID = "CL_00001062";

    protected Texture(String p_i1282_1_, BufferedImage image, int offset){
        this.iconName = p_i1282_1_;
        loadSprite(image, offset);
    }

    public void initSprite(int p_110971_1_, int p_110971_2_, int p_110971_3_, int p_110971_4_, boolean p_110971_5_){
        this.originX = p_110971_3_;
        this.originY = p_110971_4_;
        this.rotated = p_110971_5_;
        float f = (float)(0.009999999776482582D / (double)p_110971_1_);
        float f1 = (float)(0.009999999776482582D / (double)p_110971_2_);
        this.minU = (float)p_110971_3_ / (float)((double)p_110971_1_) + f;
        this.maxU = (float)(p_110971_3_ + this.width) / (float)((double)p_110971_1_) - f;
        this.minV = (float)p_110971_4_ / (float)p_110971_2_ + f1;
        this.maxV = (float)(p_110971_4_ + this.height) / (float)p_110971_2_ - f1;

        if(this.useAnisotropicFiltering){
            float f2 = 8.0F / (float)p_110971_1_;
            float f3 = 8.0F / (float)p_110971_2_;
            this.minU += f2;
            this.maxU -= f2;
            this.minV += f3;
            this.maxV -= f3;
        }
    }

    public void copyFrom(Texture p_94217_1_){
        this.originX = p_94217_1_.originX;
        this.originY = p_94217_1_.originY;
        this.width = p_94217_1_.width;
        this.height = p_94217_1_.height;
        this.rotated = p_94217_1_.rotated;
        this.minU = p_94217_1_.minU;
        this.maxU = p_94217_1_.maxU;
        this.minV = p_94217_1_.minV;
        this.maxV = p_94217_1_.maxV;
    }

    /**
     * Returns the X position of this icon on its texture sheet, in pixels.
     */
    public int getOriginX(){
        return this.originX;
    }

    /**
     * Returns the Y position of this icon on its texture sheet, in pixels.
     */
    public int getOriginY(){
        return this.originY;
    }

    /**
     * Returns the width of the icon, in pixels.
     */
    public int getIconWidth(){
        return this.width;
    }

    /**
     * Returns the height of the icon, in pixels.
     */
    public int getIconHeight(){
        return this.height;
    }

    /**
     * Returns the minimum U coordinate to use when rendering with this icon.
     */
    public float getMinU(){
        return this.minU;
    }

    /**
     * Returns the maximum U coordinate to use when rendering with this icon.
     */
    public float getMaxU(){
        return this.maxU;
    }

    /**
     * Gets a U coordinate on the icon. 0 returns uMin and 16 returns uMax. Other
     * arguments return in-between values.
     */
    public float getInterpolatedU(double p_94214_1_){
        float f = this.maxU - this.minU;
        return this.minU + f * (float)p_94214_1_ / 16.0F;
    }

    /**
     * Returns the minimum V coordinate to use when rendering with this icon.
     */
    public float getMinV(){
        return this.minV;
    }

    /**
     * Returns the maximum V coordinate to use when rendering with this icon.
     */
    public float getMaxV(){
        return this.maxV;
    }

    /**
     * Gets a V coordinate on the icon. 0 returns vMin and 16 returns vMax. Other
     * arguments return in-between values.
     */
    public float getInterpolatedV(double p_94207_1_){
        float f = this.maxV - this.minV;
        return this.minV + f * ((float)p_94207_1_ / 16.0F);
    }

    public String getIconName(){
        return this.iconName;
    }

    public void setIconWidth(int p_110966_1_){
        this.width = p_110966_1_;
    }

    public void setIconHeight(int p_110969_1_){
        this.height = p_110969_1_;
    }

    public void loadSprite(BufferedImage image, int offset){
        this.resetSprite();
        int i = image.getWidth();
        int j = image.getHeight();
        this.width = i + offset;
        this.height = j + offset;

        data = image;
    }

    private void resetSprite(){
        this.animationMetadata = null;
        this.frameCounter = 0;
        this.tickCounter = 0;
    }

    /**
     * The result of this function determines is the below 'load' function is
     * called, and the default vanilla loading code is bypassed completely.
     *
     * @param manager
     * @param location
     * @return True to use your own custom load code and bypass vanilla loading.
     */
    public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location){
        return false;
    }

    /**
     * Load the specified resource as this sprite's data. Returning false from this
     * function will prevent this icon from being stitched onto the master texture.
     *
     * @param manager
     *            Main resource manager
     * @param location
     *            File resource location
     * @return False to prevent this Icon from being stitched
     */
    public boolean load(IResourceManager manager, ResourceLocation location){
        return true;
    }
}
Использую так:
main:
File[] imageFiles = new File("textures/").listFiles(filter -> !filter.getName().equals("atlas.png") && filter.getName().endsWith(".png"));

        List<BufferedImage> images = Lists.newArrayListWithCapacity(imageFiles.length);
        for(File f : imageFiles){
            images.add(ImageIO.read(f));
        }

        AtlasStitcher stitcher = new AtlasStitcher(8192, 8192, true, 0, 0);
        stitcher.rotate = false;

        for(int i = 0; i < images.size(); i++){
            BufferedImage image = images.get(i);
            stitcher.addSprite(new Texture(imageFiles[i].getName(), image, 0));
        }

        stitcher.doStitch();

        System.out.println(stitcher.getCurrentWidth() + " :: " + stitcher.getCurrentHeight());

        BufferedImage atlasImage = new BufferedImage(stitcher.getCurrentWidth(), stitcher.getCurrentHeight(), BufferedImage.TYPE_INT_ARGB);
        Iterator<Texture> i = stitcher.getStichSlots().iterator();
        while(i.hasNext()){
            Texture texture = i.next();
            atlasImage.createGraphics().drawImage(texture.data, null, texture.getOriginX(), texture.getOriginY());
        }
        ImageIO.write(atlasImage, "PNG", new File("atlas.png"));
Потом гружу модель(у меня свой формат), пробегаюсь по всем вершинам и применяю код, который в посту вышел кинул.
 

fane4qa

Каменная лига
Сообщения
510
Лучшие ответы
5
Симпатии
19
#20
Понялл принял, спасибо) (ничегонепонятнобудуразбираться)
 
Сверху