I don’t like to post transparency issues, I feel like you guys have to repeat yourselves non stop when it comes to transparency, but I am having one
I’ll put the entire code at the bottom, not that I think it’s wrong, but I made 2 small cases to keep it simple.
Here is a quick overview though:
Scene:
-blue cube, unshaded material
-a character model comprising of multiple parts
-only one part, the hair, is placed in the transparent bucket and set to blendmode.alpha, rest all left opaque
-an ambient light for the character
-white viewport clear color
-camera set to look at the characters head side on
I changed the color of the transparent hair part to red and the opaque head to cyan to make it easier to see.
This results in exactly what I expected:
Hair works perfectly
Next I have almost the same setup, except the character is rendered to a texture. The blue box is left on the rootnode. The texture is then placed on the guiNode so it appears over the top of the blue box scene.
I don’t understand why the blue from the box is showing through the solid cyan head? For the rendered texture, I thought that it would first draw the characters head since it’s opaque, then draw the transparent hair on top since its set to bucket.transparent, all of that goes on the texture, then it would render the normal rootNode scene and out this texture on top.
These are the 2 head parts, in blender so no transparency here
I would have thought the solid head wouldn’t disappear and allow blue to come through, and don’t understand why rendering to a texture then putting it on top changes it. I did wonder about the blend mode, and changing it helps with this but causes more problems.
Code for working hair:
public class Test2 extends SimpleApplication
{
Node playerNode;
public static void main(String[] args){
Test2 app = new Test2();
app.start();
}
@Override
public void simpleInitApp()
{
Box b = new Box(10, 10, 10); // create cube shape
Geometry geom = new Geometry("Box", b); // create cube geometry from the shape
Material mat = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md"); // create a simple material
mat.setColor("Color", ColorRGBA.Blue); // set color of material to blue
geom.setMaterial(mat); // set the cube's material
geom.setLocalTranslation(new Vector3f(24.264202f, 43.10403f, 0.49422723f));
rootNode.attachChild(geom); // make the cube appear in the scene
viewPort.setBackgroundColor(ColorRGBA.White);
flyCam.setMoveSpeed(15);
Spatial body = getModel("Models/Actors/Players/ripley/body.mesh.xml","Materials/Actors/Players/ripley/body.j3m",false);
Spatial gear = getModel("Models/Actors/Players/ripley/gear.mesh.xml","Materials/Actors/Players/ripley/gear.j3m",false);
Spatial head = getModel("Models/Actors/Players/ripley/head.mesh.xml","Materials/Actors/Players/ripley/head.j3m",false);
Spatial feet = getModel("Models/Actors/Players/ripley/feet.mesh.xml","Materials/Actors/Players/ripley/feet.j3m",false);
Spatial hair = getModel("Models/Actors/Players/ripley/hair.mesh.xml","Materials/Actors/Players/ripley/hair.j3m",true);
playerNode = new Node();
playerNode.attachChild(body);
playerNode.attachChild(gear);
playerNode.attachChild(head);
playerNode.attachChild(feet);
playerNode.attachChild(hair);
AmbientLight al = new AmbientLight();
rootNode.attachChild(playerNode);
rootNode.addLight(al);
cam.setLocation(new Vector3f(-12.170704f, 42.28284f, 0.020329474f));
cam.setRotation(new Quaternion(-0.0077274614f, 0.7256225f, 0.008149218f, 0.68800145f));
}
public Spatial getModel(String modelName, String materialName, boolean transparent)
{
Spatial model = getAssetManager().loadModel(modelName);
Material mat = getAssetManager().loadMaterial(materialName);
mat.setColor("Diffuse", new ColorRGBA(1,1,1,1));
if(transparent)
{
mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
model.setQueueBucket(RenderQueue.Bucket.Transparent);
//mat.setFloat("AlphaDiscardThreshold", 0.1f);
}
model.setMaterial(mat);
return model;
}
}
And now the one that renders the character to a texture and attaches to the guiNode
public class Test extends SimpleApplication
{
Picture pic;
Node offRootNode;
Camera offCamera;
Node playerNode;
public static void main(String[] args){
Test app = new Test();
app.start();
}
@Override
public void simpleInitApp()
{
Box b = new Box(10, 10, 10); // create cube shape
Geometry geom = new Geometry("Box", b); // create cube geometry from the shape
Material mat = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md"); // create a simple material
mat.setColor("Color", ColorRGBA.Blue); // set color of material to blue
geom.setMaterial(mat); // set the cube's material
geom.setLocalTranslation(new Vector3f(24.264202f, 43.10403f, 0.49422723f));
rootNode.attachChild(geom); // make the cube appear in the scene
viewPort.setBackgroundColor(ColorRGBA.White);
Spatial body = getModel("Models/Actors/Players/ripley/body.mesh.xml","Materials/Actors/Players/ripley/body.j3m",false);
Spatial gear = getModel("Models/Actors/Players/ripley/gear.mesh.xml","Materials/Actors/Players/ripley/gear.j3m",false);
Spatial head = getModel("Models/Actors/Players/ripley/head.mesh.xml","Materials/Actors/Players/ripley/head.j3m",false);
Spatial feet = getModel("Models/Actors/Players/ripley/feet.mesh.xml","Materials/Actors/Players/ripley/feet.j3m",false);
Spatial hair = getModel("Models/Actors/Players/ripley/hair.mesh.xml","Materials/Actors/Players/ripley/hair.j3m",true);
playerNode = new Node();
playerNode.attachChild(body);
playerNode.attachChild(gear);
playerNode.attachChild(head);
playerNode.attachChild(feet);
playerNode.attachChild(hair);
AmbientLight al = new AmbientLight();
createRenderToTexture();
rootNode.addLight(al);
offRootNode.attachChild(playerNode);
offRootNode.addLight(al);
cam.setLocation(new Vector3f(-12.170704f, 42.28284f, 0.020329474f));
cam.setRotation(new Quaternion(-0.0077274614f, 0.7256225f, 0.008149218f, 0.68800145f));
offCamera.setLocation(new Vector3f(-12.170704f, 42.28284f, 0.020329474f));
offCamera.setRotation(new Quaternion(-0.0077274614f, 0.7256225f, 0.008149218f, 0.68800145f));
}
public Spatial getModel(String modelName, String materialName, boolean transparent)
{
Spatial model = getAssetManager().loadModel(modelName);
Material mat = getAssetManager().loadMaterial(materialName);
mat.setColor("Diffuse", new ColorRGBA(1,1,1,1));
if(transparent)
{
mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
model.setQueueBucket(RenderQueue.Bucket.Transparent);
}
model.setMaterial(mat);
return model;
}
public void simpleUpdate(float d)
{
offRootNode.updateGeometricState();
offRootNode.updateLogicalState(d);
offCamera.setLocation(cam.getLocation());
offCamera.setRotation(cam.getRotation());
}
public void createRenderToTexture()
{
width = Display.getWidth();
height = Display.getHeight();
offCamera = new Camera((int)width, (int)height);
offCamera.setFrustumPerspective(60f, (float)((float)width/(float)height), 0.1f, 1000f);
ViewPort offView = renderManager.createPreView("Offscreen View", offCamera);
offView.setClearFlags(true, true, true);
offView.setBackgroundColor(new ColorRGBA(0,0,0,0));
FrameBuffer offBuffer = new FrameBuffer((int)width, (int)height, 1);
Texture2D offTex = new Texture2D((int)width, (int)height, Image.Format.RGBA8);
offTex.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
offTex.setMagFilter(Texture.MagFilter.Nearest);
offBuffer.setDepthBuffer(Image.Format.Depth);
offBuffer.setColorTexture(offTex);
offView.setOutputFrameBuffer(offBuffer);
offRootNode = new Node();
offView.attachScene(offRootNode);
pic = new Picture("realtime");
pic.setTexture(assetManager, offTex, true);
pic.setWidth(width);
pic.setHeight(height);
guiNode.attachChild(pic);
}
}