Кастомный рендер OBJ модели где угодно

Версия Minecraft
1.12.2
25
3
Имеется:
OBJ Модель из 2х мешей/сеток [сфера и параллелепипед] + 2 материала [с текстурой для сферы и синий цвет для параллелепипеда]

Задача:
Отрисовать модель в GUI или на экране во время игры с параметрами:
  • возможность сместить базовое положение модели для манипуляций с вращением и т.д.;
  • возможность выбора мешей, какие отрисовать из всей модели;
  • возможность изменить текстуры у любого материала модели;

Сие обсуждение, и некоторые другие из интернетов, привело меня к следующему действию:

I - для начала я создал класс для хранения моделей с необходимыми параметрами:
ParameterizedModel.class:
public class ParameterizedModel {
  
    public int listId;
    public ResourceLocation file;
    public List<String> visibleMeshes;
    public Map<String, String> materialTextures;
    public float[] baseOffset;
    public OBJModel iModel;
  
    public ParameterizedModel(int list, ResourceLocation file, float[] baseAxisOffsets, List<String> visibleMeshes, Map<String, String> replacesMaterialTextures) {
        this.listId = list;
        this.file = file;
        this.iModel = null;
        this.baseOffset = new float[] { 0.0f, 0.0f, 0.0f };
        if (baseAxisOffsets!=null && baseAxisOffsets.length>=3) {
            for (int i=0; i<3; i++) { this.baseOffset[i] = baseAxisOffsets[i]; }
        }
        this.visibleMeshes = Lists.<String>newArrayList();
        this.materialTextures = Maps.<String, String>newHashMap();
        if (visibleMeshes!=null && visibleMeshes.size()>0) { this.visibleMeshes = visibleMeshes; }
        if (materialTextures!=null && materialTextures.size()>0) { this.materialTextures = replacesMaterialTextures; }
    }
  
    public boolean equals(Object obj) {
        if (!(obj instanceof ParameterizedModel)) { return false; }
        ParameterizedModel objPM = (ParameterizedModel) obj;
        if (this == objPM) { return true; }
        if (!this.file.equals(objPM.file)) { return false; }
        for (int i=0; i<3; i++) {
            if (this.baseOffset[i]!=objPM.baseOffset[i]) { return false; }
        }
        if (this.visibleMeshes.size()==0 && this.materialTextures.size()==0 && objPM.visibleMeshes.size()==0 && objPM.materialTextures.size()==0) { return true; }
        if (this.visibleMeshes.size()!=objPM.visibleMeshes.size()) {
            if (objPM.visibleMeshes.size()>0) { return false; }
        }
        if (this.visibleMeshes.size()>0 && objPM.visibleMeshes.size()>0) {
            for (String name : this.visibleMeshes) {
                if (!objPM.visibleMeshes.contains(name)) { return false; }
            }
        }
        if (this.materialTextures.size()!=objPM.materialTextures.size()) {
            if (objPM.materialTextures.size()>0) { return false; }
        }
        if (this.materialTextures.size()>0 && objPM.materialTextures.size()>0) {
            for (String name : this.materialTextures.keySet()) {
                if (!objPM.materialTextures.containsKey(name) || !objPM.materialTextures.get(name).equals(this.materialTextures.get(name))) { return false; }
            }
        }  
        return true;
    }
  
}
II - далее создал класс для загрузки/получения OBJ моделей и отрисовки их по указанным параметрам:
ModelBuffer.class:
public class ModelBuffer {

    private static List<ParameterizedModel> MODELS = Lists.<ParameterizedModel>newArrayList();
    private static List<String> NOT_FOUND = Lists.<String>newArrayList();
      
    public static int getDisplayList(String objModel, float[] baseAxisOffsets, List<String> visibleMeshes, Map<String, String> replacesMaterialTextures) {
        ParameterizedModel model = new ParameterizedModel(-1, new ResourceLocation(objModel), baseAxisOffsets, visibleMeshes, replacesMaterialTextures);
        for (ParameterizedModel pm : ModelBuffer.MODELS) {
            if (pm.equals(model)) {
                model = pm;
                break;
            }
        }
        if (model.listId<0 && !ModelBuffer.NOT_FOUND.contains(objModel)) {
            try {
                model.iModel = (OBJModel) OBJLoader.INSTANCE.loadModel(model.file);
                if (model.iModel==null) {
                    ModelBuffer.NOT_FOUND.add(objModel);
                    return -1;
                }
                model.listId = GLAllocation.generateDisplayLists(1);
                GlStateManager.glNewList(model.listId, GL11.GL_COMPILE);
                Function<ResourceLocation, TextureAtlasSprite> spriteFunction = location -> {
                    ResourceLocation loc;
                    if (replacesMaterialTextures!=null && replacesMaterialTextures.containsKey(location.toString())) { loc = new ResourceLocation(replacesMaterialTextures.get(location.toString())); }
                    else { loc = location; }
                    TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(loc.toString());
                    return sprite;
                };
                if (model.visibleMeshes==null || model.visibleMeshes.size()==0) { model.visibleMeshes = Lists.<String>newArrayList(model.iModel.getMatLib().getGroups().keySet()); }
                @SuppressWarnings("deprecation")
                IBakedModel bakedmodel = model.iModel.bake(new OBJModel.OBJState(ImmutableList.copyOf(model.visibleMeshes), false), DefaultVertexFormats.ITEM, spriteFunction);
                if (model.baseOffset[0]!=0.0f || model.baseOffset[1]!=0.0f || model.baseOffset[2]!=0.0f) {
                    GlStateManager.translate(model.baseOffset[0], model.baseOffset[1], model.baseOffset[2]);
                }
                Tessellator tessellator = Tessellator.getInstance();
                BufferBuilder worldrenderer = tessellator.getBuffer();
                worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.ITEM);
                for (BakedQuad bakedquad : bakedmodel.getQuads(null, null, 0)) {
                    worldrenderer.addVertexData(bakedquad.getVertexData());
                }
                tessellator.draw();
                GlStateManager.glEndList();
                ModelBuffer.MODELS.add(model);
            }
            catch (Exception e) { }
        }
        return model.listId;
    }

}
III - ну и самое интересное - отрисовка этого дела на экране:
Где нибудь в событиях GUI или Экрана:
        GlStateManager.pushMatrix();
        GlStateManager.callList(ModelBuffer.getDisplayList("customnpcs:models/block/obj/test.obj", null, null, null));
        GlStateManager.popMatrix();

Вызов листа в таком виде не работает (модель просто невидимая).
1 - Однако если до вызова листа отрисовать какой нибудь текст:
доп строка 1:
        this.drawString(Minecraft.getMinecraft().fontRenderer, "LIST:"+list, 0, 0, 0xFFFFFF);
То модель будет отрисована неполностью, её нормали отображены, а так же стороны рисуются лишь на 50%
list.png
2 - Или забиндить любую текстуру:
доп строка 2:
        Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation("any_path"));
То модель отрисуется вся, но первый меш всегда будет чёрным + нормали всё ещё отображены.
list2.png

Что касается задачи по параметрам, то всё работает как надо (проверено через другие модели):
  • Смещение модели работает, если передать массив чисел с точкой;
  • Нужные меши рисуются, если передать лист с их именами;
  • Текстуры у материалов подменяются, если передать мапу с подменами;

Вопрос: Где у меня косяк, или Как отрисовать модель с правильными нормалями и целиком в нужном освещении?
 
Последнее редактирование:
1,038
57
229
Однако если до вызова листа отрисовать какой нибудь текст:
чушь какая то, значит явно ты что то делаешь не так. То есть всякие там Push и Pop Matrix нарушены и рисуется из-за того что всё верх ногами. Нужен 5ти минутный лог.

а так же стороны рисуются лишь на 50%
а ты можешь показать нормали в blender и UV? (мне просто любопытно)
То модель отрисуется вся, но первый меш всегда будет чёрным + нормали всё ещё отображены.
неужели моего кода нигде не сохранилось.. А ты смотрел как это делают другие?
столько всякой фигни ты делаешь лишь для того чтобы отобразить меш который состоит из частей..
А шейдер мог бы сам их вращать ничуть не хуже скелетной анимации. Но можно и без него, но зачем так много кода? (это я сам с собой разговариваю)

То модель отрисуется вся, но первый меш всегда будет чёрным + нормали всё ещё отображены.
могу лишь сказать что чёрный - результат отсутствия или текстуры, или UV

Косяк где то в мелочи, ты может вообще не в тот момент начинаешь рисовать.

О хоспаде и я же в предыдущих обсуждениях.

В общем для начала, нарисуйте кубик как там предложили, только 1 с текстурой, а другой без. А вот когда получится, переходите к отрисовке 1 части модели, когда получится, переходит к отрисовке двух частей имеющих разные текстуры.
У вас либо поворот, либо координаты, либо текстуры, либо матрицы, либо нормали - идут не так. И тут сложно гадать.
 
Последнее редактирование:
25
3
Много кода - это да;
Смещение смог реализовать и через GlStateManager.translate(x, y, z); так что часть кода в рисовке на листе - удалил

Запустил отрисовку листа раньше всего остального (+ бинд белой текстуры, если другая - эффект тот же)
Для примера эта же модель, но как стаковый предмет (такие же дела если взять блок) выглядит вот так:
1681901129837.png
Кастомная модель через лист, как видно, вывернута по всем осям и без текстуры.
В логах ошибок нет.

Модели которые необходимо отобразить на экране - предметами не являются.

Отрисовку вызываю из события RenderGameOverlayEvent в случае элемента ElementType.TEXT
Кстати та же петрушка если все настройки отключить и воспользоваться простым кодом:
create list:
list = GLAllocation.generateDisplayLists(1);
GlStateManager.glNewList(list , GL11.GL_COMPILE);
IBakedModel bakedmodel = iModel.bake(TRSRTransformation.identity(), DefaultVertexFormats.ITEM, ModelLoader.defaultTextureGetter());
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder worldrenderer = tessellator.getBuffer();
worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.ITEM);
for (BakedQuad bakedquad : bakedmodel.getQuads(null, null, 0)) {
    worldrenderer.addVertexData(bakedquad.getVertexData());
}
tessellator.draw();
GlStateManager.glEndList();
 
Последнее редактирование:
1,038
57
229
текстура должна биндится перед отрисовкой, она не попадает в DisplayList, потому что он не может её хранить.
То есть в тот момент когда ты рисуешь кто то или что то перебиндивает эту текстуру.
Ну то есть, это не точно, но если ошибка в этом, то это выглядит так
ты биндишь свою текстуру
кубы майнкрафт биндят свою текстуру
ты отрисовываешь свою модель, но текстура может быть в шейдере только 1, последняя (ну так устроен Minecraft). Она белая или чёрная, потому что по UV берётся из другого участка, может даже там стоит Claim (то есть текстура не в режиме repeat) и соответственно этого участка у майнкрафт текстуры нет.
Вот так может быть
Когда же ты рисуешь вторую часть модели, ты снова биндишь и так как она была последней, она и используются.

Я тебе даже подскажу, бинди текстуру только когда готов DrawList и можешь даже дважды биндить текстуру))) (ну чтобы наверняка)

А может быть так что он не успевает создать drawlist когда текстура забиндина и отрисовывает его лишь в следующий раз.

Копай дальше.. держи в курсе.

жаль ты не используешь шейдер освещения, без него не понятно плоская модель или плотная. Но пока у тя получается, то и пофиг. Но если будет видео, покажи блок держа в руке топор со всех сторон.

Ещё такое может быть из-за отложенного рендера, то есть tesselator может отрисовывать не сейчас, а потом (в конце кадра).
Возможно имеет смысл использовать другие события, RenderBlock (какие там есть на это дело).

и дополню что Overlay может рисоваться без
glEnable(GL_DEPTH_TEST);

а это отменяет все нормали. так как стоит glDisable(GL_DEPTH_TEST);
 
Последнее редактирование:
25
3
GL11.glEnable(GL11.GL_DEPTH_TEST); - в код добавляется без проблем (не помогло)
GL11.glEnable(GL11.GL_DEPTH); - сразу же ругается (Post render - 1280: Invalid enum) [он же GlStateManager.enableDepth(); ]

OBJ Моделей у меня штук 10, есть и такие где много материалов.
У всех одна проблема - вывернуты по осям и нет наложения текстуры.

Так же изменял место из которого необходимо отрисовать модель (из GUI Screen) проблема остаётся;

Прописываю для одной из таких моделей бинд конкретно её текстуры, белый меняется на сумму всех цветов текстуры.
Наверное что-то не так в запекании модели по части определения текстуры Function<ResourceLocation, TextureAtlasSprite> spriteFunction

Попробую обмануть систему и рисовать каждый мешь отдельно под свою текстуру.
 
Последнее редактирование:
1,038
57
229
белый меняется на сумму всех цветов текстуры.
скриншот из игры и текстуры нужен. (скорее был бы полезен, потому что тяжело представить что было и что получилось)

Попробую обмануть систему
тоже вариант.
 
25
3
Скиншот - не вопрос.
К тому же код специально кастомный, по-этому я взял только наконечник топора (текстура собственно в руке держится)
+ забиндил эту текстуру перед вызовом листа:
1681965492730.png

Если рассмотреть метод IModel.bake(...) можно увидеть, что для каждого материала в нужный момент вызывается нужная текстура через spriteFunction. (что собственно объясняет рендер модели в руке, и даже в моём коде - цветная рукоять не белая)
А эта функция, обращается к общей карте TextureMapBlocks. Есть предположение, что биндить надо эту карту.
(все методы упрощены для описания)

Но почему модель выворачивает, я хз.
Получается что все координаты вершин модели умножены на -1, и UV координаты тоже.
 
Последнее редактирование:
25
3
И так, забиндил карту текстур и отображение расцветки пошло как надо.
1681967218066.png

Ах да вот код:
перед вызовом листа:
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);

Так что остаётся проблема с выворачиванием модели. Не связано ли это с разницей осей моделирования и Minecraft?
(т.е. при моделировании система XYZ, а в игре XZY)

Если поползать по коду, то вот в этой части:
рисовка сторон по точкам:
for (BakedQuad bakedquad : bakedmodel.getQuads(null, null, 0)) {
    worldrenderer.addVertexData(bakedquad.getVertexData());
}
то этот самый bakedquad.getVertexData() возвращает набор int[] в котором первые 3 числа - это позиция точки по осям XYZ, потом 4 позиции это цвет как RGBA. (потом повтор ещё для 3х вершин). Да только я хз как оси шифруются, любое изменение числа влияет на масштаб модели по этой оси.
Вывод: костыль создать не удалось.
 
Последнее редактирование:
25
3
Сам спросил и сам же и ответил

Было 2 проблемы:
1 - Отсутствовал билд текстуры перед вызовом/обработкой готового листа с моделью;
2 - Так как я вызывал рисовку модели из события RenderGameOverlayEvent, то модель выворачивало;

Решения:
I
- класс Параметризации теперь выглядит так:
ParameterizedModel.class:
public class ParameterizedModel {
    
    public int listId;
    public ResourceLocation file;
    public List<String> visibleMeshes;
    public Map<String, String> materialTextures;
    public OBJModel iModel;
    
    public ParameterizedModel(int list, ResourceLocation file, List<String> visibleMeshes, Map<String, String> replacesMaterialTextures) {
        this.listId = list;
        this.file = file;
        this.iModel = null;
        this.visibleMeshes = Lists.<String>newArrayList();
        this.materialTextures = Maps.<String, String>newHashMap();
        if (visibleMeshes!=null && visibleMeshes.size()>0) { this.visibleMeshes = visibleMeshes; }
        if (materialTextures!=null && materialTextures.size()>0) { this.materialTextures = replacesMaterialTextures; }
    }
    
    public boolean equals(Object obj) {
        if (!(obj instanceof ParameterizedModel)) { return false; }
        ParameterizedModel objPM = (ParameterizedModel) obj;
        if (this == objPM) { return true; }
        if (!this.file.equals(objPM.file)) { return false; }
        if (this.visibleMeshes.size()==0 && this.materialTextures.size()==0 && objPM.visibleMeshes.size()==0 && objPM.materialTextures.size()==0) { return true; }
        if (this.visibleMeshes.size()!=objPM.visibleMeshes.size()) {
            if (objPM.visibleMeshes.size()>0) { return false; }
        }
        if (this.visibleMeshes.size()>0 && objPM.visibleMeshes.size()>0) {
            for (String name : this.visibleMeshes) {
                if (!objPM.visibleMeshes.contains(name)) { return false; }
            }
        }
        if (this.materialTextures.size()!=objPM.materialTextures.size()) {
            if (objPM.materialTextures.size()>0) { return false; }
        }
        if (this.materialTextures.size()>0 && objPM.materialTextures.size()>0) {
            for (String name : this.materialTextures.keySet()) {
                if (!objPM.materialTextures.containsKey(name) || !objPM.materialTextures.get(name).equals(this.materialTextures.get(name))) { return false; }
            }
        }    
        return true;
    }
    
}
II - класс загрузки и создания листа отрисованной модели вот:
ModelBuffer.class:
public class ModelBuffer {

    private static List<ParameterizedModel> MODELS = Lists.<ParameterizedModel>newArrayList(); // список параметризированных отрисованных моделей
    private static List<String> NOT_FOUND = Lists.<String>newArrayList(); // список отсутствующих моделей, чтобы не фризить клиент
    
    /** Собственно попытка получить ID листа:
     * @param objModel - ресурс на расположение OBJ модели
     * @param visibleMeshes - список имён мешей/сеток, которые нужно отобразить из модели
     * @param replacesMaterialTextures - карта замены текстур. Ключ-ресурс на текстуру из материала, Значение-новый ресурс текстура
     * @return ID листа для рисовки
     */
    public static int getDisplayList(String objModel, List<String> visibleMeshes, Map<String, String> replacesMaterialTextures) {
        ParameterizedModel model = new ParameterizedModel(-1, new ResourceLocation(objModel), visibleMeshes, replacesMaterialTextures);
        for (ParameterizedModel pm : ModelBuffer.MODELS) {
            if (pm.equals(model)) {
                model = pm;
                break;
            }
        }
        if (model.listId<0 && !ModelBuffer.NOT_FOUND.contains(objModel)) {
            try {
                model.iModel = (OBJModel) OBJLoader.INSTANCE.loadModel(model.file);
                if (model.iModel==null) {
                    LogWriter.error("Error: OBJ model\""+objModel+"\" file not found");
                    ModelBuffer.NOT_FOUND.add(objModel);
                    return -1;
                }
                model.iModel.process(ImmutableMap.of("flip-v", "true"));
                model.listId = GLAllocation.generateDisplayLists(1);
                GlStateManager.glNewList(model.listId, GL11.GL_COMPILE);
                Function<ResourceLocation, TextureAtlasSprite> spriteFunction = location -> {
                    ResourceLocation loc;
                    if (replacesMaterialTextures!=null && replacesMaterialTextures.containsKey(location.toString())) { loc = new ResourceLocation(replacesMaterialTextures.get(location.toString())); }
                    else { loc = location; }
                    TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(loc.toString());
                    return sprite;
                };
                if (model.visibleMeshes==null || model.visibleMeshes.size()==0) { model.visibleMeshes = Lists.<String>newArrayList(model.iModel.getMatLib().getGroups().keySet()); }
                @SuppressWarnings("deprecation")
                OBJBakedModel bakedmodel = (OBJBakedModel) model.iModel.bake(new OBJModel.OBJState(ImmutableList.copyOf(model.visibleMeshes), true), DefaultVertexFormats.ITEM, spriteFunction);
                Tessellator tessellator = Tessellator.getInstance();
                BufferBuilder worldrenderer = tessellator.getBuffer();
                worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.ITEM);
                for (BakedQuad bakedquad : bakedmodel.getQuads(null, null, 0)) {
                    worldrenderer.addVertexData(bakedquad.getVertexData());
                }
                tessellator.draw();
                GlStateManager.glEndList();
                ModelBuffer.MODELS.add(model);
            }
            catch (Exception e) { LogWriter.error("Error create OBJ render list: "+e);}
        }
        if (model.listId==172) { model.listId = -1; }
        return model.listId;
    }

}
III - и остаётся нарисовать эту модель на экране:
в классе событий клиента:
@SubscribeEvent
public void npcRenderOverlay(RenderGameOverlayEvent.Text event) {
    this.mc = Minecraft.getMinecraft();
    this.sw = new ScaledResolution(this.mc);
    if (this.mc.currentScreen!=null && !(this.mc.currentScreen instanceof GuiChat)) { return; }

    GlStateManager.pushMatrix();
    GlStateManager.translate(this.sw.getScaledWidth_double()/2.0d, this.sw.getScaledHeight_double()/2.0d, 0.0f); // Отображение в центре экрана
    Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); // бинд текстуры
    GlStateManager.scale(-1.0f, -1.0f, -1.0f); // вывернуть модель обратно
    // Всякие манипуляции для отображения
    GlStateManager.scale(50.0f, 50.0f, 50.0f); // размер
    GlStateManager.translate(-0.5f, 0.0f, -0.5f); // смещение от центра модели
    GlStateManager.rotate(90, 0.0f, 1.0f, 0.0f); // повернуть, дабы сбоку виднее
    GlStateManager.callList(ModelBuffer.getDisplayList("customnpcs:models/block/obj/npcmobcloner.obj", null, null)); // получение и рисовка модели
    GlStateManager.popMatrix();
}

Если альтернативы не появится в ближайшие пару дней, тему закрою :p
Итого вот что у меня получилось:
1681982220261.png
 
25
3
Однако проблема.
Чтобы отрисовать модель правильно, всё же необходимо включить глубину и настроить освещённость модели.
Иначе она похоже на плоское пятно.
Для этого:
добавить:
// перед вызовом листа:
GlStateManager.enableDepth();
RenderHelper.enableStandardItemLighting();
// после вызова листа:
GlStateManager.disableDepth();
RenderHelper.disableStandardItemLighting();
Вот только модель словно в тёмной пещере.

Кто-нибудь знает как её осветить?
 
1,038
57
229
Лайтмапа в майне есть
типо Minecraft.getMinecraft.entityRender.enableLightmap()?

или такое? Opengl Fixed Function Pipeline или как перенести освещение в шейдер
На сколько я помню в minecraft у каждого блока есть освещённость (на сколько далеко или там какой цвет у блока). Как я понял из описания люди берут 4 точки чтобы на каждую сторону иметь цвет.
По второй ссылке там просто более элегантное решение через шейдер

но само слово lightmap означает немного другие вещи, это запеченная текстура света и тени в кубомапу (cubemap) или каскадные тени(плоская Plane текстура).
Поэтому,
сетнешь координаты на 240 там и всо
я так и не понял о чём ты.
 
25
3
И так:
  • enableLightmap(); для RenderGameOverlayEvent уже активиронан
  • OpenGlHelper.setLightmapTextureCoords(id, u, v); затея интересная и модель становится светлее (ненамного), но всё ещё то же пятно.

Есть предположение, что модель вызванная моим способом отрисовывается по координатам 0,0,0 (т.е. в жж мира, где 100% темно ибо бедрок) после чего выводится на экран в указанном мною месте. Но глубины всё же не видно.

т.е. надо как-то отрисовать модель по позиции игрока, а уже после выводить её на экран.1682317841108.png
интересно если модель рисуется в 0,0,0 - у неё всё равно должно быть видно глубину по граням или хз....
 
25
3
Если взять мой код рисовки модели и прикрутить её скажем к рендору сущности:
событие:
@SubscribeEvent
public void testPostRenderLivingEvent(RenderLivingEvent.Post<EntityLivingBase> event) {
    double x = event.getX(), y = event.getY(), z = event.getZ();
    GlStateManager.pushMatrix();
    GlStateManager.translate(x, y + event.getEntity().height + 0.6, z);
    GlStateManager.rotate((System.currentTimeMillis()%2000)/(2000.0f/360.0f), 1.0f, 0.0f, 0.0f);
    this.mc.renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
    GlStateManager.callList(ModelBuffer.getDisplayList("modid:models/util/compass.obj", null, null));
    GlStateManager.popMatrix();
}

То модель рисуется правильно, с глубиной, освещенностью и прочим настройкам положения солнца/луны и освещённостью блока:
1682318548116.png

Да только отрисовать её охота на экране игрока, а не над бошкой сущности.

Может проще использовать другое событие рендера, но какое?
 
25
3
Поползав по гайдам Ивасиков пришёл к выводу:
рисовка модели из RenderGameOverlayEvent:
GlStateManager.pushMatrix();
GlStateManager.translate(uvPos[0], uvPos[1], 0.0d);
GlStateManager.scale(-1.0f, -1.0f, -1.0f);
GlStateManager.rotate(-45.0f, 1.0f, 0.0f, 0.0f);
GlStateManager.enableDepth();
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
GlStateManager.enableRescaleNormal();
GlStateManager.enableLighting();
RenderHelper.enableStandardItemLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240.0f, 240.0f);
GlStateManager.callList(ModelBuffer.getDisplayList("modid:models/util/compass.obj", Lists.<String>newArrayList("body"), null));
GlStateManager.disableRescaleNormal();
GlStateManager.disableLighting();
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
GlStateManager.enableBlend();
GlStateManager.disableDepth();
GlStateManager.popMatrix();
получается как надо:
1682326415553.png
может есть способ сделать модель светлее?
 
1,038
57
229
может есть способ сделать модель светлее?
есть, текстуру осветлить. Ты посмотри внимательно, белый якробелым, чёрный чёрным. Всё идеально. Не такой мягкий свет, но раз ты до сих пор не используешь шейдер то видимо лучше не будет.
без шуток, это шедевр, ради этого стоило учить моды и помогать другим (хотя конкретно тебе я тебе мало чем помог).
1682333148064.png
 
25
3
Все высказывания в данной теме мне помогли найти нужное направление для решения. А то я думал о синем, когда дело в красном :)

Цвет в текстурах/материалах не то решение, которое тут нужно. Всё дело оказалось в этой штуке:
GlStateManager.scale(-1.0f, -1.0f, -1.0f);
она нужна чтобы вывернуть модель в норм состояние, но так же она выворачивает и освещение модели.

В итоге я в пред матрице провожу все махинации со смещением, масштабированием и вращениями, после чего рисую новую матрицу, в которой задаю освещение и вызываю лист.
Так что теперь модель отображается там где я хотел, и как хотел.

Один минус, карта текстур блоков не содержит кастомные ресурсы(текстуры), так что код пока подходит только для тех текстур, которые загрузились во время запуска игры. Но я думаю и с этим можно справиться.

Над модификацией я ещё работаю, но код уже можно отыскать вот тута:
Тему можно закрывать.
 
25
3
Касательно кастомных текстур:
1 - Попытки, используя доступные методы регистрации и создания TextureMap после запуска Minecraft, привели к смещению всех текстур блоков, так как новые текстуры заливаются в начало карты, а игра уже запомнила позиции текстур блоков;
2 - Писать собственные методы на запись кастомных текстур в конец карты привели к тонне разнообразных ошибок, т.к. некоторые текстуры могут быть анимированы, да и приходится манипулировать с большим числом приватных финальных переменных;
3 - Но и тут нашёлся выход. В файл-модель (assets/modid/models/block.json) одного из созданных модом блоков в лист с именем "textures" я дописал строчные элементы с путями до необходимых мне текстур на вроде:
файл модели блока:
"custom_0": "modid:texture_path_0",
"custom_1": "modid:texture_path_1",
// ...
"custom_N": "modid:texture_path_N"
что заставляет игру загрузить эти текстуры при запуске, а значит больше нет никаких проблем :)

Как итог, я смог собрать квестовый компас во одной модели, который показывает направление до места выполнения задачи, вид задачи, мини описание, направление сторон света (всё это относительно положения и камеры игрока), а так же и высоту до места.
+ стрелка пропадает в зоне поиска решения задачи (в ванильном компасе стрелка крутится).
Можно будет настроить положение на экране, размер и наклон компаса:
1682586971705.png

Костыли рулят!
 
Последнее редактирование:
Сверху