{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreicm5vyca6xkpoiy3ee522qjjzfshc7rvqhy3keyma3poxjgxfl64u",
"uri": "at://did:plc:dxjzgxe7cvirxkwfjr2tjspt/app.bsky.feed.post/3mi3drq7ykac2"
},
"path": "/t/an-attempt-at-vulkan/49433?page=3#post_43",
"publishedAt": "2026-03-26T06:09:36.000Z",
"site": "https://hub.jmonkeyengine.org",
"tags": [
"@Override"
],
"textContent": "\n package com.jme3.lwjgl.test;\n\n import com.jme3.app.LegacyApplication;\n import com.jme3.asset.TextureKey;\n import com.jme3.asset.plugins.ClasspathLocator;\n import com.jme3.export.binary.BinaryImporter;\n import com.jme3.input.FlyByCamera;\n import com.jme3.material.Material;\n import com.jme3.material.plugins.J3MLoader;\n import com.jme3.math.ColorRGBA;\n import com.jme3.math.Vector3f;\n import com.jme3.renderer.Camera;\n import com.jme3.renderer.ViewPort;\n import com.jme3.scene.Geometry;\n import com.jme3.scene.Node;\n import com.jme3.scene.Spatial;\n import com.jme3.scene.shape.Box;\n import com.jme3.system.AppSettings;\n import com.jme3.system.JmeSystem;\n import com.jme3.system.VulkanSystemDelegate;\n import com.jme3.texture.Image;\n import com.jme3.texture.Texture;\n import com.jme3.texture.Texture2D;\n import com.jme3.texture.image.ColorSpace;\n import com.jme3.util.BufferUtils;\n import java.awt.image.BufferedImage;\n import java.io.File;\n import java.nio.ByteBuffer;\n import javax.imageio.ImageIO;\n\n public class VulkanMultiSetTextureTest extends LegacyApplication {\n\n //\"Common/MatDefs/Aurora/Aurora.j3md\"\n //\"Common/MatDefs/Misc/VKUnshaded.j3md\"\n private static final String MAT_DEF = \"Common/MatDefs/Misc/VKUnshaded.j3md\";\n\n private final Node rootNode = new Node(\"Root\");\n private ViewPort viewPort;\n private Camera cam;\n private FlyByCamera flyCam;\n\n private float fpsTime = 0f;\n private int fpsFrames = 0;\n\n // 新增:保存测试几何体,update 时可拿到 material\n private Geometry testGeom;\n\n @Override\n public void initialize() {\n super.initialize();\n\n assetManager.registerLocator(\"/\", ClasspathLocator.class);\n assetManager.registerLoader(J3MLoader.class, \"j3md\", \"j3m\");\n assetManager.registerLoader(BinaryImporter.class, \"j3o\");\n\n\n cam = getCamera();\n viewPort = renderManager.createMainView(\"Main\", cam);\n viewPort.setBackgroundColor(ColorRGBA.DarkGray);\n viewPort.attachScene(rootNode);\n\n cam.setLocation(new Vector3f(0f, 0f, 20f));\n cam.setFrustumFar(1000f);\n\n flyCam = new FlyByCamera(cam);\n flyCam.setMoveSpeed(30f);\n flyCam.setDragToRotate(true);\n flyCam.registerWithInput(inputManager);\n\n Box box = new Box(2f, 2f, 2f);\n testGeom = new Geometry(\"MultiSetBox\", box);\n\n Material mat = new Material(assetManager, MAT_DEF);\n\n Texture2D extra = loadPngFromFileNoJmeLoader(\"F:/JME/jmonkeyengine/jme3-core/src/main/resources/Common/Textures/MissingMaterial.png\", true);\n if (extra != null) {\n mat.setTexture(\"ColorMap\", extra);\n //mat.setTexture(\"ExtraTex\", extra);\n }\n // assetManager.registerLocator(\"F:/AYA2022年10月16日/Jme\", com.jme3.asset.plugins.FileLocator.class);\n // Spatial model = assetManager.loadModel(\"kasolia.j3o\");\n // model.setMaterial(mat);\n // rootNode.attachChild(model);\n testGeom.setMaterial(mat);\n rootNode.attachChild(testGeom);\n\n System.out.println(\"[App] mat.ExtraTex=\" + mat.getParam(\"ExtraTex\"));\n System.out.println(\"[App] init done. children=\" + rootNode.getQuantity()\n + \", ExtraTex=\" + (extra != null));\n }\n\n private Texture loadTexture(String path) {\n try {\n TextureKey key = new TextureKey(path, false);\n Texture tex = assetManager.loadTexture(key);\n tex.setAnisotropicFilter(4);\n return tex;\n } catch (Exception e) {\n System.err.println(\"[Warn] texture load failed: \" + path + \" -> \" + e.getMessage());\n return null;\n }\n }\n\n @Override\n public void update() {\n super.update();\n\n float tpf = timer.getTimePerFrame();\n\n fpsTime += tpf;\n fpsFrames++;\n if (fpsTime >= 1.0f) {\n int fps = Math.round(fpsFrames / fpsTime);\n fpsTime = 0f;\n fpsFrames = 0;\n if (context != null) {\n context.setTitle(\"Vulkan MultiSet Texture Test | FPS: \" + fps);\n }\n }\n\n rootNode.updateLogicalState(tpf);\n rootNode.updateGeometricState();\n\n if (context != null && context.isRenderable()) {\n renderManager.render(tpf, true);\n }\n }\n\n private static Texture2D loadPngFromFileNoJmeLoader(String absPath, boolean flipY) {\n try {\n BufferedImage bi = ImageIO.read(new File(absPath));\n if (bi == null) {\n return null;\n }\n\n int w = bi.getWidth();\n int h = bi.getHeight();\n ByteBuffer buf = BufferUtils.createByteBuffer(w * h * 4);\n\n for (int row = 0; row < h; row++) {\n int y = flipY ? (h - 1 - row) : row; // 关键:按需翻转Y\n for (int x = 0; x < w; x++) {\n int argb = bi.getRGB(x, y);\n byte a = (byte) ((argb >> 24) & 0xFF);\n byte r = (byte) ((argb >> 16) & 0xFF);\n byte g = (byte) ((argb >> 8) & 0xFF);\n byte b = (byte) (argb & 0xFF);\n buf.put(r).put(g).put(b).put(a);\n }\n }\n buf.flip();\n\n Image img = new Image(Image.Format.RGBA8, w, h, buf, null, ColorSpace.Linear);\n Texture2D tex = new Texture2D(img);\n tex.setMinFilter(com.jme3.texture.Texture.MinFilter.BilinearNoMipMaps);\n tex.setMagFilter(com.jme3.texture.Texture.MagFilter.Bilinear);\n tex.setWrap(com.jme3.texture.Texture.WrapMode.Repeat);\n return tex;\n } catch (Exception e) {\n e.printStackTrace();\n return null;\n }\n }\n\n public static void main(String[] args) {\n JmeSystem.setSystemDelegate(new VulkanSystemDelegate());\n\n AppSettings s = new AppSettings(true);\n s.setCustomRenderer(com.jme3.renderer.vulkan.context.LwjglVulkanContext.class);\n s.setWidth(1920);\n s.setHeight(1080);\n s.setTitle(\"Vulkan MultiSet Texture Test\");\n\n VulkanMultiSetTextureTest app = new VulkanMultiSetTextureTest();\n app.setSettings(s);\n app.start();\n }\n }\n\n\n\nMade significant progress\nI attempted to modify a file named VKUnshaded.j3md for testing purposes.\n\n\n #version 450\n #define VULKAN_NATIVE 1\n\n #import \"Common/ShaderLib/VKGLSLCompat.glsllib\"\n #import \"Common/ShaderLib/VKSkinning.glsllib\"\n // #import \"Common/ShaderLib/VKInstancing.glsllib\" // 先禁用,避免矩阵UBO冲突\n #import \"Common/ShaderLib/VKMorphAnim.glsllib\"\n\n layout(location = 0) in vec3 inPosition;\n layout(location = 1) in vec2 inTexCoord;\n layout(location = 2) in vec2 inTexCoord2;\n layout(location = 3) in vec4 inColor;\n\n layout(location = 0) out vec2 texCoord1;\n layout(location = 1) out vec2 texCoord2;\n layout(location = 2) out vec4 vertColor;\n\n // 与 FS 对齐的主 UBO\n layout(set = 0, binding = 0, std140) uniform JmeUniforms {\n mat4 g_WorldViewProjectionMatrix;\n vec4 m_Color;\n vec4 g_Resolution;\n vec4 g_Mouse;\n vec4 g_Time;\n };\n\n #ifdef HAS_POINTSIZE\n layout(set = 0, binding = 3) uniform PointSizeUbo {\n float m_PointSize;\n };\n #endif\n\n #if defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD))\n #define NEED_TEXCOORD1\n #endif\n\n void main() {\n #ifdef NEED_TEXCOORD1\n texCoord1 = inTexCoord;\n #endif\n\n #ifdef SEPARATE_TEXCOORD\n texCoord2 = inTexCoord2;\n #endif\n\n #ifdef HAS_VERTEXCOLOR\n vertColor = inColor;\n #else\n vertColor = vec4(1.0);\n #endif\n\n #ifdef HAS_POINTSIZE\n gl_PointSize = m_PointSize;\n #endif\n\n vec4 modelSpacePos = vec4(inPosition, 1.0);\n\n // Phase-1:先注释,后续分批接回\n // #ifdef NUM_MORPH_TARGETS\n // Morph_Compute(modelSpacePos);\n // #endif\n //\n // #ifdef NUM_BONES\n // Skinning_Compute(modelSpacePos);\n // #endif\n\n gl_Position = g_WorldViewProjectionMatrix * modelSpacePos;\n }\n\n\n\n\n #version 450\n #define VULKAN_NATIVE 1\n #import \"Common/ShaderLib/VKGLSLCompat.glsllib\"\n\n #if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD))\n #define NEED_TEXCOORD1\n #endif\n\n // 恢复基础材质/全局参数块(与 VS 统一 set/binding)\n layout(set = 0, binding = 0, std140) uniform JmeUniforms {\n mat4 g_WorldViewProjectionMatrix; // FS 不用,但保持跨阶段布局一致\n vec4 m_Color; // HAS_COLOR 时使用\n vec4 g_Resolution;\n vec4 g_Mouse;\n vec4 g_Time;\n };\n\n layout(set = 0, binding = 1) uniform sampler2D m_ColorMap;\n layout(set = 0, binding = 2) uniform sampler2D m_LightMap;\n\n #if defined(DISCARD_ALPHA)\n layout(set = 0, binding = 3, std140) uniform AlphaParams {\n float m_AlphaDiscardThreshold;\n };\n #endif\n\n #ifdef DESATURATION\n layout(set = 0, binding = 4, std140) uniform DesaturationParams {\n float m_DesaturationValue;\n };\n #endif\n\n layout(location = 0) in vec2 texCoord1;\n layout(location = 1) in vec2 texCoord2;\n layout(location = 2) in vec4 vertColor;\n\n layout(location = 0) out vec4 fragColor;\n\n void main() {\n vec4 color = vec4(1.0);\n\n #ifdef HAS_COLORMAP\n color *= texture(m_ColorMap, texCoord1);\n #endif\n\n #ifdef HAS_VERTEXCOLOR\n color *= vertColor;\n #endif\n\n #ifdef HAS_COLOR\n color *= m_Color;\n #endif\n\n #ifdef HAS_LIGHTMAP\n #ifdef SEPARATE_TEXCOORD\n color.rgb *= texture(m_LightMap, texCoord2).rgb;\n #else\n color.rgb *= texture(m_LightMap, texCoord1).rgb;\n #endif\n #endif\n\n #if defined(DISCARD_ALPHA)\n if (color.a < m_AlphaDiscardThreshold) {\n discard;\n }\n #endif\n\n #ifdef DESATURATION\n vec3 gray = vec3(dot(vec3(0.2126, 0.7152, 0.0722), color.rgb));\n color.rgb = mix(color.rgb, gray, m_DesaturationValue);\n #endif\n\n fragColor = color;\n }\n\n\n\n\n @Override\n public void updateBufferData(VertexBuffer vb) {\n if (vb == null) {\n return;\n }\n\n try {\n runtime.invalidateMeshGpuByVertexBuffer(vb);\n } catch (Throwable t) {\n // 兜底全量失效\n LOGGER.log(Level.WARNING, \"[VKRenderer] precise invalidate failed, fallback to all, type=\"\n + vb.getBufferType(), t);\n runtime.invalidateAllMeshGpu();\n }\n\n if (LOGGER.isLoggable(Level.FINE)) {\n LOGGER.fine(\"[VKRenderer] updateBufferData(VertexBuffer) -> precise invalidate, type=\"\n + vb.getBufferType());\n }\n }\n\n\nToday, the function “updateBufferData” was also completed.\n\nI am very satisfied with the current progress. I believe it won’t be long before the first version is released and then we can recruit volunteers to test it.",
"title": "An attempt at Vulkan"
}