Posted by
philjord on
Feb 18, 2019; 7:19am
URL: https://forum.jogamp.org/Java3D-in-batch-mode-tp4039415p4039548.html
Unfortunately I'm no Linux server expert so I really can't help with how to get a GraphicsEnvironment working with teh screen unplugged.
These days I mostly work with my adaptation of Java3D on Android that has no AWT in it at all, and allows me to simply create an OpenGL surface and give it to Java3D to work on.
new Canvas3D(GLWindow.create(new GLCapabilities(null))). The examples for Java3D 1.6 have an offscreen
example .
However it has 2 issues; 1 it’s not very dynamic so it’s hard to see what it can do just from the demo and ; 2 most of the code in it is focused on coordinating an on screen canvas and an off screen canvas and a raster between them. With a lot of work you could turn this into a sort of “security camera in a 3d shooter” type demo, but it distracts from the power of the off screen rendering.
I would mention that in your case (of not having a screen plugged into your GPU card) I would expect GraphicsDevice.getBestConfiguration to work fine. GraphicsDevice.getBestConfiguration eventually through a chain of calls arrives at JoglPipeline.getBestConfiguration which calls new Frame() and there is a chance that any given configuration may be unable to instantiate that Frame, and hence the init code will fail. In that case you might consider using Java3D 1.7 with the Android (no-AWT) adaptation I made.
You need to manually invoke Canvas3D.renderOffScreenBuffer(); and optionally Canvas3D.waitForOffScreenRendering(). But the scene graph can be updated and used as usual and you can do anything you like with the image you give to Canvas3D.setOffScreenBuffer including (for example) saving multiple images as a video like
SweetHome3D does, using Java3D for the lower quality renders and ray tracing for the higher.
Below I’ve written a very small example of what can be easily and quickly done with the off screen canvas. It requires the
examples for Java3D 1.6 because I use the mildly interesting SphereMotion scene, though if you like you can just grab that one
file .
For brevity this code has had the license removed, but please note it is derived from the
OffScreenTest of the Java3D examples and is covered by that license.
Each time you click the 3D image it will take a copy and display it in the label below it
package _testcase;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.ImageComponent;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Screen3D;
import javax.media.j3d.View;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import com.sun.j3d.utils.universe.SimpleUniverse;
import org.jdesktop.j3d.examples.sphere_motion.SphereMotion;
public class OffScreen extends javax.swing.JFrame {
private SimpleUniverse univ = null;
private BranchGroup scene = null;
private javax.swing.JPanel drawingPanel;
private Canvas3D createOnScreenCanvasAndUniverse() {
// Get the preferred graphics configuration for the default screen
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
// Create a Canvas3D using the preferred configuration
Canvas3D onScrCanvas = new Canvas3D(config, false);
// Create simple universe with view branch
univ = new SimpleUniverse(onScrCanvas);
// This will move the ViewPlatform back a bit so the
// objects in the scene can be viewed.
univ.getViewingPlatform().setNominalViewingTransform();
// Ensure at least 5 msec per frame (i.e., < 200Hz)
univ.getViewer().getView().setMinimumFrameCycleTime(5);
return onScrCanvas;
}
private OffScreenCanvas3D createOffScreenCanvas() {
// request an offscreen Canvas3D with a single buffer configuration
GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
template.setDoubleBuffer(GraphicsConfigTemplate3D.UNNECESSARY);
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
.getBestConfiguration(template);
// Create a offscreen Canvas3D using the single buffer configuration.
OffScreenCanvas3D offScrCanvas = new OffScreenCanvas3D(gc, true);
return offScrCanvas;
}
public OffScreen() {
initComponents();
// Create the content branch and add it to the universe
scene = new BranchGroup();
scene.addChild(new SphereMotion(new String[0]).createSceneGraph());
// Create an OnScreenCanvas3D and SimpleUniverse; add canvas to drawing panel
Canvas3D onScreenCanvas = createOnScreenCanvasAndUniverse();
drawingPanel.add(onScreenCanvas, java.awt.BorderLayout.CENTER);
// build a JLabel to display the image buffer
ImageIcon output = new ImageIcon();
JLabel outputJL = new JLabel(output);
drawingPanel.add(outputJL, java.awt.BorderLayout.SOUTH);
// Create an OffScreenCanvas3D
OffScreenCanvas3D offScreenCanvas = createOffScreenCanvas();
output.setImage(offScreenCanvas.bImage);
// set the offscreen to match the onscreen
Screen3D sOn = onScreenCanvas.getScreen3D();
Screen3D sOff = offScreenCanvas.getScreen3D();
sOff.setSize(sOn.getSize());
sOff.setPhysicalScreenWidth(sOn.getPhysicalScreenWidth());
sOff.setPhysicalScreenHeight(sOn.getPhysicalScreenHeight());
//Because we have both on screen and off screen we need to attach the offscreen canvas to the universe view
View view = univ.getViewer().getView();
view.addCanvas3D(offScreenCanvas);
//************************ on a click update the image shown in the JLabel
onScreenCanvas.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
offScreenCanvas.renderOffScreenBuffer();
offScreenCanvas.waitForOffScreenRendering();
// force the image to update
outputJL.setIcon(output);
outputJL.revalidate();
outputJL.repaint();
}
});
univ.addBranchGraph(scene);
}
private void initComponents() {
drawingPanel = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
drawingPanel.setLayout(new java.awt.BorderLayout());
drawingPanel.setPreferredSize(new java.awt.Dimension(500, 500));
getContentPane().add(drawingPanel, java.awt.BorderLayout.CENTER);
pack();
}
public static void main(String args[]) {
System.setProperty("sun.awt.noerasebackground", "true");
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new OffScreen().setVisible(true);
}
});
}
class OffScreenCanvas3D extends Canvas3D {
BufferedImage bImage;
ImageComponent2D buffer;
public OffScreenCanvas3D(GraphicsConfiguration gconfig, boolean offscreenflag) {
super(gconfig, offscreenflag);
bImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
buffer = new ImageComponent2D(ImageComponent.FORMAT_RGB, bImage, true, false); // notice yup = false because we are rendering onto an ImageIcon
buffer.setCapability(ImageComponent2D.ALLOW_IMAGE_READ);
this.setOffScreenBuffer(buffer);
}
}
}