{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreib3fxd2cjrrg5twbuhmhikp76khiblq7cmqpylfzbcrjxocverp7i",
"uri": "at://did:plc:dxjzgxe7cvirxkwfjr2tjspt/app.bsky.feed.post/3mgvtifqkefy2"
},
"path": "/t/an-attempt-at-vulkan/49433#post_2",
"publishedAt": "2026-03-13T00:10:08.000Z",
"site": "https://hub.jmonkeyengine.org",
"tags": [
"@Override"
],
"textContent": "\n package com.jme3.renderer.vulkan;\n\n import com.jme3.scene.VertexBuffer;\n\n import java.util.EnumMap;\n\n /**\n * VkMeshGpu:一个 jME3 Mesh 在 GPU(Vulkan) 侧对应的资源集合。\n *\n * 作用:\n * - 把 jME3 的各个 VertexBuffer(Position/Color/Normal/UV...)映射成 Vulkan 的 VkBuffer。\n * - 可选地保存 index buffer(索引缓冲),用于 vkCmdDrawIndexed。\n *\n * 说明:\n * - 本类仅是“句柄/元数据容器”,不负责创建/销毁,生命周期通常由 VulkanRuntime/VkResourceFactory 管理。\n * - 当前最小实现一般只用 Position + Color(与你的 pipeline/shader 输入匹配),后续可扩展更多语义。\n */\n public final class VkMeshGpu {\n\n /**\n * 顶点缓冲表:按 jME3 的 VertexBuffer.Type 索引到 Vulkan 的 VkBuffer。\n *\n * 例如:\n * - Type.Position -> 一个包含 vec3(float) 的 Vulkan vertex buffer\n * - Type.Color -> 一个包含 vec3(float) 的 Vulkan vertex buffer\n *\n * 使用时:\n * - 你的 VulkanPipeline 的 vertex input 需要与这些 buffer 的 stride/format 对齐\n * (比如 binding0=Position, binding1=Color)。\n */\n public final EnumMap<VertexBuffer.Type, VkBuffer> vbos =\n new EnumMap<>(VertexBuffer.Type.class);\n\n /**\n * 索引缓冲(可选)。\n *\n * - 如果为 null:表示 mesh 没有索引缓冲,使用 vkCmdDraw(vertexCount, ...)\n * - 如果非 null:表示 mesh 有索引缓冲,使用 vkCmdDrawIndexed(indexCount, ...)\n */\n public VkBuffer ibo;\n\n /**\n * index buffer 的索引数量(元素个数,不是字节数)。\n * 仅在 ibo != null 时有效,用作 vkCmdDrawIndexed 的 indexCount 参数。\n */\n public int indexCount;\n\n /**\n * 顶点数量(vertex count)。\n * - 对于非索引绘制:用作 vkCmdDraw 的 vertexCount 参数\n * - 对于索引绘制:仍可用于校验/调试,但绘制主要用 indexCount\n */\n public int vertexCount;\n\n /**\n * Vulkan 的索引类型(vkCmdBindIndexBuffer 的 indexType 参数)。\n *\n * 常见取值:\n * - VK_INDEX_TYPE_UINT16:对应 jME Format.UnsignedShort\n * - VK_INDEX_TYPE_UINT32:对应 jME Format.UnsignedInt\n * - VK_INDEX_TYPE_UINT8_EXT:对应 jME Format.UnsignedByte(需要 VK_EXT_index_type_uint8 扩展)\n *\n * 注意:\n * - 如果 mesh 使用 UnsignedByte 但未启用扩展,这里可能无法正确绑定/绘制。\n */\n public int vkIndexType; // VK_INDEX_TYPE_UINT16 / VK_INDEX_TYPE_UINT32 / VK_INDEX_TYPE_UINT8_EXT\n }\n\n\n\n\n package com.jme3.lwjgl.test;\n\n import com.jme3.renderer.Renderer;\n import com.jme3.renderer.vulkan.LwjglVulkanContext;\n import com.jme3.renderer.vulkan.VKRenderer;\n import com.jme3.scene.Mesh;\n import com.jme3.scene.VertexBuffer;\n import com.jme3.system.AppSettings;\n import com.jme3.system.SystemListener;\n import com.jme3.util.BufferUtils;\n\n import java.nio.FloatBuffer;\n\n public class VulkanMainMeshTest implements SystemListener {\n\n private LwjglVulkanContext context;\n\n private Mesh triMesh;\n private FloatBuffer posBuf;\n private FloatBuffer colBuf;\n\n private long lastTimeNs;\n private float angleRad = 0f;\n\n // 初始三角形(未旋转)\n // 正方形(2 triangles = 6 verts)\n private final float[] basePos = new float[]{\n // tri 1\n -0.6f, -0.6f, 0f,\n 0.6f, -0.6f, 0f,\n 0.6f, 0.6f, 0f,\n // tri 2\n 0.6f, 0.6f, 0f,\n -0.6f, 0.6f, 0f,\n -0.6f, -0.6f, 0f\n };\n\n public static void main(String[] args) {\n VulkanMainMeshTest app = new VulkanMainMeshTest();\n app.start();\n }\n\n public void start() {\n AppSettings settings = new AppSettings(true);\n settings.setTitle(\"Vulkan Rotating Triangle\");\n settings.setWidth(900);\n settings.setHeight(700);\n settings.setSamples(1);\n\n context = new LwjglVulkanContext();\n context.setSettings(settings);\n context.setSystemListener(this);\n\n context.create(false);\n }\n\n @Override\n public void initialize() {\n System.out.println(\"Vulkan System Initialized.\");\n\n triMesh = new Mesh();\n triMesh.setMode(Mesh.Mode.Triangles);\n\n // 位置/颜色 buffer(3 verts * 3 comps)\n posBuf = BufferUtils.createFloatBuffer(18);\n colBuf = BufferUtils.createFloatBuffer(new float[]{\n // tri 1 colors\n 1f, 0f, 0f,\n 0f, 1f, 0f,\n 0f, 0f, 1f,\n // tri 2 colors\n 0f, 0f, 1f,\n 1f, 1f, 0f,\n 1f, 0f, 0f\n });\n\n // 写入初始位置\n posBuf.put(basePos).rewind();\n colBuf.rewind();\n\n triMesh.setBuffer(VertexBuffer.Type.Position, 3, VertexBuffer.Format.Float, posBuf);\n triMesh.setBuffer(VertexBuffer.Type.Color, 3, VertexBuffer.Format.Float, colBuf);\n\n triMesh.updateBound();\n triMesh.updateCounts();\n\n lastTimeNs = System.nanoTime();\n }\n\n @Override\n public void update() {\n // 计算 dt\n long now = System.nanoTime();\n float dt = (now - lastTimeNs) / 1_000_000_000f;\n lastTimeNs = now;\n\n // 累积角度(1 rad/s,可自行调)\n angleRad += dt;\n\n // CPU 侧旋转三角形(绕 Z)\n float c = (float) Math.cos(angleRad);\n float s = (float) Math.sin(angleRad);\n\n posBuf.rewind();\n for (int i = 0; i < 6; i++) {\n float x = basePos[i * 3];\n float y = basePos[i * 3 + 1];\n float z = basePos[i * 3 + 2];\n\n float rx = x * c - y * s;\n float ry = x * s + y * c;\n\n posBuf.put(rx).put(ry).put(z);\n }\n posBuf.rewind();\n\n // 提交给 Vulkan renderer\n Renderer r = context.getRenderer();\n if (r instanceof VKRenderer) {\n ((VKRenderer) r).renderMesh(triMesh, 0, 1, null);\n }\n }\n\n @Override\n public void reshape(int width, int height) {\n }\n\n @Override\n public void destroy() {\n }\n\n public void pause() {\n }\n\n public void resume() {\n }\n\n @Override\n public void requestClose(boolean esc) {\n }\n\n @Override\n public void gainFocus() {\n }\n\n @Override\n public void loseFocus() {\n }\n\n @Override\n public void handleError(String errorMsg, Throwable t) {\n System.err.println(errorMsg);\n if (t != null) {\n t.printStackTrace();\n }\n }\n }\n\n\n\nCurrently, I can use the mesh(class) to transfer vertices to Vulkan. However, I am unable to utilize functions like Geometry at the moment. I haven’t yet studied the material section. Once I am available next week, I will try to figure out a way to create a material backend so that the frontend of JME can directly use it (of course, this is an ideal situation and I’m not sure if it can be accomplished yet).",
"title": "An attempt at Vulkan"
}