Skip to content

渲染管线 ​

客户端统一渲染管线,支持渲染命令、渲染通道、并行渲染和着色器注册。

前置知识

需要了解 资源管理 和 Minecraft 的 PoseStack / BufferSource 基本概念。

注意

Mojang于最近宣布了MC将在不久后使用Vulkan后端,渲染管线正在重构以适配VK,同时支持GPU并行计算(比如Compute Shader)

Quick Start ​

kotlin
class MyRenderCommand(private val x: Double, private val y: Double, private val z: Double) : RenderCommand {
    override val renderType: RenderType? = null
    override val sortKey: Float = 0f
    override val isTransparent: Boolean = false

    override fun execute(context: RenderContext) {
        val pose = context.poseStack
        pose.pushPose()
        pose.translate(x - context.cameraX, y - context.cameraY, z - context.cameraZ)
        // 渲染逻辑 ...
        pose.popPose()
    }
}

API Reference ​

RenderCommand ​

属性/方法类型说明
renderTypeRenderType?渲染类型(用于分组和批处理)
sortKeyFloat排序键(透明物体排序,值越大越远)
isTransparentBoolean是否透明
execute(context)(RenderContext) -> Unit执行渲染

RenderContext ​

属性类型说明
poseStackPoseStack变换矩阵栈
bufferSourceMultiBufferSource缓冲区源
partialTickFloat插值因子(0~1)
cameraXDouble相机 X 坐标
cameraYDouble相机 Y 坐标
cameraZDouble相机 Z 坐标
frameTimeMsLong帧时间(毫秒)
gameTimeLong游戏时间(ticks)
graphicsGuiGraphics?GUI 渲染上下文
cameraCamera?相机实例

RenderPass ​

方法参数说明
构造函数name: String, priority: Int, enabled: Boolean创建渲染通道
collect(command)RenderCommand收集渲染命令
prepare()—准备(排序等)
execute(context)RenderContext执行所有已收集的命令
clear()—清空命令列表
getStats()—获取通道统计信息

RenderPass 统计 (Stats):

属性类型说明
nameString通道名称
totalCommandsInt总命令数
groupedCommandsInt分组命令数
renderTypeCountIntRenderType 数量

TransparentRenderPass ​

继承 RenderPass,自动按距离从远到近排序。

参数类型说明
nameString通道名称
priorityInt优先级(越小越先执行)

IRenderable(并行渲染接口) ​

属性/方法类型说明
renderToBuffer(buffer, camera, partialTick)—渲染到顶点缓冲区(可能在工作线程调用)
isRemovedBoolean是否已移除
getDistanceSq(camX, camY, camZ)Double到相机的距离平方(用于排序)

ParallelRenderType ​

方法返回值说明
isParallel()Boolean是否启用并行渲染(默认 false)
getSortMode()SortMode排序模式(NONE / BACK_TO_FRONT)
prepareState()—准备渲染状态(主线程)
beginBuffer(buffer)—开始缓冲区(可能在工作线程)
endBuffer(buffer)—结束缓冲区并上传(主线程)
releaseState()—释放渲染状态(主线程)

ParallelExecutor ​

方法参数说明
getInstance()—获取单例
execute(renderables, config, camera, partialTick, defaultBuilder)见签名执行并行渲染
executeBatch(batches, camera, partialTick, defaultBuilder)见签名批量执行多个渲染配置
getParallelism()—获取并行度(线程数)

ShaderRegistry ​

方法参数返回值说明
get(name, owner)String, StringShaderInstance?获取着色器
getOrDefault(name, owner)String, StringShaderInstance获取着色器,失败返回默认
clearExternalCache(owner)String?—清理缓存(null 清理全部)
getExternalCachedCount(owner)String?Int获取缓存数量
isUILoaded()—BooleanUI 着色器是否就绪
isBloomShadersReady()—BooleanBloom 着色器是否就绪

内置着色器:

分类着色器名称
UIparticle、fastBlit、spriteBlit、roundBox、progressRoundBox、frameRoundBox、roundLine、sdfRect、round、panelBg
视频videoNV12、videoYUV420P
特效hdrParticle、spriteHdrParticle、brightPass、downSampling、upSampling、bloomFinalScatterPass

渲染通道 ​

不透明通道 ​

kotlin
val opaquePass = RenderPass(
    name = "opaque",
    priority = 0,
    enabled = true
) { context, commands ->
    for (command in commands) {
        command.execute(context)
    }
}

opaquePass.collect(myCommand)
opaquePass.prepare()
opaquePass.execute(renderContext)
opaquePass.clear()

透明通道 ​

kotlin
val transparentPass = TransparentRenderPass(
    name = "transparent",
    priority = 100
)

// 透明命令自动从远到近排序
transparentPass.collect(transparentCommand)
transparentPass.prepare()  // 执行排序
transparentPass.execute(context)

类型化通道 ​

kotlin
class MyTypedPass : RenderPass("my_pass"), TypedRenderPass {
    override fun canHandle(command: RenderCommand): Boolean {
        return command is MySpecialCommand
    }
}

并行渲染 ​

kotlin
val executor = ParallelExecutor.getInstance()

// 单配置执行
executor.execute(
    renderables = particles,
    config = myRenderConfig,
    camera = camera,
    partialTick = partialTick,
    defaultBuilder = bufferBuilder
)

// 批量执行
executor.executeBatch(
    batches = listOf(
        particles to particleConfig,
        trails to trailConfig
    ),
    camera = camera,
    partialTick = partialTick,
    defaultBuilder = bufferBuilder
)

并行阈值

当 IRenderable 数量 >= 64 且 IRenderConfig.isParallel() 返回 true 时,才会启用并行渲染。否则使用串行渲染。

外部着色器 ​

从 Behemiron/photon/shader/ 目录加载,使用 Minecraft 标准 JSON 格式:

json
{
    "blend": {
        "func": "add",
        "srcrgb": "srcalpha",
        "dstrgb": "1-srcalpha"
    },
    "vertex": "my_shader",
    "fragment": "my_shader",
    "attributes": ["Position", "UV0", "Color"],
    "samplers": [{ "name": "Sampler0" }],
    "uniforms": [
        { "name": "ModelViewMat", "type": "matrix4x4", "count": 16 },
        { "name": "ProjMat", "type": "matrix4x4", "count": 16 }
    ]
}

完整示例 ​

kotlin
@Component
class CustomRenderer {

    private val opaquePass = RenderPass("custom_opaque", priority = 50)
    private val transparentPass = TransparentRenderPass("custom_transparent", priority = 150)

    fun onRenderFrame(context: RenderContext) {
        // 收集命令
        opaquePass.collect(MyRenderCommand(10.0, 64.0, 10.0))
        transparentPass.collect(GlowRenderCommand(10.0, 65.0, 10.0))

        // 执行渲染
        opaquePass.prepare()
        opaquePass.execute(context)
        opaquePass.clear()

        transparentPass.prepare()
        transparentPass.execute(context)
        transparentPass.clear()
    }

    // 粒子并行渲染
    fun renderParticles(particles: List<IRenderable>, camera: Camera, partialTick: Float) {
        if (particles.isEmpty()) return

        val executor = ParallelExecutor.getInstance()
        executor.execute(
            renderables = particles,
            config = myParticleConfig,
            camera = camera,
            partialTick = partialTick,
            defaultBuilder = bufferBuilder
        )
    }

    // 使用着色器
    fun renderWithShader() {
        val shader = ShaderRegistry.getOrDefault("roundBox", "my_plugin")
        // 使用 shader 进行渲染 ...
    }
}

注意事项

  • IRenderable.renderToBuffer() 可能在工作线程调用,不要修改 OpenGL 状态,不要访问非线程安全的共享资源。
  • prepareState() 和 releaseState() 只在主线程调用,可安全操作 OpenGL 状态。
  • 透明物体必须使用 TransparentRenderPass 以保证正确的绘制顺序(从远到近)。
  • 检查 ShaderRegistry.isUILoaded() / isBloomShadersReady() 后再使用对应着色器。