After trying to use the material parameters for unshaded.j3md when I meant to use the material parameters for lighting.j3md for the umpteenth time I decided to see if I could do anything about it and make materials statically typed
Replacing this:
Material shipMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
shipMaterial.setTexture("DiffuseMap", someTexture);
shipMaterial.setTexture("GlowMap", someOtherTexture);
shipMaterial.setBoolean("UseVertexColor", true);
shipMaterial.setColor("Diffuse", ColorRGBA.White);
shipMaterial.setColor("Ambient", ColorRGBA.White);
With this
LightingMaterial shipMaterial = new LightingMaterial(assetManager);
shipMaterial.setDiffuseMap(someTexture); <--- these setters take typed arguments, not "Object"
shipMaterial.setGlowMap(someOtherTexture);
shipMaterial.setUseVertexColor(true);
shipMaterial.setDiffuse(ColorRGBA.White);
shipMaterial.setAmbient(ColorRGBA.White);
So I made a gradle plugin TypedMaterials to do just that. It scans the .j3md files (both locally and in dependencies) and synthesises classes based on the parameters in the MaterialParameters section of the definition. All classes are created in src/main/generated/java
which is added to source.Sets.main.java.srcs
in gradle. I haven’t hand typed any of these classes so they should stay up to date with new JME versions.
These materials extend the Material
class so can be used anywhere a Material
could be.
And (where available on the material) include the documentation as a javadoc
How do I use the plugin
Bare minimum
In the simplest case where you only want JME materials you can add the following to your build.gradle
buildscript{
repositories {
mavenCentral()
}
dependencies {
classpath "com.onemillionworlds:typed-materials:1.0.0"
}
}
plugins {
// java plugins as normal
}
apply plugin: 'com.onemillionworlds.typed-materials'
typedMaterials {
jmeMaterials()
}
//jme dependencies as normal
This will provide statically typed materials for the materials found in jme3-core and jme3-effects
Local materials
The plugin can also provide statically typed material classes for your own local materials. By default it assumes these materials are found within your module at src/main/resources/MatDefs
; if that’s the case this is the config
typedMaterials {
jmeMaterials()
localMaterialsSearch('com.yoursite.package.to.create.materials.in')
}
If you have your materials in a non standard location that can be passed as additional parameters
typedMaterials {
jmeMaterials()
localMaterialsSearch('com.yoursite.package', 'path/to/assets/materials', 'folderAtAssetsRoot')
}
e.g. (if migrating from the old assets folder)
typedMaterials {
jmeMaterials()
localMaterialsSearch('com.yoursite.package', 'assets', 'assets')
}
The first parameter is the path to where to find the materials (where to search) and the second is the folder that is the root of the assets (which is used to figure out how much of the directories structure to snip off for the asset name).
If you are also using lombok you may need to use a separate module; see Lombok-compatibility
Non JME library materials
If a 3rd party library is providing materials these can also be registered to generate java classes
typedMaterials {
....
librarySearch("libraryNameMaterials", ".*libraryname.*", "com.libraryname.materials")
}
The parameters are: task name, regex to select library, package to create materials in
Wrappers
In addition to the typed Materials (e.g. UnshadedMaterial) there are also wrappers (e.g. UnshadedMaterialWrapper) these are useful if you are not constructing a material but obtaining one in another way (e.g. using the getter on a material)
LightingMaterialWrapper lightingMaterial = new LightingMaterialWrapper(someGeometry.getMaterial()));
lightingMaterial.setDiffuseMap(someDiffuseMap)
These do not extend Material but you can get the underlying material back again if needed
lightingMaterial.getMaterial();
Material Factories
In addition to the Typed Materials and wrappers a MaterialFactory will also be generated. It can be used like this
MaterialFactory factory = MaterialFactory.INSTANCE;
LightingMaterial = factory.createMaterial(LightingMaterial.class);
This can be useful for projects that want to use mocking in their tests as the MaterialFactory
can be mocked (e.g. using Mockito) to produce mock materials (which would otherwise need a live AssetManager).