Aaahh, got it, thanks.
Unfortunately, the shadernode editor logs nothing there either. @nehon, is there any place where I can find the exception trace? “Cannot load material definition” is simply not enough to find the actual source of error.
Here are the sources.
There are still almost identical to Nehon’s original test case, so I have no idea what might be causing this.
Put all files into the package named in the Java class to try it out.
Since we’re chasing something weird and elusive, so the more outlandish potential trouble spots:
- Shader file names contain uppercase. Might cause behavioural differences between Windows and Linux machines that might derail the shadernode editor.
- I routinely add an empty line to files. Not sure whether I modified the shader files in that fashion, but that could cause differences, too.
TestTexture3D.java:
[java]package org.toolforger.experiments.voxelsVia3dTextures;
import com.jme3.app.SimpleApplication;
import com.jme3.bounding.BoundingBox;
import com.jme3.light.PointLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture3D;
import com.jme3.util.BufferUtils;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.ArrayList;
public class TestTexture3D extends SimpleApplication {
public static void main(String[] args) {
TestTexture3D app = new TestTexture3D();
app.start();
}
// FIXME add shader resources
@Override
public void simpleInitApp() {
//mouseInput.setCursorVisible(true);
flyCam.setMoveSpeed(10);
//creating a sphere
Sphere sphere = new Sphere(32, 32, 1);
//getting the boundingbox
sphere.updateBound();
BoundingBox bb = (BoundingBox) sphere.getBound();
Vector3f min = bb.getMin(null);
float[] ext = new float[]{bb.getXExtent() * 2, bb.getYExtent() * 2, bb.getZExtent() * 2};
//we need to change the UV coordinates (the sphere is assumet to be inside the 3D image box)
sphere.clearBuffer(Type.TexCoord);
VertexBuffer vb = sphere.getBuffer(Type.Position);
FloatBuffer fb = (FloatBuffer) vb.getData();
float[] uvCoordinates = BufferUtils.getFloatArray(fb);
//now transform the coordinates so that they are in the range of <0; 1>
for (int i = 0; i < uvCoordinates.length; i += 3) {
uvCoordinates[i] = (uvCoordinates[i] - min.x) / ext[0];
uvCoordinates[i + 1] = (uvCoordinates[i + 1] - min.y) / ext[1];
uvCoordinates[i + 2] = (uvCoordinates[i + 2] - min.z) / ext[2];
}
//apply new texture coordinates
VertexBuffer uvCoordsBuffer = new VertexBuffer(Type.TexCoord);
uvCoordsBuffer.setupData(Usage.Static, 3, com.jme3.scene.VertexBuffer.Format.Float,
BufferUtils.createFloatBuffer(uvCoordinates));
sphere.setBuffer(uvCoordsBuffer);
//create geometry, and apply material and our 3D texture
Geometry g = new Geometry("sphere", sphere);
Material material = new Material(assetManager, "org/toolforger/experiments/voxelsVia3dTextures/tex3D.j3md");
try {
Texture texture = this.getTexture();
material.setTexture("Texture", texture);
} catch (IOException e) {
e.printStackTrace();
}
material.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); ///
g.setMaterial(material);
g.setQueueBucket(RenderQueue.Bucket.Transparent); ///
rootNode.attachChild(g);
//add some light so that it is visible
PointLight light = new PointLight();
light.setColor(ColorRGBA.White);
light.setPosition(new Vector3f(5, 5, 5));
light.setRadius(20);
rootNode.addLight(light);
light = new PointLight();
light.setColor(ColorRGBA.White);
light.setPosition(new Vector3f(-5, -5, -5));
light.setRadius(20);
rootNode.addLight(light);
}
/**
* This method creates a RGB8 texture with the sizes of 10x10x10 pixels.
*/
private Texture getTexture() throws IOException {
ArrayList<ByteBuffer> data = new ArrayList<ByteBuffer>(1);
ByteBuffer bb = BufferUtils.createByteBuffer(10 * 10 * 10 * 4);//all data must be inside one buffer
// for (int i = 0; i < 10; ++i) {
// for (int j = 0; j < 10 * 10; ++j) {
// bb.put((byte) (255f * i / 10f));
// bb.put((byte) (255f * j / 10f));
// bb.put((byte) (255f));
// }
// }
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
for (int k= 0; k < 10; k++) {
bb.put((byte) (255f * i / 10f));
bb.put((byte) (255f * j / 10f));
bb.put((byte) (255f * k / 10f));
bb.put((byte) 127); ///
}
}
}
bb.rewind();
data.add(bb);
return new Texture3D(new Image(Format.RGBA8, 10, 10, 10, data));
}
}
[/java]
tex3D.j3md:
[java]
MaterialDef My MaterialDef {
MaterialParameters {
Texture3D Texture
}
Technique {
VertexShader GLSL100: org/toolforger/experiments/voxelsVia3dTextures/tex3D.vert
FragmentShader GLSL100: org/toolforger/experiments/voxelsVia3dTextures/tex3D.frag
WorldParameters {
WorldViewProjectionMatrix
}
}
}
[/java]
tex3D.vert:
[java]uniform mat4 g_WorldViewProjectionMatrix;
attribute vec3 inTexCoord;
attribute vec3 inPosition;
varying vec3 texCoord;
void main(){
gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition,1.0);
texCoord=inTexCoord;
}
[/java]
tex3D.frag:
[java]uniform sampler3D m_Texture;
varying vec3 texCoord;
void main(){
gl_FragColor= texture3D(m_Texture,texCoord);
}
[/java]
@nehon To trigger the FileAlreadyLockedException, I need to edit the jm3d file, then save it. The save works but the file’s “modified” status is not cleared (the file name remains bold). After that, switching from text editing to shadernode editing do I get a FileAlreadyLockedException. Seems like the save operation or something in its vicinity does not properly unlock the file if something fails.