An attempt at Vulkan
package com.jme3.renderer.vulkan;
import com.jme3.scene.VertexBuffer;
import java.util.EnumMap;
/**
* VkMeshGpu:一个 jME3 Mesh 在 GPU(Vulkan) 侧对应的资源集合。
*
* 作用:
* - 把 jME3 的各个 VertexBuffer(Position/Color/Normal/UV...)映射成 Vulkan 的 VkBuffer。
* - 可选地保存 index buffer(索引缓冲),用于 vkCmdDrawIndexed。
*
* 说明:
* - 本类仅是“句柄/元数据容器”,不负责创建/销毁,生命周期通常由 VulkanRuntime/VkResourceFactory 管理。
* - 当前最小实现一般只用 Position + Color(与你的 pipeline/shader 输入匹配),后续可扩展更多语义。
*/
public final class VkMeshGpu {
/**
* 顶点缓冲表:按 jME3 的 VertexBuffer.Type 索引到 Vulkan 的 VkBuffer。
*
* 例如:
* - Type.Position -> 一个包含 vec3(float) 的 Vulkan vertex buffer
* - Type.Color -> 一个包含 vec3(float) 的 Vulkan vertex buffer
*
* 使用时:
* - 你的 VulkanPipeline 的 vertex input 需要与这些 buffer 的 stride/format 对齐
* (比如 binding0=Position, binding1=Color)。
*/
public final EnumMap<VertexBuffer.Type, VkBuffer> vbos =
new EnumMap<>(VertexBuffer.Type.class);
/**
* 索引缓冲(可选)。
*
* - 如果为 null:表示 mesh 没有索引缓冲,使用 vkCmdDraw(vertexCount, ...)
* - 如果非 null:表示 mesh 有索引缓冲,使用 vkCmdDrawIndexed(indexCount, ...)
*/
public VkBuffer ibo;
/**
* index buffer 的索引数量(元素个数,不是字节数)。
* 仅在 ibo != null 时有效,用作 vkCmdDrawIndexed 的 indexCount 参数。
*/
public int indexCount;
/**
* 顶点数量(vertex count)。
* - 对于非索引绘制:用作 vkCmdDraw 的 vertexCount 参数
* - 对于索引绘制:仍可用于校验/调试,但绘制主要用 indexCount
*/
public int vertexCount;
/**
* Vulkan 的索引类型(vkCmdBindIndexBuffer 的 indexType 参数)。
*
* 常见取值:
* - VK_INDEX_TYPE_UINT16:对应 jME Format.UnsignedShort
* - VK_INDEX_TYPE_UINT32:对应 jME Format.UnsignedInt
* - VK_INDEX_TYPE_UINT8_EXT:对应 jME Format.UnsignedByte(需要 VK_EXT_index_type_uint8 扩展)
*
* 注意:
* - 如果 mesh 使用 UnsignedByte 但未启用扩展,这里可能无法正确绑定/绘制。
*/
public int vkIndexType; // VK_INDEX_TYPE_UINT16 / VK_INDEX_TYPE_UINT32 / VK_INDEX_TYPE_UINT8_EXT
}
package com.jme3.lwjgl.test;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.vulkan.LwjglVulkanContext;
import com.jme3.renderer.vulkan.VKRenderer;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.system.AppSettings;
import com.jme3.system.SystemListener;
import com.jme3.util.BufferUtils;
import java.nio.FloatBuffer;
public class VulkanMainMeshTest implements SystemListener {
private LwjglVulkanContext context;
private Mesh triMesh;
private FloatBuffer posBuf;
private FloatBuffer colBuf;
private long lastTimeNs;
private float angleRad = 0f;
// 初始三角形(未旋转)
// 正方形(2 triangles = 6 verts)
private final float[] basePos = new float[]{
// tri 1
-0.6f, -0.6f, 0f,
0.6f, -0.6f, 0f,
0.6f, 0.6f, 0f,
// tri 2
0.6f, 0.6f, 0f,
-0.6f, 0.6f, 0f,
-0.6f, -0.6f, 0f
};
public static void main(String[] args) {
VulkanMainMeshTest app = new VulkanMainMeshTest();
app.start();
}
public void start() {
AppSettings settings = new AppSettings(true);
settings.setTitle("Vulkan Rotating Triangle");
settings.setWidth(900);
settings.setHeight(700);
settings.setSamples(1);
context = new LwjglVulkanContext();
context.setSettings(settings);
context.setSystemListener(this);
context.create(false);
}
@Override
public void initialize() {
System.out.println("Vulkan System Initialized.");
triMesh = new Mesh();
triMesh.setMode(Mesh.Mode.Triangles);
// 位置/颜色 buffer(3 verts * 3 comps)
posBuf = BufferUtils.createFloatBuffer(18);
colBuf = BufferUtils.createFloatBuffer(new float[]{
// tri 1 colors
1f, 0f, 0f,
0f, 1f, 0f,
0f, 0f, 1f,
// tri 2 colors
0f, 0f, 1f,
1f, 1f, 0f,
1f, 0f, 0f
});
// 写入初始位置
posBuf.put(basePos).rewind();
colBuf.rewind();
triMesh.setBuffer(VertexBuffer.Type.Position, 3, VertexBuffer.Format.Float, posBuf);
triMesh.setBuffer(VertexBuffer.Type.Color, 3, VertexBuffer.Format.Float, colBuf);
triMesh.updateBound();
triMesh.updateCounts();
lastTimeNs = System.nanoTime();
}
@Override
public void update() {
// 计算 dt
long now = System.nanoTime();
float dt = (now - lastTimeNs) / 1_000_000_000f;
lastTimeNs = now;
// 累积角度(1 rad/s,可自行调)
angleRad += dt;
// CPU 侧旋转三角形(绕 Z)
float c = (float) Math.cos(angleRad);
float s = (float) Math.sin(angleRad);
posBuf.rewind();
for (int i = 0; i < 6; i++) {
float x = basePos[i * 3];
float y = basePos[i * 3 + 1];
float z = basePos[i * 3 + 2];
float rx = x * c - y * s;
float ry = x * s + y * c;
posBuf.put(rx).put(ry).put(z);
}
posBuf.rewind();
// 提交给 Vulkan renderer
Renderer r = context.getRenderer();
if (r instanceof VKRenderer) {
((VKRenderer) r).renderMesh(triMesh, 0, 1, null);
}
}
@Override
public void reshape(int width, int height) {
}
@Override
public void destroy() {
}
public void pause() {
}
public void resume() {
}
@Override
public void requestClose(boolean esc) {
}
@Override
public void gainFocus() {
}
@Override
public void loseFocus() {
}
@Override
public void handleError(String errorMsg, Throwable t) {
System.err.println(errorMsg);
if (t != null) {
t.printStackTrace();
}
}
}
Currently, 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).