Difference between revisions of "Hacky Sculpt Previewer"
Jump to navigation
Jump to search
(I've added a few config booleans that change how it does the ends and edges.) |
|||
(One intermediate revision by one other user not shown) | |||
Line 1: | Line 1: | ||
<pre>/** | <pre> | ||
/** | |||
* First attempt at a sculpt previewer | * First attempt at a sculpt previewer | ||
* Adapted from Sun's ObjLoad | * Adapted from Sun's ObjLoad | ||
* BSD license (inherited) | * BSD license (inherited) | ||
* */ | |||
/** | |||
* Original Yumi Murakami. | |||
* 6-5-2007 Strife Onizuka: | |||
* Fixed centering of object and wrapping around when | |||
* downsampling. | |||
* 6-5-2007 Yumi Murakami | |||
* Use system native UI, attempted to get shading to work. | |||
* Now generates surface normals and installs Materials, both | |||
* of which are required for shading - but shading still does | |||
* not work :( | |||
* */ | * */ | ||
Line 17: | Line 30: | ||
import javax.media.j3d.*; | import javax.media.j3d.*; | ||
import javax.swing.JFileChooser; | import javax.swing.JFileChooser; | ||
import javax.swing.JOptionPane; | |||
import javax.swing.UIManager; | |||
import javax.swing.filechooser.FileNameExtensionFilter; | import javax.swing.filechooser.FileNameExtensionFilter; | ||
import javax.vecmath.*; | import javax.vecmath.*; | ||
Line 25: | Line 40: | ||
import com.sun.j3d.loaders.objectfile.ObjectFile; | import com.sun.j3d.loaders.objectfile.ObjectFile; | ||
import com.sun.j3d.utils.behaviors.vp.*; | import com.sun.j3d.utils.behaviors.vp.*; | ||
import com.sun.j3d.utils.geometry.*; | |||
import com.sun.j3d.utils.universe.*; | import com.sun.j3d.utils.universe.*; | ||
Line 73: | Line 89: | ||
Shape3D s = new Shape3D(); | Shape3D s = new Shape3D(); | ||
BufferedImage theImage = null; | |||
JFileChooser chooser = new JFileChooser(); | |||
FileNameExtensionFilter filter = new FileNameExtensionFilter("Supported Image Formats",ImageIO.getReaderFileSuffixes()); | |||
chooser.setFileFilter(filter); | |||
boolean ok = false; | |||
while (!ok) { | |||
int chooserResult = chooser.showOpenDialog(this); | |||
if (chooserResult == JFileChooser.CANCEL_OPTION) { | |||
System.exit(0); | |||
} | |||
ok = true; | |||
try { | |||
theImage = ImageIO.read(chooser.getSelectedFile()); | |||
} catch (IOException e) { | |||
JOptionPane.showMessageDialog(this,"An error occured opening the texture file:\n" + e.getMessage(),"File error",JOptionPane.ERROR_MESSAGE); | |||
System.out.println("Error opening sculpt texture file"); | |||
ok = false; | |||
} | |||
} | |||
int xStep, yStep; | |||
int width = theImage.getWidth(); | |||
int height = theImage.getHeight(); | |||
xStep = width / 64; | |||
yStep = height / 64; | |||
if (xStep < 1) | |||
xStep = 1; | |||
if (yStep < 1) | |||
yStep = 1; | |||
if ((xStep > 1) || (yStep > 1)) { | |||
JOptionPane.showMessageDialog(this,"Sculpt texture dimensions are " + width + "x" + height + ".\nMaximum detail level on Second Life to 64x64,\nso the extra pixel data is being wasted.","Texture Over Resolution",JOptionPane.WARNING_MESSAGE); | |||
} | |||
int xmax = width - (left_right?0:xStep); | |||
int ymax = height - (top_bottom?0:yStep); | |||
int vertices = (xmax/xStep) * (height/yStep); | |||
System.out.println(vertices); | |||
TriangleArray ta = new TriangleArray(vertices * 6,GeometryArray.COORDINATES); | |||
int x, y, r; | |||
r = 0; | |||
double[] bottom = new double[3]; | |||
double[] top = new double[3]; | |||
if(!top_bottom)//find the top center and bottom averages | |||
{ | |||
r = 0; | r = 0; | ||
bottom[0] = bottom[1] = bottom[2] = top[0] = top[1] = top[2] = 0.0; | |||
double[] bottom = | for (x=0; x<width; x+=xStep) { | ||
double[] pb = RGBtoVertex(theImage.getRGB(x,0)); | |||
double[] pt = RGBtoVertex(theImage.getRGB(x,height - xStep)); | |||
if(!top_bottom)// | bottom[0] += pb[0]; | ||
bottom[1] += pb[1]; | |||
bottom[2] += pb[2]; | |||
top[0] += pt[0]; | |||
top[1] += pt[1]; | |||
top[2] += pt[2]; | |||
} | |||
bottom[0] = (bottom[0] * xStep) / width; | |||
bottom[1] = (bottom[1] * xStep) / width; | |||
bottom[2] = (bottom[2] * xStep) / width; | |||
top[0] = (top[0] * xStep) / width; | |||
top[1] = (top[1] * xStep) / width; | |||
top[2] = (top[2] * xStep) / width; | |||
} | |||
for (x=0; x<xmax; x+=xStep) {//link left to right | |||
if(!top_bottom) | |||
{ | |||
int BottomLeftRGB = theImage.getRGB(x,0); | |||
int BottomRightRGB = theImage.getRGB((x+xStep) % width,0); | |||
ta.setCoordinates(r,bottom); | |||
ta.setCoordinates(r+1,RGBtoVertex(BottomRightRGB)); | |||
ta.setCoordinates(r+2,RGBtoVertex(BottomLeftRGB)); | |||
r+=3; | |||
} | |||
for (y=0; y<ymax; y+=yStep) { | |||
int topLeftRGB = theImage.getRGB(x,y); | |||
int topRightRGB = theImage.getRGB((x+xStep) % width,y); | |||
int bottomLeftRGB = theImage.getRGB(x,(y+yStep) % height); | |||
int bottomRightRGB = theImage.getRGB((x+xStep) % width,(y+yStep) % height); | |||
// Top left triangle | |||
ta.setCoordinates(r,RGBtoVertex(topLeftRGB)); | |||
ta.setCoordinates(r+1,RGBtoVertex(topRightRGB)); | |||
ta.setCoordinates(r+2,RGBtoVertex(bottomLeftRGB)); | |||
// Bottom right triangle | |||
ta.setCoordinates(r+3,RGBtoVertex(topRightRGB)); | |||
ta.setCoordinates(r+4,RGBtoVertex(bottomRightRGB)); | |||
ta.setCoordinates(r+5,RGBtoVertex(bottomLeftRGB)); | |||
r+=6; | |||
} | |||
if(!top_bottom) | |||
{ | { | ||
int TopLeftRGB = theImage.getRGB(x,ymax); | |||
int TopRightRGB = theImage.getRGB((x+xStep) % width,ymax); | |||
ta.setCoordinates(r,RGBtoVertex(TopLeftRGB)); | |||
ta.setCoordinates(r+1,RGBtoVertex(TopRightRGB)); | |||
ta.setCoordinates(r+2,top); | |||
r+=3; | |||
} | } | ||
} | |||
GeometryInfo info = new GeometryInfo(ta); | |||
NormalGenerator gen = new NormalGenerator(); | |||
gen.generateNormals(info); | |||
s.setGeometry(info.getIndexedGeometryArray()); | |||
Appearance app = new Appearance(); | |||
Material mat = new Material( new Color3f((float)0.0,(float)0.0,(float)0.0), // Ambient | |||
new Color3f((float)1.0,(float)1.0,(float)1.0), // Emissive | |||
new Color3f((float)0.5,(float)0.5,(float)0.5), // Diffuse | |||
new Color3f((float)1.0,(float)1.0,(float)1.0), // Specular | |||
(float)10.0 // Shiny | |||
); // ); | |||
app.setMaterial(mat); | |||
s.setAppearance(app); | |||
objTrans.addChild(s); | |||
BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); | BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); | ||
Line 203: | Line 234: | ||
objRoot.addChild(bgNode); | objRoot.addChild(bgNode); | ||
return objRoot; | |||
} | } | ||
Line 216: | Line 247: | ||
// Create simple universe with view branch | // Create simple universe with view branch | ||
univ = new SimpleUniverse(canvas3d); | univ = new SimpleUniverse(canvas3d); | ||
BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); | |||
// add mouse behaviors to the ViewingPlatform | // add mouse behaviors to the ViewingPlatform | ||
Line 263: | Line 294: | ||
return canvas3d; | return canvas3d; | ||
} | } | ||
/** | /** | ||
Line 281: | Line 299: | ||
*/ | */ | ||
public SculptPreview(String args[]) { | public SculptPreview(String args[]) { | ||
// Initialize the GUI components | |||
initComponents(); | initComponents(); | ||
Line 337: | Line 320: | ||
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents | // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents | ||
private void initComponents() { | private void initComponents() { | ||
try { | |||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); | |||
} catch (Exception e) { | |||
System.out.println("Error setting UI!"); | |||
} | |||
drawingPanel = new javax.swing.JPanel(); | drawingPanel = new javax.swing.JPanel(); | ||
Line 365: | Line 354: | ||
// End of variables declaration//GEN-END:variables | // End of variables declaration//GEN-END:variables | ||
} | }</pre> | ||
</pre> |
Latest revision as of 19:22, 5 May 2007
/** * First attempt at a sculpt previewer * Adapted from Sun's ObjLoad * BSD license (inherited) * */ /** * Original Yumi Murakami. * 6-5-2007 Strife Onizuka: * Fixed centering of object and wrapping around when * downsampling. * 6-5-2007 Yumi Murakami * Use system native UI, attempted to get shading to work. * Now generates surface normals and installs Materials, both * of which are required for shading - but shading still does * not work :( * */ import java.awt.GraphicsConfiguration; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import javax.imageio.*; import javax.imageio.stream.ImageInputStream; import javax.media.j3d.*; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.filechooser.FileNameExtensionFilter; import javax.vecmath.*; import com.sun.j3d.loaders.IncorrectFormatException; import com.sun.j3d.loaders.ParsingErrorException; import com.sun.j3d.loaders.Scene; import com.sun.j3d.loaders.objectfile.ObjectFile; import com.sun.j3d.utils.behaviors.vp.*; import com.sun.j3d.utils.geometry.*; import com.sun.j3d.utils.universe.*; public class SculptPreview extends javax.swing.JFrame { private boolean left_right = true; private boolean top_bottom = false; private boolean spin = false; private boolean noTriangulate = false; private boolean noStripify = false; private double creaseAngle = 60.0; private URL filename = null; private SimpleUniverse univ = null; private BranchGroup scene = null; double[] RGBtoVertex(int RGB) { int blue = RGB & 255; int green = (RGB >> 8) & 255; int red = (RGB >> 16) & 255; double[] result = new double[3]; result[0] = (((double)red) / 255.0) - 0.5; result[1] = (((double)green) / 255.0) - 0.5; result[2] = (((double)blue) / 255.0) - 0.5; return result; } public BranchGroup createSceneGraph() { // Create the root of the branch graph BranchGroup objRoot = new BranchGroup(); // Create a Transformgroup to scale all objects so they // appear in the scene. TransformGroup objScale = new TransformGroup(); Transform3D t3d = new Transform3D(); t3d.setScale(0.7); objScale.setTransform(t3d); objRoot.addChild(objScale); // Create the transform group node and initialize it to the // identity. Enable the TRANSFORM_WRITE capability so that // our behavior code can modify it at runtime. Add it to the // root of the subgraph. TransformGroup objTrans = new TransformGroup(); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); objScale.addChild(objTrans); Shape3D s = new Shape3D(); BufferedImage theImage = null; JFileChooser chooser = new JFileChooser(); FileNameExtensionFilter filter = new FileNameExtensionFilter("Supported Image Formats",ImageIO.getReaderFileSuffixes()); chooser.setFileFilter(filter); boolean ok = false; while (!ok) { int chooserResult = chooser.showOpenDialog(this); if (chooserResult == JFileChooser.CANCEL_OPTION) { System.exit(0); } ok = true; try { theImage = ImageIO.read(chooser.getSelectedFile()); } catch (IOException e) { JOptionPane.showMessageDialog(this,"An error occured opening the texture file:\n" + e.getMessage(),"File error",JOptionPane.ERROR_MESSAGE); System.out.println("Error opening sculpt texture file"); ok = false; } } int xStep, yStep; int width = theImage.getWidth(); int height = theImage.getHeight(); xStep = width / 64; yStep = height / 64; if (xStep < 1) xStep = 1; if (yStep < 1) yStep = 1; if ((xStep > 1) || (yStep > 1)) { JOptionPane.showMessageDialog(this,"Sculpt texture dimensions are " + width + "x" + height + ".\nMaximum detail level on Second Life to 64x64,\nso the extra pixel data is being wasted.","Texture Over Resolution",JOptionPane.WARNING_MESSAGE); } int xmax = width - (left_right?0:xStep); int ymax = height - (top_bottom?0:yStep); int vertices = (xmax/xStep) * (height/yStep); System.out.println(vertices); TriangleArray ta = new TriangleArray(vertices * 6,GeometryArray.COORDINATES); int x, y, r; r = 0; double[] bottom = new double[3]; double[] top = new double[3]; if(!top_bottom)//find the top center and bottom averages { r = 0; bottom[0] = bottom[1] = bottom[2] = top[0] = top[1] = top[2] = 0.0; for (x=0; x<width; x+=xStep) { double[] pb = RGBtoVertex(theImage.getRGB(x,0)); double[] pt = RGBtoVertex(theImage.getRGB(x,height - xStep)); bottom[0] += pb[0]; bottom[1] += pb[1]; bottom[2] += pb[2]; top[0] += pt[0]; top[1] += pt[1]; top[2] += pt[2]; } bottom[0] = (bottom[0] * xStep) / width; bottom[1] = (bottom[1] * xStep) / width; bottom[2] = (bottom[2] * xStep) / width; top[0] = (top[0] * xStep) / width; top[1] = (top[1] * xStep) / width; top[2] = (top[2] * xStep) / width; } for (x=0; x<xmax; x+=xStep) {//link left to right if(!top_bottom) { int BottomLeftRGB = theImage.getRGB(x,0); int BottomRightRGB = theImage.getRGB((x+xStep) % width,0); ta.setCoordinates(r,bottom); ta.setCoordinates(r+1,RGBtoVertex(BottomRightRGB)); ta.setCoordinates(r+2,RGBtoVertex(BottomLeftRGB)); r+=3; } for (y=0; y<ymax; y+=yStep) { int topLeftRGB = theImage.getRGB(x,y); int topRightRGB = theImage.getRGB((x+xStep) % width,y); int bottomLeftRGB = theImage.getRGB(x,(y+yStep) % height); int bottomRightRGB = theImage.getRGB((x+xStep) % width,(y+yStep) % height); // Top left triangle ta.setCoordinates(r,RGBtoVertex(topLeftRGB)); ta.setCoordinates(r+1,RGBtoVertex(topRightRGB)); ta.setCoordinates(r+2,RGBtoVertex(bottomLeftRGB)); // Bottom right triangle ta.setCoordinates(r+3,RGBtoVertex(topRightRGB)); ta.setCoordinates(r+4,RGBtoVertex(bottomRightRGB)); ta.setCoordinates(r+5,RGBtoVertex(bottomLeftRGB)); r+=6; } if(!top_bottom) { int TopLeftRGB = theImage.getRGB(x,ymax); int TopRightRGB = theImage.getRGB((x+xStep) % width,ymax); ta.setCoordinates(r,RGBtoVertex(TopLeftRGB)); ta.setCoordinates(r+1,RGBtoVertex(TopRightRGB)); ta.setCoordinates(r+2,top); r+=3; } } GeometryInfo info = new GeometryInfo(ta); NormalGenerator gen = new NormalGenerator(); gen.generateNormals(info); s.setGeometry(info.getIndexedGeometryArray()); Appearance app = new Appearance(); Material mat = new Material( new Color3f((float)0.0,(float)0.0,(float)0.0), // Ambient new Color3f((float)1.0,(float)1.0,(float)1.0), // Emissive new Color3f((float)0.5,(float)0.5,(float)0.5), // Diffuse new Color3f((float)1.0,(float)1.0,(float)1.0), // Specular (float)10.0 // Shiny ); // ); app.setMaterial(mat); s.setAppearance(app); objTrans.addChild(s); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); if (spin) { Transform3D yAxis = new Transform3D(); Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, objTrans, yAxis, 0.0f, (float) Math.PI*2.0f); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); } // Set up the background Color3f bgColor = new Color3f(0.05f, 0.05f, 0.5f); Background bgNode = new Background(bgColor); bgNode.setApplicationBounds(bounds); objRoot.addChild(bgNode); return objRoot; } private Canvas3D createUniverse() { // Get the preferred graphics configuration for the default screen GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); // Create a Canvas3D using the preferred configuration Canvas3D canvas3d = new Canvas3D(config); // Create simple universe with view branch univ = new SimpleUniverse(canvas3d); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); // add mouse behaviors to the ViewingPlatform ViewingPlatform viewingPlatform = univ.getViewingPlatform(); PlatformGeometry pg = new PlatformGeometry(); // Set up the ambient light Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f); AmbientLight ambientLightNode = new AmbientLight(ambientColor); ambientLightNode.setInfluencingBounds(bounds); pg.addChild(ambientLightNode); // Set up the directional lights Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1Direction = new Vector3f(1.0f, 1.0f, 1.0f); Color3f light2Color = new Color3f(1.0f, 1.0f, 1.0f); Vector3f light2Direction = new Vector3f(-1.0f, -1.0f, -1.0f); DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction); light1.setInfluencingBounds(bounds); pg.addChild(light1); DirectionalLight light2 = new DirectionalLight(light2Color, light2Direction); light2.setInfluencingBounds(bounds); pg.addChild(light2); viewingPlatform.setPlatformGeometry( pg ); // This will move the ViewPlatform back a bit so the // objects in the scene can be viewed. viewingPlatform.setNominalViewingTransform(); if (!spin) { OrbitBehavior orbit = new OrbitBehavior(canvas3d, OrbitBehavior.REVERSE_ALL); orbit.setSchedulingBounds(bounds); viewingPlatform.setViewPlatformBehavior(orbit); } // Ensure at least 5 msec per frame (i.e., < 200Hz) univ.getViewer().getView().setMinimumFrameCycleTime(5); return canvas3d; } /** * Creates new form */ public SculptPreview(String args[]) { // Initialize the GUI components initComponents(); // Create Canvas3D and SimpleUniverse; add canvas to drawing panel Canvas3D c = createUniverse(); drawingPanel.add(c, java.awt.BorderLayout.CENTER); // Create the content branch and add it to the universe scene = createSceneGraph(); univ.addBranchGraph(scene); } // ---------------------------------------------------------------- /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents private void initComponents() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { System.out.println("Error setting UI!"); } drawingPanel = new javax.swing.JPanel(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("SculptPreview"); drawingPanel.setLayout(new java.awt.BorderLayout()); drawingPanel.setPreferredSize(new java.awt.Dimension(700, 700)); getContentPane().add(drawingPanel, java.awt.BorderLayout.CENTER); pack(); }// </editor-fold>//GEN-END:initComponents /** * @param args the command line arguments */ public static void main(final String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { SculptPreview sp = new SculptPreview(args); sp.setVisible(true); } }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel drawingPanel; // End of variables declaration//GEN-END:variables }