Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
1,71 MB
Nội dung
Dr Manuel Carcenac - European University of Lefke Advanced topics in modeling with Java OpenGL - JOGL Spatial orientation: Euler angles, gimbal lock, a practical solution Textures NURBS surfaces Fractal landscape generated with diamond-square algorithm References: http://jogamp.org/ (for JOGL 2.0) http://download.java.net/media/jogl/jogl-2.x-docs/ http://www.glprogramming.com/red/ http://eng.eul.edu.tr/manuel/Course_on_Graphics_in_Java/Course_on_Graphics_in_Java.htm (for practical introduction to JOGL 2.0) Advanced Animation and Rendering Techniques – Theory and Practice Alan Watt, Mark Watt; Addison-Wesley, ACM press http://www.mactech.com/articles/develop/issue_25/schneider.html http://www.oera.net/How2/TextureMaps2.htm http://planetpixelemporium.com/planets.html (for NURBS) (for beautiful free planet textures) (for beautiful free planet textures) Dr Manuel Carcenac - European University of Lefke Spatial orientation: Euler angles, gimbal lock, a practical solution Euler angles: any spatial orientation of an object can be described by angles = degrees of freedom how to get from the absolute coordinate system to the local coordinate system of the object ? global rotation = succession of rotations around coordinate system axes several possibilities: in which order we rotate around axes x , y , z ? one possible solution: absolute (x,y,z) rot of angle a around axis z rot of angle b around axis y' (x',y',z) (x'',y',z') local (x'',y'',z'') rot of angle c around axis x'' z z' z'' c b y'' c a a y' y x'' b x' x Dr Manuel Carcenac - European University of Lefke gimbal lock: decoupled degrees of freedom: axes of rotation remain more or less orthogonal angles remain decoupled = they have independent actions big problem: loss of a degree of freedom: in certain configurations, of the axes of rotation become aligned! their associated angles are equivalent = they produce the same rotation in space only effective degrees of freedom left example: b = - / a and c both rotate around axis z once b is fixed, only possible to rotate around z axis with a and c z x'' z' y'' c z'' y' c a y a x' x annoying problem: degrees of freedom partially coupled: b tends toward / a and c become increasingly coupled varying a has an increasing effect on the rotation that should be controled only by c = very disturbing for a human operator (especially to control camera orientation ) Dr Manuel Carcenac - European University of Lefke a practical solution: instead of Euler angles, define directly the local coordinate system of the object with orthogonal unit vectors u , v , w assume u , v , w given initially how to adjust the space orientation of u , v , w ? incremental approach: start with an inital u , v , w then rotate gradually u , v , w in space new u , v , w after each incremental rotation δ u' u w' w v' v at each time step, apply small rotations around u , v or w = applied relatively to the object intuitive for operator axes of rotation remain practically orthogonal over a time step remain far away from any gimbal lock configuration Dr Manuel Carcenac - European University of Lefke 3D rotation around a vector: rotation of angle δ around unit vector n : v v' v' n×v v' δ v v= v n v= = (n v) n v = v - (n v) n v' = v= + cos δ v + sin δ n×v v' = cos δ v + (1 - cos δ) (n v) n + sin δ n×v Dr Manuel Carcenac - European University of Lefke application to attitude control of virtual camera: initial orientation of camera: w aiming direction uup up vector = up direction of screen u orthogonalized relative to w : u = uup - (u.w) w uup u = uup - (uup.w) w w v=w×u real-time control of evolution of camera orientation: we adjust camera orientation in real time = we are in a spacecraft and we control its orientation (attitude control system, attitude rockets) small rotations over roll , pitch , yaw at each time step u w yaw roll pitch v Dr Manuel Carcenac - European University of Lefke controlling orientation with some keyboard action keys: fast rotation: rotation 10 δ Insert Page Up roll incline left: rot(-δ,w) over u,v Delete Page Down roll incline right: rot(δ,w) over u,v pitch up: rot(δ,v) over u,w yaw left: rot(δ,u) over v,w yaw right: rot(-δ,u) over v,w pitch down: rot(-δ,v) over u,w Insert key pressed while other keys used fast rotation by 10 δ per time step Dr Manuel Carcenac - European University of Lefke extra: position control of virtual camera: how to move the camera? incremental approach: initial position p small translation over p at each time step translation expressed relatively to camera orientation: move backward - forward: intuitive for operator translation along w move left - right: translation along v move down - up: translation along u fast move: translation 10 δ Insert Page Up move forward: pp+δw moving mode Delete Page Down move backward: pp-δw move left: pp-δv move up: pp+δu move right: pp+δv move down: pp-δu Delete key pressed while other keys used moving mode, else rotation mode Insert key pressed while other keys used fast move by 10 δ per time step Dr Manuel Carcenac - European University of Lefke class V3d: operations on 3D vectors class V3d { double x , y , z; V3d() {} V3d(double x , double y , double z) { this.x = x; void V3d_move(V3d n , double d) { this.x += d * n.x; this.y += d * n.y; this.z += d * n.z; } this.y = y; this.z = z; } // this < this + d * n void V3d_rotate(V3d n , double theta) // this < rotation (theta , n) of this; n unit vector; theta in deg { double c = Math.cos(theta * Math.PI / 180.0) , s = Math.sin(theta * Math.PI / 180.0); double k = (1 - c) * (this.x * n.x + this.y * n.y + this.z * n.z); double x = c * this.x + k * n.x + s * (n.y * this.z - n.z * this.y) , y = c * this.y + k * n.y + s * (n.z * this.x - n.x * this.z) , z = c * this.z + k * n.z + s * (n.x * this.y - n.y * this.x); this.x = x; this.y = y; this.z = z; } void V3d_orthogonalize(V3d b) // this < this - (this b) b { double d = this.x * b.x + this.y * b.y + this.z * b.z; this.x -= d * b.x; this.y -= d * b.y; this.z -= d * b.z; } void V3d_normalize() // this < unit vector (this) { double d = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); if (d < 1.0e-10) { System.out.println("in V3d_normalize: d < 1.0e-10"); this.x /= d; this.y /= d; this.z /= d; } void V3d_vector_product(V3d a , V3d b) // this < a x b { this.x = a.y * b.z - a.z * b.y; this.y = a.z * b.x - a.x * b.z; System.exit(0); } this.z = a.x * b.y - a.y * b.x; } void normal_3_points(V3d p0 , V3d p1 , V3d p2) { x = (p1.y - p0.y) * (p2.z - p0.z) - (p1.z - p0.z) * (p2.y - p0.y); y = (p1.z - p0.z) * (p2.x - p0.x) - (p1.x - p0.x) * (p2.z - p0.z); z = (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x); double d = Math.sqrt( x * x + y * y + z * z); if (d < 1.0e-10) { System.out.println("d < 1.0e-10 in normal_3_points"); x /= d; y /= d; z /= d; } System.exit(0); } } Dr Manuel Carcenac - European University of Lefke class Craft: virtual craft (orientation and position controlled in real time with keyboard) class Craft { V3d p , u , v , w; double dmove , drot; boolean move , fast; Craft( double posx , double posy , double posz , double aimx , double aimy , double aimz , double upx , double upy , double upz , final JFrame f , double dm , double dr) { p = new V3d(posx , posy , posz); w = new V3d(aimx , aimy , aimz); w.V3d_normalize(); u = new V3d(upx , upy , upz); u.V3d_orthogonalize(w); u.V3d_normalize(); v = new V3d(); v.V3d_vector_product(w , u); this.dmove = dm; this.drot = dr; move = false; fast = false; f.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); double d; if (move) d = (fast ? 10 * dmove : dmove); else d = (fast ? 10 * drot : drot); switch (key) { case KeyEvent.VK_LEFT: if (move) p.V3d_move(v , - d); else { v.V3d_rotate(u , d); w.V3d_rotate(u , d); }; break; case KeyEvent.VK_RIGHT: if (move) p.V3d_move(v , d); else { v.V3d_rotate(u , - d); w.V3d_rotate(u , - d); }; break; case KeyEvent.VK_DOWN: if (move) p.V3d_move(u , - d); else { u.V3d_rotate(v , - d); w.V3d_rotate(v , - d); }; break; case KeyEvent.VK_UP: if (move) p.V3d_move(u , d); else { u.V3d_rotate(v , d); w.V3d_rotate(v , d); }; break; case KeyEvent.VK_PAGE_DOWN: if (move) p.V3d_move(w , - d); else { u.V3d_rotate(w , d); v.V3d_rotate(w , d); }; break; case KeyEvent.VK_PAGE_UP: if (move) p.V3d_move(w , d); else { u.V3d_rotate(w , - d); v.V3d_rotate(w , - d); }; break; case KeyEvent.VK_INSERT: fast = true; break; case KeyEvent.VK_DELETE: move = true; break; } f.repaint(); } } ); f.addKeyListener(new KeyAdapter() { public void keyReleased(KeyEvent e) { int key = e.getKeyCode(); switch (key) { case KeyEvent.VK_INSERT: fast = false; break; case KeyEvent.VK_DELETE: move = false; break; } } } ); } } what if we need to use keyPressed and keyReleased for other keys as well ? 10 Dr Manuel Carcenac - European University of Lefke example: interactive cubic NURBS: degree 3, order 4, nc×nc control pts, nc + knots along u and v specific weight w for each control point select with buttons a control point then change its x, y, z, w with sliders control points are displayed as blue dots (red dot for selected one) class Gui { JFrame f; DrawingPanel p; JPanel ps; JSlider skx , sky , skz , skw; JLabel lkx , lky , lkz , lkw; JButton b_left , b_right , b_down , b_up; float[][] xc , yc , zc , wc; float SIZE; int nc , ik , jk; class DrawingPanel extends GLJPanel { public void display(GLAutoDrawable drawable) { //********** DISPLAY //// - CONTROL POINTS for (int i = ; i < nc ; i++) for (int j = ; j < nc ; j++) { if (i == ik && j == jk) gl.glMaterialfv( , new float[] { 1.0f , 0.0f , 0.0f , 1.0f } , 0); else gl.glMaterialfv( , new float[] { 0.0f , 0.0f , 1.0f , 1.0f } , 0); gl.glPushMatrix(); gl.glTranslatef(xc[i][j] , yc[i][j] , zc[i][j]); glu.gluSphere(quad , 1.5f , 10 , 10); gl.glPopMatrix(); } //// - NURBS gl.glMaterialfv( , new float[] { 1.0f , 1.0f , 0.0f , 1.0f } , 0); float[] knots = new float[nc + 4]; knots[0] = 0.0f; knots[1] = 0.0f; knots[2] = 0.0f; knots[3] = 0.0f; for (int k = ; k < nc ; k++) knots[k] = 0.0f + 1.0f * (k - 3) / (nc - 3); knots[nc + 0] = 1.0f; knots[nc + 1] = 1.0f; knots[nc + 2] = 1.0f; knots[nc + 3] = 1.0f; float[] ctrlpts = new float[nc * nc * 4]; for (int i = ; i < nc ; i++) for (int j = ; j < nc ; j++) { ctrlpts[nc * * i + * j + 0] = xc[i][j]; ctrlpts[nc * * i + * j + 1] = yc[i][j]; ctrlpts[nc * * i + * j + 2] = zc[i][j]; ctrlpts[nc * * i + * j + 3] = wc[i][j]; } 36 Dr Manuel Carcenac - European University of Lefke glugl2.gluBeginSurface(nurbs); glugl2.gluNurbsSurface( nurbs , nc + , knots , nc + , knots , nc * , , ctrlpts ,4,4 , GL2.GL_MAP2_VERTEX_4); glugl2.gluEndSurface(nurbs); gl.glFlush(); } } ); } } Gui() { f = new JFrame(); f.setFocusable(true); f.setVisible(true); p = new DrawingPanel(); f.getContentPane().add(p , BorderLayout.CENTER); String s = JOptionPane.showInputDialog(f , "number of control points over u and v; at least 4"); nc = Integer.valueOf(s).intValue(); if (nc < 4) { System.out.println("nc < 4"); System.exit(0); } SIZE = 100.0f; xc = new float[nc][nc]; yc = new float[nc][nc]; zc = new float[nc][nc]; wc = new float[nc][nc]; for (int i = ; i < nc ; i++) for (int j = ; j < nc ; j++) { xc[i][j] = 0.0f; yc[i][j] = SIZE * i / (nc - 1); zc[i][j] = SIZE * j / (nc - 1); wc[i][j] = 1.0f; } ik = 0; jk = 0; ps = new JPanel(); ps.setLayout(new GridLayout(0 , 2)); f.getContentPane().add(ps , BorderLayout.EAST); b_left = new JButton(); b_left.setText("select left"); ps.add(b_left); b_left.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ik ; if (ik == -1) ik = nc - 1; skx.setValue((int)xc[ik][jk]); sky.setValue((int)yc[ik][jk]); skz.setValue((int)zc[ik][jk]); skw.setValue((int)(wc[ik][jk] * 10)); f.repaint(); } } ); b_right = new JButton(); b_right.setText("select right"); ps.add(b_right); b_right.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ik++; if (ik == nc) ik = 0; skx.setValue((int)xc[ik][jk]); sky.setValue((int)yc[ik][jk]); skz.setValue((int)zc[ik][jk]); skw.setValue((int)(wc[ik][jk] * 10)); f.repaint(); } } ); b_down = new JButton(); b_down.setText("select down"); ps.add(b_down); b_down.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { jk ; if (jk == -1) jk = nc - 1; skx.setValue((int)xc[ik][jk]); sky.setValue((int)yc[ik][jk]); skz.setValue((int)zc[ik][jk]); skw.setValue((int)(wc[ik][jk] * 10)); f.repaint(); } } ); b_up = new JButton(); b_up.setText("select up"); ps.add(b_up); b_up.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { jk++; if (jk == nc) jk = 0; skx.setValue((int)xc[ik][jk]); sky.setValue((int)yc[ik][jk]); skz.setValue((int)zc[ik][jk]); skw.setValue((int)(wc[ik][jk] * 10)); f.repaint(); } } ); 37 Dr Manuel Carcenac - European University of Lefke skx = new JSlider(JSlider.HORIZONTAL , -100 , 100 , 0); lkx = new JLabel(" x of selected control point"); sky = new JSlider(JSlider.HORIZONTAL , -50 , 150 , 0); lky = new JLabel(" y of selected control point"); skz = new JSlider(JSlider.HORIZONTAL , -50 , 150 , 0); lkz = new JLabel(" z of selected control point"); skw = new JSlider(JSlider.HORIZONTAL , , 100 , 10); lkw = new JLabel(" w of selected control point"); skx.addChangeListener( { sky.addChangeListener( { skz.addChangeListener( { skw.addChangeListener( { ps.add(skx); ps.add(lkx); ps.add(sky); ps.add(lky); ps.add(skz); ps.add(lkz); ps.add(skw); ps.add(lkw); xc[ik][jk] = (float)(skx.getValue()); f.repaint(); } } ); yc[ik][jk] = (float)(sky.getValue()); f.repaint(); } } ); zc[ik][jk] = (float)(skz.getValue()); f.repaint(); } } ); wc[ik][jk] = skw.getValue() / 10.0f; f.repaint(); } } ); f.setSize(new Dimension(1000 + 16 , 600 + 38)); } } 38 Dr Manuel Carcenac - European University of Lefke 39 Dr Manuel Carcenac - European University of Lefke 40 Dr Manuel Carcenac - European University of Lefke applying a texture over a NURBS surface: how to define the mapping: ut and vt in function of u , v ? use a 2D NURBS surface = points of coordinates (ut , vt) allows specification of deformations (stretching, squeezing) of texture over NURBS surface simple case: linear mapping: degree 1, order 2 control points + = knots along u and v float[] tex_knots = new float[] { 0.0f , 0.0f , 1.0f , 1.0f }; float[] tex_ctrlpts = new float[] { 0.0f , 0.0f , 0.0f , 1.0f , 1.0f , 0.0f , 1.0f , 1.0f }; glugl2.gluBeginSurface(nurbs); glugl2.gluNurbsSurface( nurbs , , tex_knots , , tex_knots , * , , tex_ctrlpts , , , GL2.GL_MAP2_TEXTURE_COORD_2); glugl2.gluNurbsSurface( nurbs , , GL2.GL_MAP2_VERTEX_3); glugl2.gluEndSurface(nurbs); not yet implemented in JOGL 41 Dr Manuel Carcenac - European University of Lefke Fractal landscape generated with diamond-square algorithm starting idea: subdivide each quadrangle into sub quadrangles generate each of the new points of the finer grid: height of point = middle of the heights of its already generated closest neighbors + random pertubation 1st step: generate points at centers of quadrangles 2nd step: generate points at middles of quadrangles' sides 1st step 2nd step 42 Dr Manuel Carcenac - European University of Lefke levels of subdivision of a grid of points: grid of (2n + 1) × (2n + 1) points 2n × 2n quadrangles n + levels of the grid: k = 0: × points = corners of the whole grid k = 1: × points quadrangles k = n: (2n + 1) × (2n + 1) points quadrangle full grid Ik = , , 2k level-k coordinates of a point at level k : Jk = , , 2k i = 2n-k Ik its absolute (level-n) coordinates are: j = 2n-k Jk example: n = × points level-0 coordinates: level-1 coordinates: level-2 coordinates: 43 Dr Manuel Carcenac - European University of Lefke how to perturb the points: square grid of horizontal size H size of quadrangle of level k is H / 2k roughness = parameter from to function rand() random number in range [0 , 1] perturbation = r × (2 rand() -1) × H / 2k assume points at level k are already generated generate in two steps the new points at level k + first step (diamond step): for every point (Ik+1 , Jk+1) at level k +1 : if point (Ik+1 , Jk+1) center of a level-k quadrangle : z of center point (Ik+1 , Jk+1) perturbation + middle of z of level-(k+1) points (Ik+1 - 1, Jk+1 - 1) , (Ik+1 + , Jk+1 - 1) , (Ik+1 - 1, Jk+1 + 1) , (Ik+1 + , Jk+1 + 1) second step (square step): for every point (Ik+1 , Jk+1) at level k +1 : if point (Ik+1 , Jk+1) not already generated during first step : z of center point (Ik+1 , Jk+1) perturbation + middle of z of level-(k+1) points (Ik+1 - 1, Jk+1) , (Ik+1 + , Jk+1) , (Ik+1 , Jk+1 - 1) , (Ik+1 , Jk+1 + 1) Note: Ik+1 , Jk+1 level-(k+1) coordinates multiply them by 2n-k-1 to obtain the absolute coordinates 44 Dr Manuel Carcenac - European University of Lefke pseudo-code: for k , , n - 1: for Ik+1 , , 2k+1 : for Jk+1 , , 2k+1 : if Ik+1 odd and Jk+1 odd : z( 2n-k-1 Ik+1 , 2n-k-1 Jk+1 ) z_middle( 2n-k-1 (Ik+1 - 1) , 2n-k-1 (Jk+1 - 1) , 2n-k-1 (Ik+1 + 1) , 2n-k-1 (Jk+1 - 1) , 2n-k-1 (Ik+1 - 1) , 2n-k-1 (Jk+1 + 1) , 2n-k-1 (Ik+1 + 1) , 2n-k-1 (Jk+1 + 1) ) + r (2 rand() -1) H / 2k for Ik+1 , , 2k+1 : for Jk+1 , , 2k+1 : if (Ik+1 odd and Jk+1 even) or (Ik+1 even and Jk+1 odd) : z( 2n-k-1 Ik+1 , 2n-k-1 Jk+1 ) z_middle( 2n-k-1 (Ik+1 - 1) , 2n-k-1 Jk+1 , 2n-k-1 (Ik+1 + 1) , 2n-k-1 Jk+1 , 2n-k-1 Ik+1 , 2n-k-1 (Jk+1 - 1) , 2n-k-1 Ik+1 , 2n-k-1 (Jk+1 + 1) ) + r (2 rand() -1) H / 2k we have generated a grid of points of varying height non flat, twisted quadrangles flat polygons required for Open GL subdivide each quadrangle into two triangles 45 Dr Manuel Carcenac - European University of Lefke fractal landscape with quadrangles represented by couples of triangles: class FractalLandscape { int N; double size; double[][] z; // 1