i want to duplicate a number of copies of an module which is from an .obj file, and i wish:
1. don't want to read them all through file, i suspect this would result in slow loading and extra memory. 2. control them indepently, like location and angle 3. can "hide" (disapear) any of them. current code is as below, my problem is that: 1. can put the to somewhere and in certain angle, but the location and angle is based on the prior location or angle. 2. can't identify each of them ,so can't hide a particular one.( can't identify so sure can't hide...) do i have to create them all through reading obj files? i tested and the CPU load was very low but cost lot more memory. with the code below, the cpu and memory is neary same with one obj. in display: for (int i=0;i<10;i++){ chairModel.mRotate(); chairModel.mDraw(); } class func: public void mRotate(){ gl.glRotatef((float)Math.random()*360, 0f, 1f, 0f); gl.glTranslatef(1, 10-(float)Math.random(), -1); } public void mDraw() { gl.glCallList(objectlist); gl.glDisable(GL2.GL_COLOR_MATERIAL); } |
Administrator
|
Don't use display lists, they are half broken in numerous drivers, it's a waste of time even on very old hardware.
You can store the geometry (vertices, colors, texture coordinates, indices, normals, ...) of a cube or any more complicated model into one or several vertex buffer objects. You can use the same geometry with different transforms (rotation, translation, scale, ...). This tutorial might help you: http://glprogramming.com/red/chapter03.html You have to understand how the model-view matrix works, you'll need to use glLoadIdentity and maybe glMultMatrix and glLoadMatrix if you choose to store the transforms into matrices.
Julien Gouesse | Personal blog | Website
|
In reply to this post by Ususuus
This is my first post... apologies in advance if I stumble....
You are using a deprecated approach; better would be to use shaders, as follows: Read in the obj file once into a VBO, then draw it as many times as you like by calling glDrawArrays() for each occurance, with different MV ("model-view") matrices that you pass through the shader pipeline as uniform variables. You can hide one of them by simply skipping the corresponding call to glDrawArrays(). If there is some simple relationship between how the different copies move relative to each other, there is an even more efficient approach: instancing. You read in the obj file once into a VBO, then draw it using glDrawArraysInstanced(), specifying the number of instances you want drawn of the object. In the vertex shader, you can then use the built-in variable gl_InstanceID to manipulate the model matrix differently for each instance. Hiding one of them is slightly trickier, but there are many possible tricks for doing it. Complete examples of both methods are given in chapter 4 of this book (sorry for the shameless plug): http://jogamp.org/wiki/index.php/Jogl_Tutorial#Gordon_and_Clevenger_textbook (Julien - feel free to correct anything I may have mis-stated) |
In reply to this post by gouessej
Hi gouessej,
i just feel that the tutorial is not very friendly to a brand new 3D user, i went through the JAVA3D tutorials easily but feel very hard at JOGL. Most of my understands for JOGL is from existed codes, by guessing... your tips help me a lot~~ |
In reply to this post by V. Scott Gordon
that's very detailed instructions, thanks a lot.
the book link just links to the tutorial page, whick book exactly are your refering to? |
This post was updated on .
In reply to this post by gouessej
UPDATE, this tutorial seems great~~~
UPDATE again, you two said display list was deprecated but the tutorial have a chapter discribing it. was the tutorial up to dated? and another problem is that , the tutorial samples were in C not java, that will make worse for me. Chapter 1. Introduction to OpenGL Chapter 2. State Management and Drawing Geometric Objects Chapter 3. Viewing Chapter 4. Color Chapter 5. Lighting Chapter 6. Blending, Antialiasing, Fog, and Polygon Offset Chapter 7. Display Lists Chapter 8. Drawing Pixels, Bitmaps, Fonts, and Images Chapter 9. Texture Mapping |
In reply to this post by Ususuus
The textbook with an author matching my name :)
|
Administrator
|
In reply to this post by Ususuus
Java3D uses JOGL under the hood. Java3D is an high level 3D scenegraph API whereas JOGL is a low level Java binding for the OpenGL and OpenGL ES APIs with its own windowing system (NEWT), some optional helpers and utilities (TextureIO, ...) and with some classes helping the integration with the rest of the standard JavaSE API. Yes JOGL is harder to use but has a lot more possibilities.
V. Scott Gordon is right about the fixed pipeline but I just wanted to help you to understand your mistakes and some concepts before advising you to switch to shaders.
Julien Gouesse | Personal blog | Website
|
i'm reading this tutorial from chapter 1, and i think i would go through all chapters. It helps me a lot to understand how OPGL works, feeling great!!
|
Administrator
|
:) Yes, it's an excellent idea and I find these tutorials very well written. Don't hesitate to ask us any questions.
P.S: The differences between OpenGL in C and Java (JOGL) aren't huge. For example, you don't need GLUT to swap the buffers in JOGL, you can let it do it for you or do it manually.
Julien Gouesse | Personal blog | Website
|
can i suggest that we make the red book the default tutorial? especially for those starters. A right direction worthes a lot and saves time.
for C or Java, at my first glance, i just doubt whether i can make it, but when i started, i do feel no differences. |
The red book is in C++ and contains no information about JOGL. How could it serve as the default JOGL tutorial?
|
Administrator
|
In reply to this post by Ususuus
Some other contributors already ported the examples of the red book to JOGL:
https://github.com/gouessej/jogl-demos/tree/master/src/redbook/src
Julien Gouesse | Personal blog | Website
|
This post was updated on .
after all these days, i'm still stucked here. and i realized that many people have same problem with VBOs. would u please help to update the code? render a same obj file 1000 times with random position and rotation. (I also saw your ID in java-programming.org ^_^)
import java.io.*; import java.util.ArrayList; import java.util.StringTokenizer; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; import com.jogamp.opengl.util.texture.Texture; public class GLModel { private ArrayList<float[]> vertexsets; private ArrayList<float[]> vertexsetsnorms; private ArrayList<float[]> vertexsetstexs; private ArrayList<int[]> faces; private ArrayList<int[]> facestexs; private ArrayList<int[]> facesnorms; private ArrayList<String[]> mattimings; private MtlLoader materials; private int objectlist; private int numpolys; public float toppoint; public float bottompoint; public float leftpoint; public float rightpoint; public float farpoint; public float nearpoint; private String mtl_path; // THIS CLASS LOADS THE MODELS public GLModel(BufferedReader ref, boolean centerit, String path, GL2 gl) { mtl_path = path; vertexsets = new ArrayList<float[]>(); vertexsetsnorms = new ArrayList<float[]>(); vertexsetstexs = new ArrayList<float[]>(); faces = new ArrayList<int[]>(); facestexs = new ArrayList<int[]>(); facesnorms = new ArrayList<int[]>(); mattimings = new ArrayList<String[]>(); numpolys = 0; toppoint = 0.0F; bottompoint = 0.0F; leftpoint = 0.0F; rightpoint = 0.0F; farpoint = 0.0F; nearpoint = 0.0F; loadobject(ref); if (centerit) centerit(); opengldrawtolist(gl); numpolys = faces.size(); cleanup(); } private void cleanup() { vertexsets.clear(); vertexsetsnorms.clear(); vertexsetstexs.clear(); faces.clear(); facestexs.clear(); facesnorms.clear(); } private void loadobject(BufferedReader br) { int linecounter = 0; int facecounter = 0; try { boolean firstpass = true; String newline; while ((newline = br.readLine()) != null) { linecounter++; if (newline.length() > 0) { newline = newline.trim(); // LOADS VERTEX COORDINATES if (newline.startsWith("v ")) { float coords[] = new float[4]; String coordstext[] = new String[4]; newline = newline.substring(2, newline.length()); StringTokenizer st = new StringTokenizer(newline, " "); for (int i = 0; st.hasMoreTokens(); i++) coords[i] = Float.parseFloat(st.nextToken()); if (firstpass) { rightpoint = coords[0]; leftpoint = coords[0]; toppoint = coords[1]; bottompoint = coords[1]; nearpoint = coords[2]; farpoint = coords[2]; firstpass = false; } if (coords[0] > rightpoint) rightpoint = coords[0]; if (coords[0] < leftpoint) leftpoint = coords[0]; if (coords[1] > toppoint) toppoint = coords[1]; if (coords[1] < bottompoint) bottompoint = coords[1]; if (coords[2] > nearpoint) nearpoint = coords[2]; if (coords[2] < farpoint) farpoint = coords[2]; vertexsets.add(coords); } else // LOADS VERTEX TEXTURE COORDINATES if (newline.startsWith("vt")) { float coords[] = new float[4]; String coordstext[] = new String[4]; newline = newline.substring(3, newline.length()); StringTokenizer st = new StringTokenizer(newline, " "); for (int i = 0; st.hasMoreTokens(); i++) coords[i] = Float.parseFloat(st.nextToken()); vertexsetstexs.add(coords); } else // LOADS VERTEX NORMALS COORDINATES if (newline.startsWith("vn")) { float coords[] = new float[4]; String coordstext[] = new String[4]; newline = newline.substring(3, newline.length()); StringTokenizer st = new StringTokenizer(newline, " "); for (int i = 0; st.hasMoreTokens(); i++) coords[i] = Float.parseFloat(st.nextToken()); vertexsetsnorms.add(coords); } else // LOADS FACES COORDINATES if (newline.startsWith("f ")) { facecounter++; newline = newline.substring(2, newline.length()); StringTokenizer st = new StringTokenizer(newline, " "); int count = st.countTokens(); int v[] = new int[count]; int vt[] = new int[count]; int vn[] = new int[count]; for (int i = 0; i < count; i++) { char chars[] = st.nextToken().toCharArray(); StringBuffer sb = new StringBuffer(); char lc = 'x'; for (int k = 0; k < chars.length; k++) { if (chars[k] == '/' && lc == '/') sb.append('0'); lc = chars[k]; sb.append(lc); } StringTokenizer st2 = new StringTokenizer(sb.toString(), "/"); int num = st2.countTokens(); v[i] = Integer.parseInt(st2.nextToken()); if (num > 1) vt[i] = Integer.parseInt(st2.nextToken()); else vt[i] = 0; if (num > 2) vn[i] = Integer.parseInt(st2.nextToken()); else vn[i] = 0; } faces.add(v); facestexs.add(vt); facesnorms.add(vn); } else // LOADS MATERIALS if (newline.charAt(0) == 'm' && newline.charAt(1) == 't' && newline.charAt(2) == 'l' && newline.charAt(3) == 'l' && newline.charAt(4) == 'i' && newline.charAt(5) == 'b') { String[] coordstext = new String[3]; coordstext = newline.split("\\s+"); if (mtl_path != null) loadmaterials(); } else // USES MATELIALS if (newline.charAt(0) == 'u' && newline.charAt(1) == 's' && newline.charAt(2) == 'e' && newline.charAt(3) == 'm' && newline.charAt(4) == 't' && newline.charAt(5) == 'l') { String[] coords = new String[2]; String[] coordstext = new String[3]; coordstext = newline.split("\\s+"); coords[0] = coordstext[1]; coords[1] = facecounter + ""; mattimings.add(coords); // System.out.println(coords[0] + ", " + coords[1]); } } } } catch (IOException e) { System.out.println("Failed to read file: " + br.toString()); } catch (NumberFormatException e) { System.out.println("Malformed OBJ file: " + br.toString() + "\r \r" + e.getMessage()); } } private void loadmaterials() { FileReader frm; String refm = mtl_path; try { frm = new FileReader(refm); BufferedReader brm = new BufferedReader(frm); materials = new MtlLoader(brm, mtl_path); frm.close(); } catch (IOException e) { System.out.println("Could not open file: " + refm); materials = null; } } private void centerit() { float xshift = (rightpoint - leftpoint) / 2.0F; float yshift = (toppoint - bottompoint) / 2.0F; float zshift = (nearpoint - farpoint) / 2.0F; for (int i = 0; i < vertexsets.size(); i++) { float coords[] = new float[4]; coords[0] = ((float[]) vertexsets.get(i))[0] - leftpoint - xshift; coords[1] = ((float[]) vertexsets.get(i))[1] - bottompoint - yshift; coords[2] = ((float[]) vertexsets.get(i))[2] - farpoint - zshift; vertexsets.set(i, coords); } } public float getXWidth() { float returnval = 0.0F; returnval = rightpoint - leftpoint; return returnval; } public float getYHeight() { float returnval = 0.0F; returnval = toppoint - bottompoint; return returnval; } public float getZDepth() { float returnval = 0.0F; returnval = nearpoint - farpoint; return returnval; } public int numpolygons() { return numpolys; } public void opengldrawtolist(GL2 gl) { //////////////////////////////////////// /// With Materials if available //////// //////////////////////////////////////// this.objectlist = gl.glGenLists(1); int nextmat = -1; int matcount = 0; int totalmats = mattimings.size(); String[] nextmatnamearray = null; String nextmatname = null; if (totalmats > 0 && materials != null) { nextmatnamearray = (String[]) (mattimings.get(matcount)); nextmatname = nextmatnamearray[0]; nextmat = Integer.parseInt(nextmatnamearray[1]); } gl.glNewList(objectlist, GL2.GL_COMPILE); Texture glTxt = null; for (int i = 0; i < materials.Textures.size(); i++) { glTxt = ((MtlLoader.mtexture) materials.Textures.get(i)).glTexture; glTxt.enable(gl); glTxt.bind(gl); } for (int i = 0; i < faces.size(); i++) { if (i == nextmat) { gl.glEnable(GL2.GL_COLOR_MATERIAL); gl.glColor4f((materials.getKd(nextmatname))[0], (materials.getKd(nextmatname))[1], (materials.getKd(nextmatname))[2], (materials.getd(nextmatname))); matcount++; if (matcount < totalmats) { nextmatnamearray = (String[]) (mattimings.get(matcount)); nextmatname = nextmatnamearray[0]; nextmat = Integer.parseInt(nextmatnamearray[1]); } } int[] tempfaces = (int[]) (faces.get(i)); int[] tempfacesnorms = (int[]) (facesnorms.get(i)); int[] tempfacestexs = (int[]) (facestexs.get(i)); //// Quad Begin Header //// int polytype; if (tempfaces.length == 3) { polytype = GL.GL_TRIANGLES; } else if (tempfaces.length == 4) { polytype = GL2.GL_QUADS; } else { polytype = GL2.GL_POLYGON; } gl.glBegin(polytype); //////////////////////////// for (int w = 0; w < tempfaces.length; w++) { if (tempfacesnorms[w] != 0) { float normtempx = ((float[]) vertexsetsnorms.get(tempfacesnorms[w] - 1))[0]; float normtempy = ((float[]) vertexsetsnorms.get(tempfacesnorms[w] - 1))[1]; float normtempz = ((float[]) vertexsetsnorms.get(tempfacesnorms[w] - 1))[2]; gl.glNormal3f(normtempx, normtempy, normtempz); } if (tempfacestexs[w] != 0) { float textempx = ((float[]) vertexsetstexs.get(tempfacestexs[w] - 1))[0]; float textempy = ((float[]) vertexsetstexs.get(tempfacestexs[w] - 1))[1]; float textempz = ((float[]) vertexsetstexs.get(tempfacestexs[w] - 1))[2]; gl.glTexCoord3f(textempx, 1f - textempy, textempz); } float tempx = ((float[]) vertexsets.get(tempfaces[w] - 1))[0]; float tempy = ((float[]) vertexsets.get(tempfaces[w] - 1))[1]; float tempz = ((float[]) vertexsets.get(tempfaces[w] - 1))[2]; gl.glVertex3f(tempx, tempy, tempz); } //// Quad End Footer ///// gl.glEnd(); /////////////////////////// } gl.glEndList(); } public void opengldraw(GL2 gl) { gl.glCallList(objectlist); gl.glDisable(GL2.GL_COLOR_MATERIAL); } } package PowerOBJLoader; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.awt.GLJPanel; import com.jogamp.opengl.glu.GLU; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.ArrayList; import java.util.Calendar; import javax.swing.JFrame; import com.jogamp.opengl.util.FPSAnimator; import com.sun.javafx.geom.Vec3f; public class Example extends GLJPanel implements GLEventListener { private static float angleX = 0; private static float angleY = 0; private static float angleZ = 0; private static int width; private static int height; private FPSAnimator animator; private ArrayList <ObjModel>chairModel = new ArrayList<ObjModel>(); private ObjModel chairModel2 = null; private Vec3f pos=new Vec3f(0,0,-1); private float posz=-1; private boolean a=true; private boolean b=true; private boolean turnL=false; private boolean turnR=false; private int moubtn=0; private int PosX=0; private int PosY=0; public Example() { setFocusable(true); addGLEventListener(this); addMouseListener(new MouseListener() { public void mouseReleased(MouseEvent arg0) { moubtn=0; PosX=0; PosY=0; } public void mousePressed(MouseEvent arg0) { if(arg0.getButton()==MouseEvent.BUTTON1){ moubtn=1; }else if(arg0.getButton()==MouseEvent.BUTTON3){ moubtn=2; PosX=arg0.getX(); PosY=arg0.getY(); } } public void mouseExited(MouseEvent arg0) { } public void mouseEntered(MouseEvent arg0) { } public void mouseClicked(MouseEvent arg0) { } }); addMouseMotionListener(new MouseMotionListener() { public void mouseMoved(MouseEvent arg0) { } public void mouseDragged(MouseEvent arg0) { if(moubtn==1){ }else if(moubtn==2){ pos.x+=1f*(arg0.getX()-PosX)/width; pos.y+=1f*(arg0.getY()-PosY)/height; System.out.println(PosX+"\t"+PosY+"\t"+arg0.getX()+"\t"+arg0.getY()+"\t"+1f*(arg0.getX()-PosX)/width); } } }); addKeyListener(new KeyListener() { public void keyTyped(KeyEvent arg0) { } public void keyReleased(KeyEvent arg0) { if(arg0.getKeyChar()=='a' || arg0.getKeyChar()=='A'){ turnL=false; turnR=false; }else if(arg0.getKeyChar()=='d' || arg0.getKeyChar()=='D'){ turnL=false; turnR=false; } } public void keyPressed(KeyEvent arg0) { if( arg0.getKeyChar()=='f' || arg0.getKeyChar()=='F'){ pos.x=0; pos.y=0; } if( arg0.getKeyChar()=='m' || arg0.getKeyChar()=='M'){ a=true; b=false; }else if( arg0.getKeyChar()=='n' || arg0.getKeyChar()=='N'){ a=false; b=true; } if( arg0.getKeyChar()=='w' || arg0.getKeyChar()=='W'){ pos.z+=0.05f; }else if( arg0.getKeyChar()=='s' || arg0.getKeyChar()=='S'){ pos.z-=0.05f; } if(arg0.getKeyChar()=='a' || arg0.getKeyChar()=='A'){ turnL=true; turnR=false; }else if(arg0.getKeyChar()=='d' || arg0.getKeyChar()=='D'){ turnL=false; turnR=true; } } }); animator = new FPSAnimator(this, 10, false); animator.start(); width = height = 800; } public void init(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); gl.glEnable(GL2.GL_DEPTH_TEST); gl.glShadeModel(GL2.GL_SMOOTH); gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST); gl.glEnable(GL2.GL_CULL_FACE); gl.glEnable(GL2.GL_NORMALIZE); // gl.glMatrixMode(GL2.GL_PROJECTION); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); /* gl.glEnable(GL2.GL_LIGHTING); gl.glEnable(GL2.GL_LIGHT0); gl.glEnable(GL2.GL_LIGHT1); gl.glShadeModel(GL2.GL_SMOOTH);*/ gl.glClearColor(0.9f, 0.9f, 0.9f, 0.1f); // 背景色 setLight(gl); GLU glu = new GLU(); if (false == loadModels(gl)) { System.exit(1); } glu.gluPerspective(1, (double) getWidth() / getHeight(), 0.3, 50); gl.glMatrixMode(GL2.GL_MODELVIEW); } public void display(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); // GLU glu=new GLU(); GLU glu=GLU.createGLU(gl); gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); /* gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity();*/ /* // Perspective. float widthHeightRatio = (float) getWidth() / (float) getHeight(); glu.gluPerspective(45, widthHeightRatio, 1, 1000); glu.gluLookAt(0, 0, 2, 0, 0, 0, 0, 1, 0);*/ // Change back to model view matrix. gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(pos.x, pos.y, pos.z); gl.glRotatef(angleX, 0f, 1f, 0f); gl.glScaled(0.005f, 0.005f, 0.005f); if(turnL==true){ angleX=angleX+4f; } if(turnR==true){ angleX=angleX-4f; } // System.out.println("A in display: "+a); /* gl.glRotatef((float)Math.random()*360, 0f, 1f, 0f); gl.glTranslatef(10-(float)Math.random(), 0, -1);*/ /* if(a==true){ chairModel.mDraw(); }*/ for (int i=0;i<chairModel.size();i++){ // chairModel.get(i).mRotate(i*30f); chairModel.get(i).mDraw(); } /*gl.glTranslatef(1, 10-(float)Math.random(), -1); gl.glRotatef((float)Math.random()*360, 0f, 1f, 0f);*/ // if(b==true){ // // chairModel2.mRotate(90f); // chairModel2.mDraw(); // } // animator.pause(); gl.glFlush(); } private Boolean loadModels(GL2 gl) { for(int i=0;i<1;i++){ ObjModel temp = new ObjModel("E:/Objs/cb.obj", gl); chairModel.add(temp); } return true; } public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { GL2 gl = drawable.getGL().getGL2(); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); GLU glu = new GLU(); glu.gluPerspective(100, (double) getWidth() / getHeight(), 0.1, 100); gl.glMatrixMode(GL2.GL_MODELVIEW); } public void dispose(GLAutoDrawable arg0) { // TODO Auto-generated method stub } private void setLight(GL2 gl) { gl.glEnable(GL2.GL_LIGHTING); float SHINE_ALL_DIRECTIONS = 1; float[] lightPos = { -30, 30, 30, SHINE_ALL_DIRECTIONS }; float[] lightColorAmbient = { 0.5f, 0.5f, 0.5f, 1f }; float[] lightColorSpecular = { 0.9f, 0.9f, 0.9f, 1f }; // Set light parameters. // gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, lightPos, 0); gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, lightColorAmbient, 0); // gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPECULAR, lightColorSpecular, 0); gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, lightColorSpecular, 0); gl.glEnable(GL2.GL_LIGHT0); } public static void main(String[] args) { JFrame window = new JFrame(); window.getContentPane().add(new Example()); window.setSize(width, height); window.setVisible(true); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } |
Administrator
|
You're still using display lists, you don't use VBOs.
Julien Gouesse | Personal blog | Website
|
i'm working on this with both my company laptop and my own, but i can't upload my works from my company laptop, surely you know why.
so i just put my "display list" code here, i believe it should be very easy to modify this code to VBO. I'm not giving up at this but i do really want a shortcut, driving me crazy... |
Administrator
|
If you don't understand your own code, you won't be able to maintain it.
Julien Gouesse | Personal blog | Website
|
In reply to this post by Ususuus
The resource I offered has a complete example doing exactly what you want, using VBOs and non-deprecated shaders, with explanations and running code, in Java/JOGL. I'm not sure how much shorter a shortcut I can offer.
|
Free forum by Nabble | Edit this page |