PoC Life
-
Автор темы
- #1
Перед прочтением основного контента ниже, пожалуйста, обратите внимание на обновление внутри секции Майна на нашем форуме. У нас появились:
- бесплатные читы для Майнкрафт — любое использование на свой страх и риск;
- маркетплейс Майнкрафт — абсолютно любая коммерция, связанная с игрой, за исключением продажи читов (аккаунты, предоставления услуг, поиск кодеров читов и так далее);
- приватные читы для Minecraft — в этом разделе только платные хаки для игры, покупайте группу "Продавец" и выставляйте на продажу свой софт;
- обсуждения и гайды — всё тот же раздел с вопросами, но теперь модернизированный: поиск нужных хаков, пати с игроками-читерами и другая полезная информация.
Спасибо!
Список:
1. Создаём главный класс + снимаем ограничения - https://yougame.biz/threads/325113
2. Автобус евентов - https://yougame.biz/threads/325114
3. OpenGL + Шейдеры + Рендер - https://yougame.biz/threads/325115
4. Аим - https://yougame.biz/threads/325188
5. GlowESP aka OpenGL Framebuffer - https://yougame.biz/threads/325211/
6. Текст, шрифты, атлас - https://yougame.biz/threads/325292
Есть много вариаций как делать эти шрифты, сглаживать их, например: MisterL_43123 рассказал о MSDF (https://yougame.biz/threads/301776). Лично я опять же расскажу самый популярный способ в читах на текущий момент.
Начнём с того, что мы будем использовать java.awt - библиотека, входящая в jdk, отвечающая за рендер. У неё также есть свой враппер javax.swing, но его мы не затрагиваем.
Текстурный атлас
Начнём с того, что шрифт - грубо говоря это текстура. Но не могу же я генерировать триллиард текстур под каждую буковку, шрифт с опред. размером? Поэтому мы будем использовать одну огромную картинку - текстурный атлас, где одна картинка поделена на подкартинки, которые в дальнейшем можно извлекать используя UV. UV - это обычные нормализованные координаты (от 0 до 1).
Допустим есть такая картинка:
Давайте попробуем нарисовать не всю её, а только нижнюю левую "плиточку". Для этого высчитаем UV:
u = x / размер картинки
v = y / размер картинки
И затем отрисуем (не хочу дублировать код, поэтому читайте ниже, там будет где я использую uv)
Практика
Делать такие атласы мы естественно будем автоматом, для этого у нас есть BufferedImage и Graphics2D для отрисовки.
Но для начала нужно получить шрифт (обратите внимание, что я использовал конструкцию try для автоматического закрытия InputStream):
После этого создаём картинку:
Чтобы шрифты не были пиксельными (alias), нужно использовать antialiasing, он уже идёт из коробки:
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Также можно включить
Далее я создам класс Glyph с информацией о символе где я сохраню uv и размер:
Далее наносим необходимые символы на картинку:
Про asecnt и descent можно увидеть здесь:
В итоге можно посмотреть результат через ImageIO.write:
Далее необходимо создать OpenGL текстуру и записать туда информацию о цветах всех пикселей:
Теперь у нас есть OpenGL текстура и информация о каждом символе. Давайте создадим метод отрисовки строки:
Усё:
1. Создаём главный класс + снимаем ограничения - https://yougame.biz/threads/325113
2. Автобус евентов - https://yougame.biz/threads/325114
3. OpenGL + Шейдеры + Рендер - https://yougame.biz/threads/325115
4. Аим - https://yougame.biz/threads/325188
5. GlowESP aka OpenGL Framebuffer - https://yougame.biz/threads/325211/
6. Текст, шрифты, атлас - https://yougame.biz/threads/325292
Есть много вариаций как делать эти шрифты, сглаживать их, например: MisterL_43123 рассказал о MSDF (https://yougame.biz/threads/301776). Лично я опять же расскажу самый популярный способ в читах на текущий момент.
Начнём с того, что мы будем использовать java.awt - библиотека, входящая в jdk, отвечающая за рендер. У неё также есть свой враппер javax.swing, но его мы не затрагиваем.
Текстурный атлас
Начнём с того, что шрифт - грубо говоря это текстура. Но не могу же я генерировать триллиард текстур под каждую буковку, шрифт с опред. размером? Поэтому мы будем использовать одну огромную картинку - текстурный атлас, где одна картинка поделена на подкартинки, которые в дальнейшем можно извлекать используя UV. UV - это обычные нормализованные координаты (от 0 до 1).
Допустим есть такая картинка:
Давайте попробуем нарисовать не всю её, а только нижнюю левую "плиточку". Для этого высчитаем UV:
u = x / размер картинки
v = y / размер картинки
И затем отрисуем (не хочу дублировать код, поэтому читайте ниже, там будет где я использую uv)
Практика
Делать такие атласы мы естественно будем автоматом, для этого у нас есть BufferedImage и Graphics2D для отрисовки.
Но для начала нужно получить шрифт (обратите внимание, что я использовал конструкцию try для автоматического закрытия InputStream):
Java:
try (FileInputStream inputStream = new FileInputStream("путь/до/шрифта")) {
Font font = Font.createFont(Font.PLAIN, inputStream);
font = font.deriveFont(Font.PLAIN, размер);
}
Java:
BufferedImage image = new BufferedImage(512, 512, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = image.createGraphics();
graphics.setColor(new Color(0, 0, 0, 0));
graphics.fillRect(0, 0, 512, 512);
graphics.dispose();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Также можно включить
Пожалуйста, авторизуйтесь для просмотра ссылки.
.Далее я создам класс Glyph с информацией о символе где я сохраню uv и размер:
Java:
public class Glyph {
private final int width, height;
private final float u, v;
public Glyph(int width, int height, float u, float v) {
this.width = width;
this.height = height;
this.u = u;
this.v = v;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public float getU() {
return u;
}
public float getV() {
return v;
}
}
Java:
Glyph glyphs[1300];
FontMetrics fontMetrics = graphics.getFontMetrics(); // Получаем информацию о metrics
int x = 0;
int y = 0;
for (int i = 0; i < glyphs.length; i++) {
char character = (char) i;
// Фильтрация ненужных символов
if (character < '!')
continue;
if (character > '~' && character < 1040) // 1040 - Русская А
continue;
Rectangle2D size = fontMetrics.getStringBounds(String.valueOf(character), graphics); // Получаем размеры символа
int width = size.getBounds().width + 5; // 5 - расстояние между символами, а то чё они впритык ебать будут
int height = size.getBounds().height;
if (x + width >= 512) { // Если x вышел за пределы размера картинки
x = 0;
y += height + fontMetrics.getDescent(); // То перемещаемся ниже
}
Glyph glyph = new Glyph(width, height, x / 512.0f, y / 512.0f);
glyphs[i] = glyph; // Устанавливаем информацию для символа в массив
graphics.drawString(String.valueOf(character), x, y + fontMetrics.getAscent()); // Рисуем символ (в данном случае целую строку из одного символа)
x += glyph.getWidth() + 5; // Между символами создадим небольшой отступ
}
В итоге можно посмотреть результат через ImageIO.write:
Далее необходимо создать OpenGL текстуру и записать туда информацию о цветах всех пикселей:
Java:
int[] pixels = image.getRGB(0, 0, 512, 512, null, 0, 512);
ByteBuffer byteBuffer = BufferUtils.createByteBuffer(pixels.length * 4); // Создаём буффер цветов rgba
for (int color : pixels) {
byteBuffer.put((byte) ((color >> 16) & 0xFF)); // r
byteBuffer.put((byte) ((color >> 8) & 0xFF)); // g
byteBuffer.put((byte) (color & 0xFF)); // b
byteBuffer.put((byte) ((color >> 24) & 0xFF)); // b
}
byteBuffer.flip();
int textureID = GlStateManager.genTexture(); // Создаём новую текстуру
GlStateManager.bindTexture(textureID);
GlStateManager.texParameter(GL30.GL_TEXTURE_2D, GL30.GL_TEXTURE_MIN_FILTER, GL30.GL_LINEAR);
GlStateManager.texParameter(GL30.GL_TEXTURE_2D, GL30.GL_TEXTURE_MAG_FILTER, GL30.GL_LINEAR);
GL30.glTexImage2D(GL30.GL_TEXTURE_2D, 0, GL30.GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL30.GL_RGBA, GL30.GL_UNSIGNED_BYTE, byteBuffer); // Заполняем текстуру информацией о цветах
GlStateManager.bindTexture(0);
Java:
GlStateManager.bindTexture(textureID);
for (char character : text.toCharArray()) {
if (character >= glyphs.length) // Если вдруг случайно захотели нарисовать экзотический символ, которого нету в массиве :)
continue;
Glyph glyph = glyphs[character];
float u = glyph.getU();
float v = glyph.getV();
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder builder = tessellator.getBuffer();
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
builder.pos(x, y, 0).tex(u, v).endVertex();
builder.pos(x, y + glyph.getHeight(), 0).tex(u, v + glyph.getHeight() / 512.0f).endVertex();
builder.pos(x + glyph.getWidth(), y + glyph.getHeight(), 0).tex(u + glyph.getWidth() / 512.0f, v + glyph.getHeight() / 512.0f).endVertex();
builder.pos(x + glyph.getWidth(), y, 0).tex(u + glyph.getWidth() / 512.0f, v).endVertex();
tessellator.draw();
x += glyph.getWidth() - 5; // Не забываем вычесть отступ
}
GlStateManager.bindTexture(0);
Последнее редактирование: