= 创作分享 =
编程开发
如何在1.12.2中正确管理GL的渲染状态?
OpenKFC

如何在1.12.2中正确管理GL的渲染状态?

OpenKFC 于 2025-1-26 02:09 ( 4天前 ) [复制链接] [只看楼主] [打印]
143 4
本帖最后由 OpenKFC 于 2025-1-26 02:52 编辑

直接用如下的代码监听RenderGameOverlayEvent.Post事件便会出现bug:    @SubscribeEvent
    public static void onPostRenderGameOverlay(RenderGameOverlayEvent.Post event) {
        if (event.getType() != RenderGameOverlayEvent.ElementType.ALL)
            return;
        Minecraft mc = Minecraft.getMinecraft();
        ScaledResolution resolution = event.getResolution();
        mc.getRenderItem().renderItemOverlays(
                mc.fontRenderer,
                mc.player.getHeldItemMainhand(),
                resolution.getScaledWidth() >> 1,
                resolution.getScaledHeight() >> 1
        );
    }
只要手持物品的(数量 | 耐久栏 | 冷却)需要被渲染,renderItemOverlays即会在完成渲染后调用GlStateManager.enableLighting();启用光照,这会导致打开GUI(例如物品栏)时屏幕原本的暗灰色半透明背景变得不透明,效果如下:
我尝试过了在执行渲染逻辑前后分别调用GlStateManager.pushAttribs();以及GlStateManager.popAttribs();方法,这里附上它们的内部实现:
  1. GL11.glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT);
复制代码
  1. GL11.glPopAttrib();
复制代码

但这并没有解决问题,通过debug追踪,我发现在它调用完glPopAttrib之后,gl渲染器内部确实已经将lightning改为了执行我的渲染逻辑前的false状态,即
  1. GL11.glGetBoolean(2896) == false
复制代码
但是GlStateManager内部维护的lightningState字段仍为启用状态,这造成了游戏的其他渲染代码尝试GlStateManager.enableLightning()时gl渲染器的光照没能启用,附游戏画面(人偶的渲染并不正常,正常的应该略微有点暗)
我认为是GlStateManager实现不佳导致的glPushAttrib方法根本无法使用,请问有什么方法可以正确地在我执行渲染之前保存gl的各种状态并在渲染完毕后还原回去吗?


该帖共收到 4 条回复!
OpenKFC
本帖最后由 OpenKFC 于 2025-1-26 02:51 编辑

抱歉没编辑好就发出来了……

现在编辑好了
发表于 4 天前 | 只看该作者

回复 | 举报

Flechazo
你可以使用GlStateManager.pushMatrix()和GlStateManager.popMatrix()进行OpenGL状态管理,也可以手动明确地保存和恢复光照状态。第一种代码示例
  1. @SubscribeEvent
  2. public static void onPostRenderGameOverlay(RenderGameOverlayEvent.Post event) {
  3.     if (event.getType() != RenderGameOverlayEvent.ElementType.ALL)
  4.         return;
  5.     Minecraft mc = Minecraft.getMinecraft();
  6.     ScaledResolution resolution = event.getResolution();

  7.     GlStateManager.pushMatrix(); // 保存当前状态
  8.     GlStateManager.disableLighting(); // 禁用光照

  9.     mc.getRenderItem().renderItemOverlays(
  10.             mc.fontRenderer,
  11.             mc.player.getHeldItemMainhand(),
  12.             resolution.getScaledWidth() / 2,
  13.             resolution.getScaledHeight() / 2
  14.     );

  15.     GlStateManager.popMatrix(); // 恢复之前的状态
  16. }
复制代码

第二种代码示例:
  1. @SubscribeEvent
  2. public static void onPostRenderGameOverlay(RenderGameOverlayEvent.Post event) {
  3.     if (event.getType() != RenderGameOverlayEvent.ElementType.ALL)
  4.         return;
  5.     Minecraft mc = Minecraft.getMinecraft();
  6.     ScaledResolution resolution = event.getResolution();

  7.     boolean wasLightingEnabled = GL11.glGetBoolean(GL11.GL_LIGHTING); // 获取光照状态
  8.     GlStateManager.disableLighting(); // 禁用光照

  9.     mc.getRenderItem().renderItemOverlays(
  10.             mc.fontRenderer,
  11.             mc.player.getHeldItemMainhand(),
  12.             resolution.getScaledWidth() / 2,
  13.             resolution.getScaledHeight() / 2
  14.     );

  15.     if (wasLightingEnabled) {
  16.         GlStateManager.enableLighting(); // 如果之前启用了光照,则重新启用
  17.     }
  18. }
复制代码
发表于 4 天前 | 只看该作者

回复 | 举报

Flechazo
lcydw66 发表于 2025-1-26 19:17
你可以使用GlStateManager.pushMatrix()和GlStateManager.popMatrix()进行OpenGL状态管理,也可以手动明确 ...

仅供参考
发表于 4 天前 | 只看该作者

回复 | 举报

OpenKFC
目前想到的解决办法……

  1. public class GlAttribModel implements AutoCloseable {
  2.     boolean alpha = GL11.glGetBoolean(GL11.GL_ALPHA_TEST);
  3.     boolean blend = GL11.glGetBoolean(GL11.GL_BLEND);
  4.     boolean depth = GL11.glGetBoolean(GL11.GL_DEPTH_TEST);
  5.     boolean lighting = GL11.glGetBoolean(GL11.GL_LIGHTING);
  6.     boolean[] light = new boolean[]{
  7.             GL11.glGetBoolean(GL11.GL_LIGHT0),
  8.             GL11.glGetBoolean(GL11.GL_LIGHT1),
  9.             GL11.glGetBoolean(GL11.GL_LIGHT2),
  10.             GL11.glGetBoolean(GL11.GL_LIGHT3),
  11.             GL11.glGetBoolean(GL11.GL_LIGHT4),
  12.             GL11.glGetBoolean(GL11.GL_LIGHT5),
  13.             GL11.glGetBoolean(GL11.GL_LIGHT6),
  14.             GL11.glGetBoolean(GL11.GL_LIGHT7)
  15.     };

  16.     public void apply() {
  17.         if (alpha) {GlStateManager.enableAlpha();} else {GlStateManager.disableAlpha();}
  18.         if (blend) {GlStateManager.enableBlend();} else {GlStateManager.disableBlend();}
  19.         if (depth) {GlStateManager.enableDepth();} else {GlStateManager.disableDepth();}
  20.         if (lighting) {GlStateManager.enableLighting();} else {GlStateManager.disableLighting();}
  21.         for (int i = 0; i < 8; i++)
  22.             if (light[i]) {GlStateManager.enableLight(i);} else {GlStateManager.disableLight(i);}
  23.     }

  24.     @Override public void close() {apply();}
  25. }
复制代码
发表于 4 天前 | 只看该作者

回复 | 举报

百科目前不允许匿名发帖哦~ 请先 [ 登陆 ][ 注册 ] 吧~

本版积分规则

发新帖
  • 回复
  • 点评
  • 评分

[ MC百科(mcmod.cn) 除另有声明,所有开放公共编辑的内容均使用 BY-NC-SA 3.0 协议 ]

Minecraft百科CC协议
快速回复 返回顶部 返回列表