- Версия(и) Minecraft
- 1.12+
Всем привет.
В новых версиях нельзя на прямую взаимодействовать с opengl для рендера обычных блоков и предметов. Поэтому приходится изворачиваться, чтобы получить некоторые возможности. В том числе и бленд(наложение) текстур.
Для чего это нужно?
Самый простой пример - руды. Как фон можно использовать стандартную текстуру камня, а накладывать уже вкрапления ресурсов.
Чем полезно?
Проще рисовать отдельные части текстур, чем сначала искать фон, а потом в графическом редакторе накладывать остальные части. При ресурспаке фоны ваших текстур будут соответствовать текстурам из текстурпака.
Как использовать?
Для начала нужно прочитать этот туториал. И вместо обычной текстурки вернуть эту:
Ну и не забываем регистрировать наши текстутк . Я это делаю так
Теперь при создании любой смешанной текстурки помещаем её в список, и готово!
Ну и регистриуем наш обработчик событий.
Получаем в итоге
В новых версиях нельзя на прямую взаимодействовать с opengl для рендера обычных блоков и предметов. Поэтому приходится изворачиваться, чтобы получить некоторые возможности. В том числе и бленд(наложение) текстур.
Для чего это нужно?
Самый простой пример - руды. Как фон можно использовать стандартную текстуру камня, а накладывать уже вкрапления ресурсов.
Чем полезно?
Проще рисовать отдельные части текстур, чем сначала искать фон, а потом в графическом редакторе накладывать остальные части. При ресурспаке фоны ваших текстур будут соответствовать текстурам из текстурпака.
Как использовать?
Для начала нужно прочитать этот туториал. И вместо обычной текстурки вернуть эту:
Java:
public class MultiTextureAtlasSprite extends TextureAtlasSprite
{
private ResourceLocation texture1;
private ResourceLocation texture2;
private ImmutableList<ResourceLocation> dependencies;
/**
* @param texture1 фон
* @param texture2 накладываемая сверху текстура
**/
public MultiTextureAtlasSprite(ResourceLocation texture1, ResourceLocation texture2) {
super(texture1.toString().concat("_".concat(texture2.toString())));
this.texture1 = texture1;
this.texture2 = texture2;
dependencies = ImmutableList.of(this.texture1, this.texture2);
}
@Override
public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location) {
return true;
}
@Override
public Collection<ResourceLocation> getDependencies() {
return dependencies;
}
@Override
public boolean load(IResourceManager manager, ResourceLocation location, Function<ResourceLocation, TextureAtlasSprite> textureGetter) {
//получаем текстуры по отдельности
TextureAtlasSprite sprite = textureGetter.apply(texture1);
TextureAtlasSprite mappingSprite = textureGetter.apply(texture2);
width = sprite.getIconWidth();
height = sprite.getIconHeight();
int[][] pixels = new int[Minecraft.getMinecraft().gameSettings.mipmapLevels + 1][];
//кол-во пикселей в новой текстуре
pixels[0] = new int[width * height];
//получаем пиксели 1 текстуры
int[][] oldPixels = sprite.getFrameTextureData(0);
//получаем пиксели 2 текстуры
int[][] alphaPixels = mappingSprite.getFrameTextureData(0);
for (int p = 0; p < width * height; p++) {
//достаем альфу из значения пикселя(каждый цвет обозначается 8 битами)
int oldPixelAlpha = alphaPixels[0][p] >>> 24;
//Проверяем, пустой ли пиксель?
if (oldPixelAlpha > 0)
//если не пустой, то сетаем пиксель 2 текстурки в новую
pixels[0][p] = alphaPixels[0][p];
else
//если пустой, то сетаем пиксель 1 текстурки в новую
pixels[0][p] = oldPixels[0][p];
}
//очищаем предыдущие пиксели, которые могли остаться при перезагрузке текстур
this.clearFramesTextureData();
//добавляем свои
this.framesTextureData.add(pixels);
//возвращаем false, чтобы наш TextureAtlasSprite не загружался обычным способом
return false;
}
}
Java:
public class TextureEventHandler {
private static List<TextureAtlasSprite> textureAtlasSprites = new ArrayList<>();
@SubscribeEvent
public void event(TextureStitchEvent.Pre event) {
for (TextureAtlasSprite sprite : textureAtlasSprites)
event.getMap().setTextureEntry(sprite);
}
public static void registerSprite(TextureAtlasSprite textureAtlasSprite){
textureAtlasSprites.add(textureAtlasSprite);
}
}
Ну и регистриуем наш обработчик событий.
Java:
public class OreModel implements IModel {
ResourceLocation texture;
public static ResourceLocation rockTexture = new ResourceLocation("blocks/stone");
MultiTextureAtlasSprite spriteOre;
public OreModel(ResourceLocation texture) {
this.texture=texture;
spriteOre = new MultiTextureAtlasSprite(rockTexture, texture);
TextureEventHandler.registerSprite(spriteOre);
}
@Override
public IModel smoothLighting(boolean value) {
return new OreModel(texture);
}
@Override
public Collection<ResourceLocation> getTextures() {
return Collections.singletonList(texture);
}
@Override
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter) {
ModelBaker baker = ModelBaker.INSTANCE;
baker.begin(state, format);
baker.setTexture(spriteOre);
baker.putCube(0,0,0,0.5f, spriteOre.getMaxU(), spriteOre.getMinU(), spriteOre.getMinV(), spriteOre.getMaxV());
return new OreBakedModel(baker.bake(), bakedTextureGetter.apply(rockTexture));
}
}
Java:
public class OreBakedModel implements IBakedModel {
List<BakedQuad> quads;
TextureAtlasSprite textureAtlasSprite;
public OreBakedModel(List<BakedQuad> quads, TextureAtlasSprite textureAtlasSprite){
this.quads = quads;
this.textureAtlasSprite = textureAtlasSprite;
}
@Override
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) {
return quads;
}
@Override
public boolean isAmbientOcclusion() {
return true;
}
@Override
public boolean isGui3d() {
return true;
}
@Override
public boolean isBuiltInRenderer() {
return false;
}
@Override
public TextureAtlasSprite getParticleTexture() {
return textureAtlasSprite;
}
@Override
public ItemOverrideList getOverrides() {
return ItemOverrideList.NONE;
}
ItemTransformVec3f firstperson_righthand = new ItemTransformVec3f(new Vector3f(0,45,0), new Vector3f(0, 0, 0), new Vector3f(0.40f, 0.40f, 0.40f));
ItemTransformVec3f firstperson_lefthand = new ItemTransformVec3f(new Vector3f(0,225,0), new Vector3f(0, 0, 0), new Vector3f(0.40f, 0.40f, 0.40f));
ItemTransformVec3f thirdperson_righthand = new ItemTransformVec3f(new Vector3f(75,45,0), new Vector3f(0, 0.15f, 0), new Vector3f(0.375f, 0.375f, 0.375f));
private ItemTransformVec3f fixed = new ItemTransformVec3f(new Vector3f(0,0,0), new Vector3f(0, 0, 0), new Vector3f(0.5f, 0.5f, 0.5f));
private ItemTransformVec3f ground = new ItemTransformVec3f(new Vector3f(0,0,0), new Vector3f(0, 0.15f, 0), new Vector3f(0.25f, 0.25f, 0.25f));
private ItemTransformVec3f gui = new ItemTransformVec3f(new Vector3f(30,225,0), new Vector3f(0, 0, 0), new Vector3f(0.625f, 0.625f, 0.625f));
private ItemCameraTransforms itemCameraTransforms = new ItemCameraTransforms(thirdperson_righthand, thirdperson_righthand,
firstperson_lefthand, firstperson_righthand,
ItemTransformVec3f.DEFAULT, gui, ground, fixed);
@Override
public ItemCameraTransforms getItemCameraTransforms() {
return itemCameraTransforms;
}
}