jMonkeyEngine Hub - Latest posts https://hub.jmonkeyengine.org Latest posts An attempt at Vulkan what about defining a custom jme macro to wrap all the vulkan stuff, then edit every shader to use it in its vulkan compliant uniforms/inout declarations, and gate the macro inside GLSLCompat so that it actually resolves to the vulkan binding if the shader is being compiled on vulkan or to nothing if compiled on opengl? Is that something possible? If not, the other best option is to use a custom glsl preprocessor that does the same.

So instead of trying to compile opengl shaders to vulkan we compile vulkan shaders to opengl?

Something like

BIND (location=....) in vec2 texCoord;

that is transformed to

layout(location=...) in vec2 texCoord;

for vulkan
and

in vec2 texCoord;

for opengl

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_20 Mon, 16 Mar 2026 10:33:23 +0000 hub.jmonkeyengine.org-post-383951
Rapid Escalation (First Steam Prototype) I think this is mostly personal preference, and i dont know what is the vision/plan for long gameplay. But i like “build” types of skilltrees, where i have to make hard decision on where to invest and what my ship should be capable of.

I personally do not see the current design very practical, also in terms of what happens if you are on ring 20? Are you required to pan around to get to the actual nodes. From a design point of view i like the current implementation however

But hard to say and largely opinion based topic.

Add: the displacement wave effect is superb

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_11 Mon, 16 Mar 2026 09:30:15 +0000 hub.jmonkeyengine.org-post-383950
Rapid Escalation (First Steam Prototype) Thanks for the honest feedback.

I like the idea of the seconds added, but will have to think if this will fit in the vision of the game.

I do have a question on the upgrade tree for you:

Currently the upgrade tree is kind of open to buy anything of you have the money. This is an open upgrade tree.

So my question is, do you think a more closed/linear type upgrade tree would work beter for gameplay? Like the upgrade trees we get in these other incremental games?

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_10 Mon, 16 Mar 2026 08:36:23 +0000 hub.jmonkeyengine.org-post-383949
Rapid Escalation (First Steam Prototype) Not sure if it messes up balancing, but i would try a “get 0.1 seconds for each enemy killed” upgrade.

Or something that i have the feeling that staying alive longer is beneficial instead of making more runs.

But only my impression, the whole game itself feels very polished. Good work

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_9 Mon, 16 Mar 2026 08:15:47 +0000 hub.jmonkeyengine.org-post-383948
Rapid Escalation (First Steam Prototype) It is only the initial impression when you start the game. As soon as you play it more and get a grasp of the mechanics i did not have that impression anymore.

Don’t really know what i would do. Maybe a info panel that states clearly the amount of time you have and other info?

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_8 Mon, 16 Mar 2026 08:12:55 +0000 hub.jmonkeyengine.org-post-383947
Rapid Escalation (First Steam Prototype) I was thinking of making the locked items a little less saturated so that one can easily see if they are locked.

Also, I see a lot of people give feedback about the game loop and timer and short battles.

So just to clear up something, this is an incremental game and does not have a lose state.

It is all about upgrading your ship to feel more powerful in a battle run.

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_7 Mon, 16 Mar 2026 07:50:12 +0000 hub.jmonkeyengine.org-post-383946
Rapid Escalation (First Steam Prototype) Oh, sorry i did not see the little icon.
Strangely enough also the coloring of already bought items is much more visible than i remember it to be. (Currently looking from on my phone, and i have the monitor at home setup relatively dark)

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_6 Mon, 16 Mar 2026 07:33:00 +0000 hub.jmonkeyengine.org-post-383945
An attempt at Vulkan Tbh i am not sure i get the issues. Yes, spir-v does not support preprocessors style functions. Nor does opengl. You are already forced to recompile the shader in case a define changes. Jme already has its own preprocessor in place that does the loop unroll, so why not extent that part.

For uniform style variables you have push constants in vulcan. If its a good idea to use it is a different topic, but you can.

https://docs.vulkan.org/guide/latest/push_constants.html

Note, i am referring to this attempt. Last time i checked codex’s approach i got the impression that it was ment to create a implementation that makes use of the enforced ways vulcan wants to render.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_19 Mon, 16 Mar 2026 06:54:06 +0000 hub.jmonkeyengine.org-post-383944
An attempt at Vulkan
adi.barda:

Maybe I can help with that. I have some experience with ANTLR4 and can try write the transpiler. problem is that I’m not familiar with GLSL so there will be a learning curve. Question is whether it’s the right direction to solve the problem?

I’m not sure. I’m also learning and writing code at the same time. I can’t guarantee that this is correct.

When I have completed the development of the function to a certain extent, I will contribute the code to the community. However, currently the code is still rather rudimentary and the functions are not yet fully developed.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_18 Mon, 16 Mar 2026 06:44:50 +0000 hub.jmonkeyengine.org-post-383943
Rapid Escalation (First Steam Prototype) Awesome feedback, thanks a lot.

The screenshot looks like a bug with reading the property in the properties file. It is used for multi language support.

What do you mean by this? Because there is a lock and plus icon in the top right corner:

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_5 Mon, 16 Mar 2026 06:26:35 +0000 hub.jmonkeyengine.org-post-383942
An attempt at Vulkan
icyboxs:

This misalignment requires moving beyond “text substitution” to “semantic-level adaptation.

If I understand you correctly we need a real transpiler to convert from JME GLSL to Vulvan’s GLSL.
Maybe I can help with that. I have some experience with ANTLR4 and can try write the transpiler. problem is that I’m not familiar with GLSL so there will be a learning curve. Question is whether it’s the right direction to solve the problem?

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_17 Mon, 16 Mar 2026 05:16:49 +0000 hub.jmonkeyengine.org-post-383941
An attempt at Vulkan What happens in the OpenGL backend

In GLRenderer(jME’s OpenGL renderer):

  • Renderer.setShader(shader)ensures the program is linked.

  • Each Uniforminternally holds a uniform location (the result of glGetUniformLocation, or UBO block/offset information).

  • uniform.setValue()ultimately calls glUniform*or writes to a UBO (depending on the implementation).

You do not need to know the offset / std140 alignment / stride, because:

  • If using glUniform*: The driver finds the location and writes the value.

  • If using UBOs: OpenGL also provides APIs to query offsets (glGetActiveUniformsiv(..., GL_UNIFORM_OFFSET, ...)), meaning the driver calculates and provides it for you.

Therefore, in OpenGL, “reflection” mainly manifests as location queries, not as you calculating the layout yourself.

What’s missing in Vulkan

Vulkan has no glUniform*. You can only:

  1. Place all uniforms into a UBO/SSBO.

  2. Write a block of memory yourself.

  3. Have the shader read from that memory by offset.

Consequently, you must know:

  • What is the offset of m_Color?

  • What is the offset of g_WorldViewProjectionMatrix?

  • What is the stride for a mat3?

This information must come from either SPIR-V reflection or your own layout rules.

This is also a function that needs to be completed at present.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_16 Mon, 16 Mar 2026 02:57:23 +0000 hub.jmonkeyengine.org-post-383940
An attempt at Vulkan
icyboxs:

Currently, jMonkeyEngine’s shaders are filled with macro commands that prevent Vulkan from compiling properly

It would be interesting to unpack this statement.

JME uses macro commands as a compatibility layer… which presumably can be leveraged even for vulkan. At least, it seemed like many of the errors in your original shader compiler failure could have been worked around with a new set of vulkan-compatible macros.

Caveat: I don’t really know much about vulkan specifics.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_15 Mon, 16 Mar 2026 01:48:16 +0000 hub.jmonkeyengine.org-post-383939
An attempt at Vulkan The current conversion method (regex rewriting of GLSL) can only address surface-level syntax differences (version, attribute/varying, gl_FragColor, layout injection). However, Vulkan requires determinism in resource binding and pipeline layout, whereas jME’s shaders are dynamically generated based on defines, materials, and lighting, with uniforms, textures, and variants all being dynamic. This misalignment requires moving beyond “text substitution” to “semantic-level adaptation.”

Vulkan requires “explicit layout/binding”, whereas most jME GLSL relies on implicit conventions.
Vulkan GLSL/SPIR-V typically requires:
layout(location=…) in/out
layout(set=…, binding=…) uniform …
Fragment shader output: layout(location=0) out vec4 …(cannot rely on gl_FragColor)
However, jME’s shader generation, for compatibility with older GLSL, commonly uses:
attribute/varying(legacy syntax)
gl_FragColor
uniform sampler2D m_ColorMap;(without layout qualifiers)
Many #ifdefmacro branches that determine whether variables are declared or used.
Therefore, you must “guess” and inject layout qualifiers. Without structured parsing at this stage, it’s prone to issues like:
Duplicate injection
Incorrect injection order
Mismatch between locationand the actual mesh buffer
Compilation failures due to declaration/usage inconsistencies within macro branches.

OpenGL provides a “driver-managed parameter submission interface” (glUniform, state machine, texture units). The application only needs to set values by name/location, without needing to know the memory layout or binding tables.

Vulkan makes all these implicit mechanisms explicit: the application must create layouts, write buffers, bind descriptors, and must know the shader interface ABI. Therefore, reflection becomes a necessary tool.

Currently, we are considering modifying the Material in jme-core and establishing a new mapping for Vulkan.

Of course, I’m still learning to see if there are any better ways. :grin:

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_14 Mon, 16 Mar 2026 01:23:47 +0000 hub.jmonkeyengine.org-post-383938
Rapid Escalation (First Steam Prototype) nice game.

-I would like to have a visual clue of the upgrade i can buy. currently i have to hover over all slots to see which i can afford.
-Initially i tough i missed something or there is a bug because of the short game time.
-It feels strange that you have to go to the upgrade menu to be able to go to the main menu.

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_4 Sun, 15 Mar 2026 21:59:30 +0000 hub.jmonkeyengine.org-post-383937
I'm new but jME doesn't start. I'm using IntelliJ Com edition, but I cant start it. I use Mine. Can someone explain me how to do it? Another is to go you gradle-wrapper.properties, located in /gradle/wrapper folder in your project.

There is a property called distributionUrl and the url gives the version of the gradle. What version do you have? Perhaps editing it to a lower version (i.e. 7.6.6, or 8.14.4) and reload the build may help

]]>
https://hub.jmonkeyengine.org/t/im-new-but-jme-doesnt-start-im-using-intellij-com-edition-but-i-cant-start-it-i-use-mine-can-someone-explain-me-how-to-do-it/49437#post_7 Sun, 15 Mar 2026 19:58:58 +0000 hub.jmonkeyengine.org-post-383936
An attempt at Vulkan
icyboxs:

From the current perspective, the best approach seems to be using regular expressions to replace parts of the GLSL code. However, this would require writing multi-layer nested content, which could make future maintenance difficult

Can you explain this statement more? what exactly do you want to achieve? give an example if you can for something that would be hard to achieve with the regex you mentioned

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_13 Sun, 15 Mar 2026 19:45:47 +0000 hub.jmonkeyengine.org-post-383935
I'm new but jME doesn't start. I'm using IntelliJ Com edition, but I cant start it. I use Mine. Can someone explain me how to do it? Could you quote your gradle/libs.versions.toml file here, it looks like something has gone wrong with it

]]>
https://hub.jmonkeyengine.org/t/im-new-but-jme-doesnt-start-im-using-intellij-com-edition-but-i-cant-start-it-i-use-mine-can-someone-explain-me-how-to-do-it/49437#post_6 Sun, 15 Mar 2026 19:15:31 +0000 hub.jmonkeyengine.org-post-383934
VibeCity I added a few things to my jmonkeyengine fork. gl 4.3 i think is the minimum supported version. sorry osx
-Bindless Textures
-MultiDrawIndirect
-Proper compute shader integration
-GpuInfo to get available/free memory

Some parts are still quite raw opengl, but thats how it is at the moment.

in case anyone is interested in playing with the features: GitHub - zzuegg/jmonkeyengine: A complete 3D game development suite written purely in Java. · GitHub

Compute Shaders:

  // Create output texture and upload to GPU
  Texture2D tex = new Texture2D(new Image(Image.Format.RGBA8, 256, 256, data, null, ColorSpace.Linear));

  // Dispatch compute via Material
  Material compute = new Material(assetManager, "Common/MatDefs/Compute/MyCompute.j3md");
  compute.setInt("Width", 256);
  compute.setImage("OutputImage", tex, TextureImage.Access.WriteOnly);
  compute.dispatch("TechniqueName", renderManager, 16, 16, 1);

  renderer.memoryBarrier(GL4.GL_ALL_BARRIER_BITS);

  // Use result as a regular texture
  displayMat.setTexture("ColorMap", tex);

Bindless Textures:

//Enabling Bindless support 
AppSettings.setBindlessTextures(true);


  // 2. Load textures and force GPU upload to create handles
  Texture2D[] textures = new Texture2D[4];
  for (int i = 0; i < textures.length; i++) {
      textures[i] = (Texture2D) assetManager.loadTexture(paths[i]);
      renderer.preloadTexture(textures[i]);
  }

  // 3. Write 64-bit handles into an SSBO
  BufferObject ssbo = new BufferObject();
  ssbo.initializeEmpty(textures.length * 8);  // 8 bytes per handle (long)
  ByteBuffer buf = ssbo.getData();
  for (Texture2D tex : textures) {
      buf.putLong(tex.getImage().getBindlessHandle());
  }
  buf.rewind();


  // 4. Bind SSBO to material
  Material mat = new Material(assetManager, "MyBindlessMaterial.j3md");
  mat.setShaderStorageBufferObject("TextureHandles", ssbo);

 // 5. Then in the fragment shader (GLSL):
  layout(std430, binding = 0) buffer TextureHandles {
      sampler2D texHandles[];
  };

  in vec2 texCoord;
  flat in int instanceId;
  out vec4 fragColor;

  void main() {
      fragColor = texture(texHandles[instanceId], texCoord);
  }

//The required extension is automatically added to the shader if bindless is enabled and supported
#extension GL_ARB_bindless_texture : require

I am still working on how to create a nicer to use api for drawindirect, but you can look at the screenshot tests to see it in action. The key classes are:

IndirectCommandBuffer
MeshCombiner
renderManager.renderGeometryIndirect(geom, cmdBuf);

]]>
https://hub.jmonkeyengine.org/t/vibecity/49418#post_16 Sun, 15 Mar 2026 19:00:11 +0000 hub.jmonkeyengine.org-post-383933
Rapid Escalation (First Steam Prototype) Thanks. Oops, no I did not mean to add the email as required field.

I will remove now.

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_3 Sun, 15 Mar 2026 17:04:18 +0000 hub.jmonkeyengine.org-post-383932
(March 2026) Monthly WIP Screenshot Thread mostly working on game mechanics and additional content. the water filter here applies some experimental extra calculations like a second deep water color of sorts.

]]>
https://hub.jmonkeyengine.org/t/march-2026-monthly-wip-screenshot-thread/49428#post_9 Sun, 15 Mar 2026 16:49:09 +0000 hub.jmonkeyengine.org-post-383931
I'm new but jME doesn't start. I'm using IntelliJ Com edition, but I cant start it. I use Mine. Can someone explain me how to do it?

maby this could help you. These are the warnings which always come if i rebuild. I cant run it

]]>
https://hub.jmonkeyengine.org/t/im-new-but-jme-doesnt-start-im-using-intellij-com-edition-but-i-cant-start-it-i-use-mine-can-someone-explain-me-how-to-do-it/49437#post_5 Sun, 15 Mar 2026 16:08:36 +0000 hub.jmonkeyengine.org-post-383930
Rapid Escalation (First Steam Prototype) Nice! This looks well on the way!

Did you mean to include email address as a required field in the feedback form? It might discourage people from filling in the feedback form

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_2 Sun, 15 Mar 2026 15:30:57 +0000 hub.jmonkeyengine.org-post-383929
I'm new but jME doesn't start. I'm using IntelliJ Com edition, but I cant start it. I use Mine. Can someone explain me how to do it? What if you go to the main method and right click it (probably DesktopLauncher if you generated the project this week), does it look like this with the option to run it? (If so what happens when you run it?)

If those green start buttons aren’t there are there any warnings (like “SDK not set up”).

What happens when you try to build, any errors?

]]>
https://hub.jmonkeyengine.org/t/im-new-but-jme-doesnt-start-im-using-intellij-com-edition-but-i-cant-start-it-i-use-mine-can-someone-explain-me-how-to-do-it/49437#post_4 Sun, 15 Mar 2026 15:03:25 +0000 hub.jmonkeyengine.org-post-383928
I'm new but jME doesn't start. I'm using IntelliJ Com edition, but I cant start it. I use Mine. Can someone explain me how to do it? I used the initializer. By the way, thank you! The play symbole was just grey.

]]>
https://hub.jmonkeyengine.org/t/im-new-but-jme-doesnt-start-im-using-intellij-com-edition-but-i-cant-start-it-i-use-mine-can-someone-explain-me-how-to-do-it/49437#post_3 Sun, 15 Mar 2026 14:44:46 +0000 hub.jmonkeyengine.org-post-383927
Rapid Escalation (First Steam Prototype) Good day jME community.

Hope you are all well. For the past few weeks I have been working on what I hope to be my very first Steam game. I’ve got the game at a level where I want to share it with people to play test and validate.

This is where I need your help, I need some play testing of the game.

Currently it is available on itch.io at the following location:

Peek5

Peek1

Peek2

There is a feedback button on the main menu, when done playing, please quickly complete the form, it would make this game what I want it to be.

Thanks in advance.

]]>
https://hub.jmonkeyengine.org/t/rapid-escalation-first-steam-prototype/49438#post_1 Sun, 15 Mar 2026 11:54:58 +0000 hub.jmonkeyengine.org-post-383926
I'm new but jME doesn't start. I'm using IntelliJ Com edition, but I cant start it. I use Mine. Can someone explain me how to do it? hello @Jonas1 and welcome to the JME Community.

Did you create your project with the initializer or created a gradle project in intelliJ and added the dependencies?

Please paste of the error messages you are getting when you try to run the project. I use IntelliJ as well but I make my gradle project without the initializer and I may be able to help.

]]>
https://hub.jmonkeyengine.org/t/im-new-but-jme-doesnt-start-im-using-intellij-com-edition-but-i-cant-start-it-i-use-mine-can-someone-explain-me-how-to-do-it/49437#post_2 Sun, 15 Mar 2026 07:56:18 +0000 hub.jmonkeyengine.org-post-383925
I'm new but jME doesn't start. I'm using IntelliJ Com edition, but I cant start it. I use Mine. Can someone explain me how to do it? I just used the open butten in the newest intellij and jmonkey version. Im sorry but no one was able to help me. And i use java 17 and the perfect gradle

]]>
https://hub.jmonkeyengine.org/t/im-new-but-jme-doesnt-start-im-using-intellij-com-edition-but-i-cant-start-it-i-use-mine-can-someone-explain-me-how-to-do-it/49437#post_1 Sun, 15 Mar 2026 06:57:30 +0000 hub.jmonkeyengine.org-post-383924
An attempt at Vulkan I’m stuck on this too. Slang offers a good solution but unfortunately there are no java bindings for it yet. I’ve toyed around with making my own bindings but haven’t made a whole lot of progress.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_12 Sun, 15 Mar 2026 01:32:50 +0000 hub.jmonkeyengine.org-post-383923
VibeCity worked mostly moving my rendering to use bindless textures and ssbo’s


the visible pointlights in the air are actual sideeffect where the light refracts with the volumetric fog at close distance. not sure how to fix, and technically it would be correct.

]]>
https://hub.jmonkeyengine.org/t/vibecity/49418#post_15 Sun, 15 Mar 2026 00:36:13 +0000 hub.jmonkeyengine.org-post-383922
An attempt at Vulkan I’m a bit stuck and need a solution to make OpenGL’s GLSL compatible with Vulkan’s GLSL. I’ve looked up some literature, but none of it seems suitable for the current situation. Vulkan uses descriptors for binding, while OpenGL is different. Currently, jMonkeyEngine’s shaders are filled with macro commands that prevent Vulkan from compiling properly. Although both APIs can use GLSL, they still have differences in input handling. From the current perspective, the best approach seems to be using regular expressions to replace parts of the GLSL code. However, this would require writing multi-layer nested content, which could make future maintenance difficult. I’ve also looked at other game engines like UE and Unity, which seem to use a unique shading language that can compile into the binary files required by the target API, but this doesn’t seem ideal for jMonkeyEngine’s transition. So now I’m contemplating a way to both avoid modifying the current jMonkeyEngine shader content and achieve Vulkan compatibility. If anyone has relevant knowledge in this area, please share it with me. Thank you very much.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_11 Sun, 15 Mar 2026 00:08:00 +0000 hub.jmonkeyengine.org-post-383921
An attempt at Vulkan https://youtu.be/eYkkGzoRzkU
A piece of good news: I can now successfully use most of the frontend functionalities in jMonkeyEngine 3.

package com.jme3.lwjgl.test;

import com.jme3.app.FlyCamAppState;
import com.jme3.app.LegacyApplication;
import com.jme3.asset.plugins.ClasspathLocator;
import com.jme3.input.FlyByCamera;
import com.jme3.input.RawInputListener;
import com.jme3.input.event.JoyAxisEvent;
import com.jme3.input.event.JoyButtonEvent;
import com.jme3.input.event.KeyInputEvent;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent;
import com.jme3.input.event.TouchEvent;
import com.jme3.material.Material;
import com.jme3.material.plugins.J3MLoader;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.ViewPort;

import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Quad;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeSystem;
import com.jme3.system.VulkanSystemDelegate;

public class VulkanMaterialUnshadedApp extends LegacyApplication {

    private Node rootNode = new Node("Root");
    private ViewPort viewPort;
    private Camera cam;

    private FlyCamAppState flyCamState;
    private boolean flyConfigured = false;

    @Override
    public void initialize() {
        super.initialize();
        assetManager.registerLocator("/", ClasspathLocator.class);
        assetManager.registerLoader(J3MLoader.class, "j3md", "j3m");

        cam = getCamera();
        viewPort = renderManager.createMainView("Main", cam);
        viewPort.attachScene(rootNode);

        Quad q = new Quad(1f, 1f);
        Geometry g = new Geometry("quad", q);

        Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        m.setColor("Color", ColorRGBA.White);
        g.setMaterial(m);
        rootNode.attachChild(g);

        cam.setLocation(new Vector3f(0, 0, 10f));
        cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
        cam.setFrustumPerspective(45f, (float) cam.getWidth() / cam.getHeight(), 0.1f, 100f);

        flyCamState = new FlyCamAppState();
        flyCamState.initialize(stateManager, this);
        stateManager.attach(flyCamState);

        // 不要在这里立刻 getCamera() 配置
        // 验证输入对象是否为 GLFW 真实实现
        inputManager.addRawInputListener(new RawInputListener() {
            @Override
            public void beginInput() {
            }

            @Override
            public void endInput() {
            }

            @Override
            public void onKeyEvent(KeyInputEvent evt) {
                if (evt.isPressed()) {
                    System.out.println("KEY pressed: " + evt.getKeyCode());
                }
            }

            @Override
            public void onMouseMotionEvent(MouseMotionEvent evt) {
            }

            @Override
            public void onMouseButtonEvent(MouseButtonEvent evt) {
            }

            @Override
            public void onJoyAxisEvent(JoyAxisEvent evt) {
            }

            @Override
            public void onJoyButtonEvent(JoyButtonEvent evt) {
            }

            @Override
            public void onTouchEvent(TouchEvent evt) {
            }
        });
//        FlyByCamera flyCam = flyCamState.getCamera();
//        flyCam.setMoveSpeed(5f);
//        flyCam.setDragToRotate(false);
//        flyCam.registerWithInput(inputManager);
        
    }

    @Override
    public void update() {
        super.update();

        float tpf = timer.getTimePerFrame();



        // 3) scene 更新 + 渲染
        rootNode.updateLogicalState(tpf);
        rootNode.updateGeometricState();

        if (context != null && context.isRenderable()) {
            renderManager.render(tpf, true);
        }
    }

    public static void main(String[] args) {
        JmeSystem.setSystemDelegate(new VulkanSystemDelegate());

        AppSettings s = new AppSettings(true);
        s.setCustomRenderer(com.jme3.renderer.vulkan.LwjglVulkanContext.class);
        s.setWidth(1280);
        s.setHeight(720);

        VulkanMaterialUnshadedApp app = new VulkanMaterialUnshadedApp();
        app.setSettings(s);
        app.start();
    }
}

The current issue is how to handle the shaders. I might need to go to the library as I haven’t found any information about OpenGL compatibility with Vulkan on the internet. If anyone else has any findings, please let me know.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_10 Sat, 14 Mar 2026 23:49:53 +0000 hub.jmonkeyengine.org-post-383920
Resizing canvas in a Swing application Never mind guys. Claude finally fixed it.

He added this fix to the main Swing app:
```

public static void main(String[] args) {

    // Fix HiDPI gap in JME3/LWJGL2 canvas: Java 9+ declares the process
    // as DPI-aware, so the GL framebuffer is at physical pixel resolution
    // but Canvas.getWidth()/getHeight() report logical pixels.  This causes
    // glViewport to cover only (1/scale) of the framebuffer, leaving gaps
    // on the right and bottom edges.  Disabling Java's DPI scaling makes
    // logical == physical so the viewport fills the entire framebuffer.
    System.setProperty("sun.java2d.uiScale", "1");

    // Compensate by letting FlatLaf scale the Swing UI independently.
    // Toolkit.getScreenResolution() returns the OS DPI (e.g. 120 for 125%)
    // via the native GetDeviceCaps API, unaffected by sun.java2d.uiScale.
    try {
        int dpi = Toolkit.getDefaultToolkit().getScreenResolution();
        float scale = dpi / 96f;
        if (scale > 1f) {
            System.setProperty("flatlaf.uiScale", String.valueOf(scale));
        }
    } catch (Exception ignored) {
    }
``` 
]]>
https://hub.jmonkeyengine.org/t/resizing-canvas-in-a-swing-application/49436#post_2 Sat, 14 Mar 2026 21:36:31 +0000 hub.jmonkeyengine.org-post-383919
An attempt at Vulkan the glslvalidator should handle the preprocessors. at least if they are not engine custom, but then the engine should unroll them

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_9 Sat, 14 Mar 2026 18:38:31 +0000 hub.jmonkeyengine.org-post-383918
An attempt at Vulkan The shader is filled with a large number of macro commands.

This made my revisions extremely difficult.

My current idea is to perform the check at the front end rather than at the Vulkan backend.

That is to say: Before the Shader is handed over to the Renderer, you have already obtained the source and defines for each stage.

At this point, pure string patches (such as replacing macro guards, correcting attributes/varyings, inserting layouts, etc.) can be performed.
Static checks can also be conducted (such as balancing #if/#endif, checking for bare uniforms, and verifying if there are duplicate locations, etc.)

Of course, this is just a theory.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_8 Sat, 14 Mar 2026 18:34:18 +0000 hub.jmonkeyengine.org-post-383917
An attempt at Vulkan The resource binding methods of Vulkan and OpenGL seem to be quite different. What is certain at present is that to support Vulkan shaders, some macros are needed to distinguish them.

My current thinking is to try to avoid modifying the current OpenGL as much as possible.

I plan to complete the minimal modifications first.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_7 Sat, 14 Mar 2026 15:17:01 +0000 hub.jmonkeyengine.org-post-383915
An attempt at Vulkan Shaderc for crosscompilation.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_6 Sat, 14 Mar 2026 13:34:00 +0000 hub.jmonkeyengine.org-post-383914
Resizing canvas in a Swing application Hello Community,
I have an issue with resizing the JME canvas inside my Swing application.
The canvas set to some size inside the hosting panel and when the user changes the layout (resize) the canvas is also resized proportionally as expected.
The problem is that it doesn’t stretch to the full size of it’s hosting panel (see attached video clip for reference). It always has significant padding on the right / bottom.

Here is the initialization code for reference:
```

private void initJME3() {
    app = new DesignerApp();
    app.setProjectPath(projectPath);
    app.setDesignerFile(designerFile);

    // Load document
    if (designerFile.exists() && designerFile.length() > 0) {
        try {
            app.setDocument(DesignerDocument.load(designerFile));
        } catch (IOException e) {
            System.err.println("Failed to load designer document: " + e.getMessage());
            app.setDocument(new DesignerDocument(designerFile.getAbsolutePath()));
        }
    } else {
        app.setDocument(new DesignerDocument(designerFile.getAbsolutePath()));
    }

    // Forward the scripts tree refresh callback to the app
    if (scriptsTreeRefreshCallback != null) {
        app.setScriptsTreeRefreshCallback(scriptsTreeRefreshCallback);
    }

    // Forward the code file updated callback to the app
    if (codeFileUpdatedCallback != null) {
        app.setCodeFileUpdatedCallback(codeFileUpdatedCallback);
    }

    // Set callback so the app can notify us of changes
    app.setDesignerPanelCallback(new DesignerApp.DesignerPanelCallback() {
        @Override
        public void onSelectionChanged(DesignerEntity entity) {
            SwingUtilities.invokeLater(() -> updatePropertiesPanel(entity));
        }

        @Override
        public void onSceneChanged() {
            SwingUtilities.invokeLater(() -> refreshSceneTree());
        }
    });

    AppSettings settings = new AppSettings(true);
    settings.setWidth(800);
    settings.setHeight(600);
    settings.setSamples(4);
    settings.setVSync(true);
    settings.setFrameRate(60);
    settings.setGammaCorrection(false);

    app.setSettings(settings);
    app.setPauseOnLostFocus(false);
    app.setShowSettings(false);
    app.createCanvas();

    JmeCanvasContext ctx = (JmeCanvasContext) app.getContext();
    ctx.setSystemListener(app);
    canvas = ctx.getCanvas();
    // Let the canvas fill all available space - no fixed preferred size
    canvas.setMinimumSize(new Dimension(100, 100));

    // Insert canvas into the right side of the main split
    JSplitPane mainSplit = (JSplitPane) ((BorderLayout) getLayout()).getLayoutComponent(BorderLayout.CENTER);
    JPanel canvasPanel = (JPanel) mainSplit.getRightComponent();
    canvasPanel.add(canvas, BorderLayout.CENTER);

    // Resize JME3 viewport when the canvas is resized
    canvas.addComponentListener(new ComponentAdapter() {
        @Override
        public void componentResized(ComponentEvent e) {
            int w = canvas.getWidth();
            int h = canvas.getHeight();
            if (w > 0 && h > 0 && app != null) {
                app.enqueue(() -> {
                    app.onCanvasResized(w, h);
                    return null;
                });
            }
        }
    });

    app.startCanvas();

```
So far I tried to modify the AppSettings (Width / Height), The canvas settings (setPreferredSize, setMinimumSize), the canvas listener code (on componentResized modified the width / height).
I searched the forum and found some issues with the canvas inside Swing applications. Not sure what is the best approach for dealing with my issue.
The canvas works just fine and resized just fine. It’s just this unwanted padding.
It’s not a deal breaker but it’s annoying :slight_smile:

WDYT?
Thanks in advance

]]>
https://hub.jmonkeyengine.org/t/resizing-canvas-in-a-swing-application/49436#post_1 Sat, 14 Mar 2026 13:22:48 +0000 hub.jmonkeyengine.org-post-383913
An attempt at Vulkan 3月 14, 2026 9:07:20 下午 com.jme3.renderer.vulkan.VKRenderer initialize 信息: VKRenderer initialized. Caps=[FrameBuffer, FrameBufferMRT, GLSL150, GLSL330, GLSL400, GLSL410, GLSL420, GLSL430, GLSL440, GLSL450, VertexBufferArray, PackedDepthStencilBuffer, TextureCompressionS3TC, DepthTexture, GLSL310], limits={VertexTextureUnits=16, FragmentTextureUnits=16} java.lang.AssertionError: Shader compilation failed: jme-vert: error: #version: Desktop shaders for Vulkan SPIR-V require version 140 or higher jme-vert:324: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:325: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:326: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:327: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:328: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:329: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:330: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:331: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:632: warning: attribute deprecated in version 130; may be removed in future release jme-vert:632: error: 'location' : SPIR-V requires location for user input/output jme-vert:638: warning: attribute deprecated in version 130; may be removed in future release jme-vert:638: error: 'location' : SPIR-V requires location for user input/output jme-vert:639: warning: attribute deprecated in version 130; may be removed in future release jme-vert:639: error: 'location' : SPIR-V requires location for user input/output jme-vert:640: warning: attribute deprecated in version 130; may be removed in future release jme-vert:640: error: 'location' : SPIR-V requires location for user input/output jme-vert:642: warning: varying deprecated in version 130; may be removed in future release jme-vert:642: error: 'location' : SPIR-V requires location for user input/output jme-vert:643: warning: varying deprecated in version 130; may be removed in future release jme-vert:643: error: 'location' : SPIR-V requires location for user input/output jme-vert:645: warning: varying deprecated in version 130; may be removed in future release jme-vert:645: error: 'location' : SPIR-V requires location for user input/output jme-vert:679: error: '' : unexpected token at com.jme3.renderer.vulkan.VKUtil.glslToSpirvFromString(VKUtil.java:388) at com.jme3.renderer.vulkan.VulkanShaders.getOrCreateModuleFromGlslString(VulkanShaders.java:60) at com.jme3.renderer.vulkan.VulkanPipeline.createGraphicsPipeline(VulkanPipeline.java:182) at com.jme3.renderer.vulkan.VulkanPipeline.init(VulkanPipeline.java:71) at com.jme3.renderer.vulkan.VulkanRuntime.getOrCreatePipeline(VulkanRuntime.java:166) at com.jme3.renderer.vulkan.VKRenderer.recordFrame(VKRenderer.java:427) at com.jme3.renderer.vulkan.VulkanFrameDriver.renderOneFrame(VulkanFrameDriver.java:116) at com.jme3.renderer.vulkan.VulkanRuntime.renderFrame(VulkanRuntime.java:323) at com.jme3.renderer.vulkan.LwjglVulkanContext.run(LwjglVulkanContext.java:73) at java.base/java.lang.Thread.run(Thread.java:833) 3月 14, 2026 9:07:20 下午 com.jme3.app.LegacyApplication handleError 严重: Vulkan render thread crashed java.lang.AssertionError: Shader compilation failed: jme-vert: error: #version: Desktop shaders for Vulkan SPIR-V require version 140 or higher jme-vert:324: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:325: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:326: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:327: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:328: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:329: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:330: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:331: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:632: warning: attribute deprecated in version 130; may be removed in future release jme-vert:632: error: 'location' : SPIR-V requires location for user input/output jme-vert:638: warning: attribute deprecated in version 130; may be removed in future release jme-vert:638: error: 'location' : SPIR-V requires location for user input/output jme-vert:639: warning: attribute deprecated in version 130; may be removed in future release jme-vert:639: error: 'location' : SPIR-V requires location for user input/output jme-vert:640: warning: attribute deprecated in version 130; may be removed in future release jme-vert:640: error: 'location' : SPIR-V requires location for user input/output jme-vert:642: warning: varying deprecated in version 130; may be removed in future release jme-vert:642: error: 'location' : SPIR-V requires location for user input/output jme-vert:643: warning: varying deprecated in version 130; may be removed in future release jme-vert:643: error: 'location' : SPIR-V requires location for user input/output jme-vert:645: warning: varying deprecated in version 130; may be removed in future release jme-vert:645: error: 'location' : SPIR-V requires location for user input/output jme-vert:679: error: '' : unexpected token at com.jme3.renderer.vulkan.VKUtil.glslToSpirvFromString(VKUtil.java:388) at com.jme3.renderer.vulkan.VulkanShaders.getOrCreateModuleFromGlslString(VulkanShaders.java:60) at com.jme3.renderer.vulkan.VulkanPipeline.createGraphicsPipeline(VulkanPipeline.java:182) at com.jme3.renderer.vulkan.VulkanPipeline.init(VulkanPipeline.java:71) at com.jme3.renderer.vulkan.VulkanRuntime.getOrCreatePipeline(VulkanRuntime.java:166) at com.jme3.renderer.vulkan.VKRenderer.recordFrame(VKRenderer.java:427) at com.jme3.renderer.vulkan.VulkanFrameDriver.renderOneFrame(VulkanFrameDriver.java:116) at com.jme3.renderer.vulkan.VulkanRuntime.renderFrame(VulkanRuntime.java:323) at com.jme3.renderer.vulkan.LwjglVulkanContext.run(LwjglVulkanContext.java:73) at java.base/java.lang.Thread.run(Thread.java:833) 3月 14, 2026 9:07:20 下午 com.jme3.system.JmeSystemDelegate lambda$new$0 警告: JmeDialogsFactory implementation not found. Vulkan render thread crashed AssertionError: Shader compilation failed: jme-vert: error: #version: Desktop shaders for Vulkan SPIR-V require version 140 or higher jme-vert:324: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:325: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:326: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:327: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:328: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:329: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:330: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:331: error: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan jme-vert:632: warning: attribute deprecated in version 130; may be removed in future release jme-vert:632: error: 'location' : SPIR-V requires location for user input/output jme-vert:638: warning: attribute deprecated in version 130; may be removed in future release jme-vert:638: error: 'location' : SPIR-V requires location for user input/output jme-vert:639: warning: attribute deprecated in version 130; may be removed in future release jme-vert:639: error: 'location' : SPIR-V requires location for user input/output jme-vert:640: warning: attribute deprecated in version 130; may be removed in future release jme-vert:640: error: 'location' : SPIR-V requires location for user input/output jme-vert:642: warning: varying deprecated in version 130; may be removed in future release jme-vert:642: error: 'location' : SPIR-V requires location for user input/output jme-vert:643: warning: varying deprecated in version 130; may be removed in future release jme-vert:643: error: 'location' : SPIR-V requires location for user input/output jme-vert:645: warning: varying deprecated in version 130; may be removed in future release jme-vert:645: error: 'location' : SPIR-V requires location for user input/output jme-vert:679: error: '' : unexpected token

It seems that I have reached a crossroads regarding shaders. It seems that I can only choose to modify the writing method of the shaders or to abstract them to achieve compatibility between OpenGL and Vulkan.
It seems a bit challenging to simultaneously support GLSL inputs for both OpenGL and Vulkan. I need to look into how other engines achieve this.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_5 Sat, 14 Mar 2026 13:10:27 +0000 hub.jmonkeyengine.org-post-383912
(Q1 - 2026) Quarterly Marketing Thread After 4 months of having the X/Twitter verified subscription for the engine’s page, I’ve decided to cancel it. The total cost for that time was $26.50, however I can certainly say we’d have gotten more reach from simply doing $25 worth of promoted posts. I also believe that jME’s limited funds would be much better left for our hosting fees or bounties instead of marketing anyways.

The only true benefit of the verified subscription was “boosted replies” however there’s also a higher subscription tier (that costs a whopping 40 a month, easily veering into scam territory in my opinion) that gives users even more of a “reply boost” (effectively making the boost for our cheaper tier less effective) and if any of you use twitter, then you likely know how much of a spam-fest the replies on any trending/viral post tend to be. The amount of time it would take replying to game dev related posts to get users’ attention simply isn’t worth it, not by a long shot.

A single 8 dollar promoted post would vastly outweigh the benefits of the X/Twitter subscription for a month. So I likely will never revisit the X/Twitter verified subscription for my own game either, and I will be reserving the limited marketing budget I have for more effective forms of marketing.

I’d ultimately call it useless for marketing any product/service unless you really have the time to spam replies all day, and even then, I question how effective that marketing strategy is considering some people tend to find that type of behavior annoying if done too much. There’s also a negative stigma that many people have toward profiles that pay for the verified badge, viewing it as a badge of shame of some sorts. Although I think this is truer for average joes and wannabe content creators with the verified subscription who spam every trending post with memes and rage bait in an attempt to get noticed, and being verified likely isn’t viewed as negatively for game devs or organizations like jME that actually have a product/service to provide, but the fact that there is a negative stigma at all is still an important aspect to consider.

So the verified subscription was worth trying, but in hindsight it is definitely not worth it, and there’s much better uses of a marketing budget that would yield better results for marketing a game engine or an indie game.

]]>
https://hub.jmonkeyengine.org/t/q1-2026-quarterly-marketing-thread/49398#post_6 Sat, 14 Mar 2026 04:15:22 +0000 hub.jmonkeyengine.org-post-383910
An attempt at Vulkan Based on the information I have, I plan to create a Vulkan backend to try to fully support the frontend of JME. This means that I need to use Vulkan to implement the OpenGL API.

Currently, my plan is to temporarily disregard the issues related to performance and design. At each step, we should try to minimize any modifications until we can ensure that the JME front-end can function properly using Vulkan.

From a theoretical perspective, all OpenGL functions should be achievable.

My current plan is to first complete the necessary content for the JME front-end, and then look into the performance issues.

I know this is a very large project, but I would rather it be an attempt to explore modern graphics APIs so that I can gain a deeper understanding of Vulkan.

My personal opinion is that OpenGL should gradually be abandoned rather than being abandoned immediately.

Based on the current development trend, it will still take some time before the performance level can surpass that of OpenGL.

OpenGL is still a very good choice for beginners as an entry-level learning tool.
The learning curve of Vulkan is extremely steep.

If you play Minecraft, please keep an eye on the latest version of Vulkan.

I suspect that Vulkan will not significantly enhance the performance of many games.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_4 Fri, 13 Mar 2026 13:47:42 +0000 hub.jmonkeyengine.org-post-383909
An attempt at Vulkan So you are planning to write a compatibility layer, similar to Google ANGLE, instead of doing a full rewrite as it is being done in 2545?

I really like this idea. It would help maintain OpenGL-based games without having to deal with aging OpenGL drivers. That is the same reasoning that led me to start working on implementing ANGLE as a backend in 2585.

The key difference in your approach is that we would have access to Vulkan inside JME, which would give us the opportunity to progressively implement Vulkan functionality directly into the engine over time.

It seems like a big project, if it can help make it more feasible, I believe you could consider targeting the smaller GLES 3.0 subset instead of full OpenGL. The engine is already essentially a GLES-based engine due to Android support, and everything that is OpenGL-only already has a GLES fallback.

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_3 Fri, 13 Mar 2026 09:21:54 +0000 hub.jmonkeyengine.org-post-383908
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).

]]>
https://hub.jmonkeyengine.org/t/an-attempt-at-vulkan/49433#post_2 Fri, 13 Mar 2026 00:10:08 +0000 hub.jmonkeyengine.org-post-383907
(March 2026) Monthly WIP Screenshot Thread
bindless textures
multi draw indirect
morph targets and 1 bone animation currently
directly rendering the makehuman model and assets
50000 people
1 drawcall, no culling currently
codebase is quite a mess

]]>
https://hub.jmonkeyengine.org/t/march-2026-monthly-wip-screenshot-thread/49428#post_8 Thu, 12 Mar 2026 21:48:17 +0000 hub.jmonkeyengine.org-post-383906
AI created changes, should it create PR's or work on my own fork At one time, I had mapped out a multistep process to convert the vertex buffer type from being an enum to just being a class that had information in it… with a bunch of preset constants for the existing enum values. I can’t find those notes anymore but it was something like:

  1. convert VerextBuffer.Type to a real class with a set of constants representing the current enum values.
  2. deal with the collateral damage
  3. add the binding name to VertexBuffer.Type and stop auto-generating it. (I wouldn’t even automatically prefix ‘in’, personally.)

This is one of a couple places where JME abused ‘enum’ when old style constants would have been better and more flexible. (Off the top of my head, blend mode was another one.)

]]>
https://hub.jmonkeyengine.org/t/ai-created-changes-should-it-create-prs-or-work-on-my-own-fork/49434#post_12 Thu, 12 Mar 2026 14:18:48 +0000 hub.jmonkeyengine.org-post-383905
AI created changes, should it create PR's or work on my own fork this would be the best case, i went for the “minimal changes required” version. After all i think everybody using custom shaders/techniques was used to reuse existing types since ages.

]]>
https://hub.jmonkeyengine.org/t/ai-created-changes-should-it-create-prs-or-work-on-my-own-fork/49434#post_11 Thu, 12 Mar 2026 10:08:41 +0000 hub.jmonkeyengine.org-post-383904
AI created changes, should it create PR's or work on my own fork another option: still have the additional Generic type, but instead of name, have all VertexBuffer carry a bindPoint label.
When the renderer sees them, it tries first to check the bindPoint label, if there is one set, will try to bind in+bindPoint, if the bind fails or the label is not sets it fallsback to in+TypeName.

In this way, overtime, we can deprecate the fixed vertexbuffer types, that are a weird jme specific thing, anyway

]]>
https://hub.jmonkeyengine.org/t/ai-created-changes-should-it-create-prs-or-work-on-my-own-fork/49434#post_10 Thu, 12 Mar 2026 09:58:57 +0000 hub.jmonkeyengine.org-post-383903
AI created changes, should it create PR's or work on my own fork i think one clean way to implement this, would be to have a new vertexbuffer type “Generic” with no checks whatsoever and a custom “name” field to VertexBuffer (that doubles as debug label), then we can make the renderer bind Generic vertexbuffers to “in”+name

]]>
https://hub.jmonkeyengine.org/t/ai-created-changes-should-it-create-prs-or-work-on-my-own-fork/49434#post_9 Thu, 12 Mar 2026 09:53:16 +0000 hub.jmonkeyengine.org-post-383902
AI created changes, should it create PR's or work on my own fork I am actually not sure if the already existing shaders would break if i pass a vec4 tex coordinate. (Which is perfectly valid). I am alwasy talking custom shaders here obviously.

Currently the buffer type, aka name is not bound to an actual type. And only InstanceData is allowed to have more then 4 components. (It is a mat4 in the case of instancing)

]]>
https://hub.jmonkeyengine.org/t/ai-created-changes-should-it-create-prs-or-work-on-my-own-fork/49434#post_8 Thu, 12 Mar 2026 09:35:00 +0000 hub.jmonkeyengine.org-post-383901
AI created changes, should it create PR's or work on my own fork Yeah, that would of course be the better solution, but it would require this fix too.

]]>
https://hub.jmonkeyengine.org/t/ai-created-changes-should-it-create-prs-or-work-on-my-own-fork/49434#post_7 Thu, 12 Mar 2026 09:32:55 +0000 hub.jmonkeyengine.org-post-383900