Необходимо создать класс для применения размытия с...
Erstellt am: 20. Februar 2025
Erstellt am: 20. Februar 2025
Необходимо создать класс для применения размытия с использованием предоставленных шейдеров. В качестве примера, я предоставлю класс KawaseBlur, чтобы вы лучше поняли структуру проекта.
Создайте новый класс для размытия, используя предоставленные шейдеры.
Убедитесь, что новый класс соответствует структуре проекта.
Используйте класс KawaseBlur в качестве примера для создания нового класса. вот шейдеры package cc.luminous.utils.shader.shaders;
import cc.luminous.utils.shader.IShader;
public class BlurUp implements IShader {
text@Override public String glsl() { return """ #version 120 uniform sampler2D image; uniform float offset; uniform vec2 resolution; void main() { vec2 uv = gl_TexCoord[0].xy / 2.0; vec2 halfpixel = resolution / 2.0; vec3 sum = texture2D(image, uv + vec2(-halfpixel.x * 2.0, 0.0) * offset).rgb; sum += texture2D(image, uv + vec2(-halfpixel.x, halfpixel.y) * offset).rgb * 2.0; sum += texture2D(image, uv + vec2(0.0, halfpixel.y * 2.0) * offset).rgb; sum += texture2D(image, uv + vec2(halfpixel.x, halfpixel.y) * offset).rgb * 2.0; sum += texture2D(image, uv + vec2(halfpixel.x * 2.0, 0.0) * offset).rgb; sum += texture2D(image, uv + vec2(halfpixel.x, -halfpixel.y) * offset).rgb * 2.0; sum += texture2D(image, uv + vec2(0.0, -halfpixel.y * 2.0) * offset).rgb; sum += texture2D(image, uv + vec2(-halfpixel.x, -halfpixel.y) * offset).rgb * 2.0; gl_FragColor = vec4(sum / 12.0, 1); } """; }
}
package cc.luminous.utils.shader.shaders;
import cc.luminous.utils.shader.IShader;
public class BlurDown implements IShader {
text@Override public String glsl() { return """ #version 120 uniform sampler2D image; uniform float offset; uniform vec2 resolution; void main() { vec2 uv = gl_TexCoord[0].xy * 2.0; vec2 halfpixel = resolution * 2.0; vec3 sum = texture2D(image, uv).rgb * 4.0; sum += texture2D(image, uv - halfpixel.xy * offset).rgb; sum += texture2D(image, uv + halfpixel.xy * offset).rgb; sum += texture2D(image, uv + vec2(halfpixel.x, -halfpixel.y) * offset).rgb; sum += texture2D(image, uv - vec2(halfpixel.x, -halfpixel.y) * offset).rgb; gl_FragColor = vec4(sum / 8.0, 1); } """; }
}
и класс kawase как пример package cc.luminous.utils.render;
import cc.luminous.utils.CustomFramebuffer;
import cc.luminous.utils.shader.ShaderUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.shader.Framebuffer;
public class KawaseBlur {
textpublic static KawaseBlur blur = new KawaseBlur(); public final CustomFramebuffer BLURRED; public final CustomFramebuffer ADDITIONAL; CustomFramebuffer blurTarget = new CustomFramebuffer(false).setLinear(); public KawaseBlur() { BLURRED = new CustomFramebuffer(false).setLinear(); ADDITIONAL = new CustomFramebuffer(false).setLinear(); } public void render(Runnable run) { Stencil.initStencilToWrite(); run.run(); Stencil.readStencilBuffer(1); BLURRED.draw(); Stencil.uninitStencilBuffer(); } public void updateBlur(float offset, int steps) { Minecraft mc = Minecraft.getInstance(); Framebuffer mcFramebuffer = mc.getFramebuffer(); ADDITIONAL.setup(); mcFramebuffer.bindFramebufferTexture(); ShaderUtil.kawaseDown.attach(); ShaderUtil.kawaseDown.setUniform("offset", offset); ShaderUtil.kawaseDown.setUniformf("resolution", 1f / mc.getMainWindow().getWidth(), 1f / mc.getMainWindow().getHeight()); CustomFramebuffer.drawTexture(); CustomFramebuffer[] buffers = {this.ADDITIONAL, this.BLURRED }; for (int i = 1; i < steps; ++i) { int step = i % 2; buffers[step].setup(); buffers[(step + 1) % 2].draw(); } ShaderUtil.kawaseUp.attach(); ShaderUtil.kawaseUp.setUniform("offset", offset); ShaderUtil.kawaseUp.setUniformf("resolution", 1f / mc.getMainWindow().getWidth(), 1f / mc.getMainWindow().getHeight()); for (int i = 0; i < steps; ++i) { int step = i % 2; buffers[(step + 1) % 2].setup(); buffers[step].draw(); } ShaderUtil.kawaseUp.detach(); mcFramebuffer.bindFramebuffer(false); }
}
пиши полный код без примеров напиши шедевр
javapackage cc.luminous.utils.render; import cc.luminous.utils.CustomFramebuffer; import cc.luminous.utils.shader.ShaderUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.shader.Framebuffer; import org.lwjgl.opengl.GL11; /** * Мастер-класс размытия на основе BlurDown и BlurUp шейдеров. * Структура повторяет KawaseBlur, но использует предоставленные шейдеры BlurUp и BlurDown. */ public class BlurShaderMaster { /** Единственный экземпляр (Singleton), позволяющий обращаться к BlurShaderMaster напрямую. */ public static final BlurShaderMaster INSTANCE = new BlurShaderMaster(); /** * Основной фреймбуфер, в котором хранится результат (размытие). * Может использоваться при отрисовке и наложении размытого изображения. */ private final CustomFramebuffer blurredFramebuffer; /** * Дополнительный фреймбуфер, используемый для промежуточных вычислений. */ private final CustomFramebuffer additionalFramebuffer; /** * Ещё один вспомогательный фреймбуфер (по аналогии с KawaseBlur). * Позволяет переключаться между несколькими буферами по очереди * и получать более гибкие варианты размытия. */ private final CustomFramebuffer blurTarget; /** * Конструктор, инициализирующий фреймбуферы для размытия. * Устанавливается линейная фильтрация (setLinear()), чтобы сгладить результат. */ public BlurShaderMaster() { this.blurredFramebuffer = new CustomFramebuffer(false).setLinear(); this.additionalFramebuffer = new CustomFramebuffer(false).setLinear(); this.blurTarget = new CustomFramebuffer(false).setLinear(); } /** * Метод для рендера с использованием трафарета (Stencil), * чтобы затем применить размытие только к нужной области. * * @param drawTarget код отрисовки фигур/элементов, которые нужно размыть. */ public void render(Runnable drawTarget) { // Инициализация буфера трафарета (Stencil) для записи. Stencil.initStencilToWrite(); // Выполняем пользовательскую отрисовку (ту, что хотим размыть). drawTarget.run(); // Переключаемся на чтение из буфера трафарета. Stencil.readStencilBuffer(1); // Рисуем результат (из последнего активного фреймбуфера) на экран. blurredFramebuffer.draw(); // Отключаем использование трафарета. Stencil.uninitStencilBuffer(); } /** * Основной метод для пошагового расчёта размытия. * Схож с KawaseBlur, но использует шейдеры BlurDown и BlurUp. * * @param offset Насколько сильно "разносится" размытие. * @param steps Количество шагов (итераций) размытия. */ public void updateBlur(float offset, int steps) { Minecraft mc = Minecraft.getInstance(); Framebuffer mcFramebuffer = mc.getFramebuffer(); // Получаем разрешение окна, чтобы корректно вычислять uniform-параметры. float width = mc.getMainWindow().getWidth(); float height = mc.getMainWindow().getHeight(); // Подготавливаем дополнительный фреймбуфер и рендерим в него содержимое экрана. additionalFramebuffer.setup(); mcFramebuffer.bindFramebufferTexture(); // Запускаем шейдер BlurDown. ShaderUtil.blurDown.attach(); ShaderUtil.blurDown.setUniform("offset", offset); ShaderUtil.blurDown.setUniformf("resolution", 1f / width, 1f / height); // Рисуем текстуру (с экрана) в additionalFramebuffer с учётом BlurDown. CustomFramebuffer.drawTexture(); // Готовим массив для переключения между двумя буферами по аналогии с KawaseBlur. CustomFramebuffer[] buffers = { additionalFramebuffer, blurredFramebuffer }; // Делаем несколько проходов (steps - 1 раз BlurDown). for (int i = 1; i < steps; i++) { int step = i % 2; buffers[step].setup(); buffers[(step + 1) % 2].draw(); } // После проходов BlurDown — переключаемся на BlurUp. ShaderUtil.blurUp.attach(); ShaderUtil.blurUp.setUniform("offset", offset); ShaderUtil.blurUp.setUniformf("resolution", 1f / width, 1f / height); // Проходим столько же раз шейдером BlurUp. for (int i = 0; i < steps; i++) { int step = i % 2; buffers[(step + 1) % 2].setup(); buffers[step].draw(); } // Отключаем шейдер и возвращаем рендер в основной буфер. ShaderUtil.blurUp.detach(); mcFramebuffer.bindFramebuffer(false); } /** * Возвращает фреймбуфер с итоговым размытием. Можно дополнительно * использовать его для наложения на интерфейс или игровую сцену. */ public CustomFramebuffer getBlurredFramebuffer() { return blurredFramebuffer; } /** * Возвращает дополнительный фреймбуфер, в котором происходит часть промежуточных вычислений. */ public CustomFramebuffer getAdditionalFramebuffer() { return additionalFramebuffer; } /** * Возвращает ещё один вспомогательный фреймбуфер (используется при необходимости). */ public CustomFramebuffer getBlurTarget() { return blurTarget; } }
Краткое описание работы класса:
Конструктор создаёт три объекта CustomFramebuffer
:
blurredFramebuffer
— для итогового размытого изображения,additionalFramebuffer
— для промежуточных вычислений,blurTarget
— дополнительный буфер (по аналогии с KawaseBlur).Метод render
:
blurredFramebuffer
,Метод updateBlur
:
mcFramebuffer
),additionalFramebuffer
через шейдер BlurDown
,steps
), переключаясь между blurredFramebuffer
и additionalFramebuffer
,BlurUp
, снова переключаясь между буферами,Таким образом, вы получаете мощное размытие, используя отдельные шейдеры BlurDown
и BlurUp
. Код организован аналогично KawaseBlur
, но заменяет логику на новые шейдеры, которые вы предоставили.
сделай чтобы под белым прямоугольником был блюр используя наш класс void renderBackground(MatrixStack matrixStack, float x, float y, float width, float height, int mouseX, int mouseY) {
DisplayUtils.drawRoundedRect(x, y, width, height, new Vector4f(4, 4, 4, 4), new Color(18, 16, 14).getRGB());
textDisplayUtils.drawRoundedRect(x, y, width, 64 / 2f, new Vector4f(6, 0, 6, 0), new Color(255, 255, 255,150).getRGB()); }
Ниже приведён пример того, как можно нарисовать белый полупрозрачный прямоугольник, под которым будет применяться размытие (используя ваш новый класс для Blur). Идея в том, что мы:
BlurShaderMaster#render
, в который в виде Runnable
передаём отрисовку области, где хотим размыть фон.BlurShaderMaster#updateBlur
, чтобы "применить" размытие.Таким образом, внутри белого прямоугольника будет видно размытие того, что мы отрисовали до шага 2.
javapublic void renderBackground(MatrixStack matrixStack, float x, float y, float width, float height, int mouseX, int mouseY) { // 1. Рисуем тёмный фон (или любую сцену, которую хотим размывать). DisplayUtils.drawRoundedRect(x, y, width, height, new Vector4f(4, 4, 4, 4), new Color(18, 16, 14).getRGB()); // 2. Запускаем запись в буфер размытия. // Всё, что будет нарисовано внутри лямбды (Runnable), попадает в область, которая размоется. BlurShaderMaster.INSTANCE.render(() -> { // Здесь задаём форму, которая должна размазывать фон. // Проще говоря, рисуем "трафарет" размытия. // Цвет можно сделать полным белым или любым другим: DisplayUtils.drawRoundedRect(x, y, width, 64 / 2f, // высота нашего белого прямоугольника new Vector4f(6, 0, 6, 0), 0xFFFFFFFF); // полностью белый (для стэнсила) }); // 3. Теперь проводим реальное размытие (количество шагов и сила задаются параметрами). BlurShaderMaster.INSTANCE.updateBlur(3.0f, 4); // 4. Рисуем сам белый прямоугольник с нужным альфа-значением (прозрачностью). // Этот прямоугольник будет "сверху", а под ним уже будет видно размытое изображение. DisplayUtils.drawRoundedRect(x, y, width, 64 / 2f, new Vector4f(6, 0, 6, 0), new Color(255, 255, 255, 150).getRGB()); }
Фоновая сцена. Всё, что нарисовано до момента вызова BlurShaderMaster.INSTANCE.render(...)
, будет потенциально видно на экране и может участвовать в размытии.
render(Runnable)
. Этот вызов включает использование трафарета (Stencil) внутри, куда записывается форма, по которой потом применяется размытие. В нашем случае это прямоугольник с закруглёнными углами.
updateBlur(offset, steps)
. После записи формы в трафарет идёт серия проходов шейдеров BlurDown
и BlurUp
. Чем больше steps
и offset
, тем сильнее визуально размытие.
Прямоугольник поверх. Завершающий шаг — рисуем сам белый полупрозрачный прямоугольник (с использованием альфа-канала, например 150 из 255), под которым уже окажется размытый фон.
Таким образом, вы получаете красивый размазанный задник (фон) только в области белого прямоугольника.
а сделай так чтобы панель на кототорой блюр рендерилась не на черном прямоугольнике короче просто отдели ее @Override
public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
super.render(matrixStack, mouseX, mouseY, partialTicks);
this.minecraft.keyboardListener.enableRepeatEvents(true);
float scale = 2f;
float width = 900 / scale;
float height = 650 / scale;
float x = MathUtil.calculateXPosition(mc.getMainWindow().scaledWidth() / 2f, width);
float y = MathUtil.calculateXPosition(mc.getMainWindow().scaledHeight() / 2f, height);
xPanel = x;
yPanel = y;
animation = MathUtil.lerp(animation, 0, 5);
textVec2i fixed = ClientUtil.getMouse((int) mouseX, (int) mouseY); mouseX = fixed.getX(); mouseY = fixed.getY(); int finalMouseX = mouseX; int finalMouseY = mouseY; mc.gameRenderer.setupOverlayRendering(2); renderBackground(matrixStack, x, y, width, height, finalMouseX, finalMouseY);
// renderCategories(matrixStack, x, y, width, height, finalMouseX, finalMouseY);
// renderComponents(matrixStack, x, y, width, height, finalMouseX, finalMouseY);
// renderColorPicker(matrixStack, x, y, width, height, finalMouseX, finalMouseY);
// renderSearchBar(matrixStack, x, y, width, height, finalMouseX, finalMouseY);
mc.gameRenderer.setupOverlayRendering();
text} void renderColorPicker(MatrixStack matrixStack, float x, float y, float width, float height, int mouseX, int mouseY) { if (ColorComponent.opened != null) { ColorComponent.opened.draw(matrixStack, mouseX, mouseY); } if (ThemeComponent.selected != null) { ThemeComponent.selected.draw(matrixStack, mouseX, mouseY); } } public void renderBackground(MatrixStack matrixStack, float x, float y, float width, float height, int mouseX, int mouseY) { // 1. Рисуем тёмный фон (или любую сцену, которую хотим размывать).
// DisplayUtils.drawRoundedRect(x, y, width, height,
// new Vector4f(4, 4, 4, 4),
// new Color(18, 16, 14).getRGB());
text// 2. Запускаем запись в буфер размытия. // Всё, что будет нарисовано внутри лямбды (Runnable), попадает в область, которая размоется. BlurShaderMaster.INSTANCE.render(() -> { // Здесь задаём форму, которая должна размазывать фон. // Проще говоря, рисуем "трафарет" размытия. // Цвет можно сделать полным белым или любым другим: DisplayUtils.drawRoundedRect(x, y, width, 64 / 2f, // высота нашего белого прямоугольника new Vector4f(6, 0, 6, 0), 0xFFFFFFFF); // полностью белый (для стэнсила) }); // 3. Теперь проводим реальное размытие (количество шагов и сила задаются параметрами). BlurShaderMaster.INSTANCE.updateBlur(0.0f, 3); // 4. Рисуем сам белый прямоугольник с нужным альфа-значением (прозрачностью). // Этот прямоугольник будет "сверху", а под ним уже будет видно размытое изображение. DisplayUtils.drawRoundedRect(x, y, width, 64 / 2f, new Vector4f(6, 0, 6, 0), new Color(255, 0, 0, 0).getRGB()); }
Чтобы сделать так, чтобы панель с блюром была отделена от черного прямоугольника и не накладывалась на него, можно просто удалить саму часть, которая рисует тёмный прямоугольник. Вместо этого, создаём отдельную панель для размытия, которая будет отрисована отдельно. При этом размытие будет применяться только к панели, а не ко всему фону.
Вот обновлённый код:
java@Override public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { super.render(matrixStack, mouseX, mouseY, partialTicks); this.minecraft.keyboardListener.enableRepeatEvents(true); // Параметры для панели float scale = 2f; float width = 900 / scale; float height = 650 / scale; float x = MathUtil.calculateXPosition(mc.getMainWindow().scaledWidth() / 2f, width); float y = MathUtil.calculateXPosition(mc.getMainWindow().scaledHeight() / 2f, height); xPanel = x; yPanel = y; animation = MathUtil.lerp(animation, 0, 5); Vec2i fixed = ClientUtil.getMouse((int) mouseX, (int) mouseY); mouseX = fixed.getX(); mouseY = fixed.getY(); int finalMouseX = mouseX; int finalMouseY = mouseY; mc.gameRenderer.setupOverlayRendering(2); renderBackground(matrixStack, x, y, width, height, finalMouseX, finalMouseY); mc.gameRenderer.setupOverlayRendering(); } public void renderBackground(MatrixStack matrixStack, float x, float y, float width, float height, int mouseX, int mouseY) { // 1. Сначала рисуем саму панель с блюром (не фон). BlurShaderMaster.INSTANCE.render(() -> { // Здесь рисуем панель, которая будет размыта. DisplayUtils.drawRoundedRect(x, y, width, height, new Vector4f(6, 6, 6, 6), // скругление new Color(255, 255, 255, 100).getRGB()); // полупрозрачная белая панель }); // 2. Запускаем размытие с заданным параметром. BlurShaderMaster.INSTANCE.updateBlur(2.0f, 4); // 3. Рисуем саму панель поверх размытия. // Это будет полупрозрачная белая панель с нужной альфой. DisplayUtils.drawRoundedRect(x, y, width, height, new Vector4f(6, 6, 6, 6), // скругление new Color(255, 255, 255, 150).getRGB()); // более высокая альфа для панели }
Удаление фона. Теперь в renderBackground
не рисуется тёмный прямоугольник, который был в предыдущем примере. Мы делаем панель с блюром отдельно.
Размытие только для панели. В блоке кода, который отвечает за размытие, вызывается BlurShaderMaster.INSTANCE.render
, где рисуется только панель (не фон).
Меньше "перекрытия". Белый прямоугольник, на котором будет отображаться размытие, рисуется с прозрачностью, что позволяет видеть размытие за ним. Оставляем панель как полупрозрачную и даём её рисование поверх размытия.
Теперь панель с размытиями будет отдельно, а не накладываться на фон.
надо чтобы панель на которой был блюр просто рендерилась не на прямоугольнике а отдельно чтобы черный прямоугольник не перекрывал блюр
Ниже приведён пример кода, в котором нет чёрного прямоугольника, а «панель с блюром» рендерится самостоятельно. Таким образом, чёрный прямоугольник не будет перекрывать размытие.
Основная идея:
updateBlur
, чтобы получить желаемую степень размытия.java@Override public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { super.render(matrixStack, mouseX, mouseY, partialTicks); this.minecraft.keyboardListener.enableRepeatEvents(true); // Параметры для размытой панели float scale = 2f; float panelWidth = 900 / scale; float panelHeight = 650 / scale; float x = MathUtil.calculateXPosition(mc.getMainWindow().scaledWidth() / 2f, panelWidth); float y = MathUtil.calculateXPosition(mc.getMainWindow().scaledHeight() / 2f, panelHeight); xPanel = x; yPanel = y; animation = MathUtil.lerp(animation, 0, 5); // Приведение координат мыши (если нужно) Vec2i fixed = ClientUtil.getMouse(mouseX, mouseY); mouseX = fixed.getX(); mouseY = fixed.getY(); // Отрисовываем нашу размытую панель mc.gameRenderer.setupOverlayRendering(2); renderBlurPanel(matrixStack, x, y, panelWidth, panelHeight); mc.gameRenderer.setupOverlayRendering(); } /** * Рендерим отдельную панель с блюром — без чёрного прямоугольника. */ public void renderBlurPanel(MatrixStack matrixStack, float x, float y, float width, float height) { // 1. Сначала вызываем render(...) из BlurShaderMaster, // чтобы записать форму (трафарет), по которой будет размытие. BlurShaderMaster.INSTANCE.render(() -> { // Здесь рисуем тот самый «трафарет» размытия // (в данном случае — белый прямоугольник с закруглёнными углами). DisplayUtils.drawRoundedRect(x, y, width, height, new Vector4f(8, 8, 8, 8), // угол скругления 0xFFFFFFFF); // полностью белый для стэнсила }); // 2. Запускаем размытие. Параметры offset и steps можно настроить по вкусу. BlurShaderMaster.INSTANCE.updateBlur(2.0f, 4); // 3. Рисуем полупрозрачную белую панель поверх размытия, // чтобы создать эффект «стекла» или «прозрачного пластика». DisplayUtils.drawRoundedRect(x, y, width, height, new Vector4f(8, 8, 8, 8), new Color(255, 255, 255, 100).getRGB()); }
Render без чёрного прямоугольника:
Мы не рисуем DisplayUtils.drawRoundedRect(...)
с тёмным цветом (или убрали этот блок из метода).
Таким образом, за нашей размытой панелью теперь будет «проглядывать» либо фон игры, либо любой другой элемент, что рендерится до неё.
BlurShaderMaster#render(...):
BlurShaderMaster#updateBlur(...):
BlurDown
и BlurUp
.offset
(например, 2.0f
) — степень смещения пикселей при размытии,steps
(например, 4
) — количество проходов размытия.Прозрачная панель:
100
), чтобы визуально было похоже на «стекло».Если в каком-то другом месте у вас всё-таки нужен чёрный фон, то его можно нарисовать до или после этого кода, но так, чтобы он не перекрывал область, где вы хотите видеть размытие. Например, если вы хотите общий фон для всего экрана, нарисуйте его перед вызовом renderBlurPanel(...)
, но не рисуйте поверх той области, в которой расположен блёр.
Таким образом, панель с блюром будет «отдельной» и не будет перекрываться чёрным прямоугольником.