java left logo
java middle logo
java right logo
 

Home arrow Other API Tips arrow JOGL arrow ArcBall rotation - NeHe Tutorial JOGL Port
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Java Network
Java Forums
Java Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 3936
Java SE Tips: 614
Java ME Tips: 202
Java EE Tips: 183
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
ArcBall rotation - NeHe Tutorial JOGL Port E-mail
User Rating: / 14
PoorBest 

Wouldn’t it be great to rotate your model at will, just by using the mouse? With an ArcBall you can do just that. This example shows how to implement this.

This is the Java port of the one of the NeHe OpenGL tutorials.

You can get complete IntelliJ IDEA project structure (all source, resources, build script, …) by downloading the source distribution from here.

The original post of the programmer who ported the examples can be found here.


Image

package demos.nehe.lesson48;

import demos.common.GLDisplay;

/**
 @author Pepijn Van Eeckhoudt
 */
public class Lesson48 {
    public static void main(String[] args) {
        GLDisplay neheGLDisplay = GLDisplay.createGLDisplay("Lesson 48: ArcBall Controller");
        Renderer renderer = new Renderer();
        InputHandler inputHandler = new InputHandler(renderer, neheGLDisplay);
        neheGLDisplay.addGLEventListener(renderer);
        neheGLDisplay.addMouseListener(inputHandler);
        neheGLDisplay.addMouseMotionListener(inputHandler);
        neheGLDisplay.start();
    }
}


package demos.nehe.lesson48;

import demos.common.GLDisplay;

import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

class InputHandler extends MouseInputAdapter {
    private Renderer renderer;

    public InputHandler(Renderer renderer, GLDisplay glDisplay) {
        this.renderer = renderer;
        glDisplay.registerMouseEventForHelp(
                MouseEvent.MOUSE_CLICKED, MouseEvent.BUTTON1_DOWN_MASK,
                "Toggle display mode"
        );
    }

    public void mouseClicked(MouseEvent e) {
        if (SwingUtilities.isRightMouseButton(e)) {
            renderer.reset();
        }
    }

    public void mousePressed(MouseEvent mouseEvent) {
        if (SwingUtilities.isLeftMouseButton(mouseEvent)) {
            renderer.startDrag(mouseEvent.getPoint());
        }
    }

    public void mouseDragged(MouseEvent mouseEvent) {
        if (SwingUtilities.isLeftMouseButton(mouseEvent)) {
            renderer.drag(mouseEvent.getPoint());
        }
    }
}


package demos.nehe.lesson48;

import java.awt.*;

/**
 * Created by IntelliJ IDEA.
 * User: pepijn
 * Date: Aug 7, 2005
 * Time: 5:18:33 PM
 * To change this template use File | Settings | File Templates.
 */
class ArcBall {
    private static final float Epsilon = 1.0e-5f;

    Vector3f StVec;          //Saved click vector
    Vector3f EnVec;          //Saved drag vector
    float adjustWidth;       //Mouse bounds width
    float adjustHeight;      //Mouse bounds height

    public ArcBall(float NewWidth, float NewHeight) {
        StVec = new Vector3f();
        EnVec = new Vector3f();
        setBounds(NewWidth, NewHeight);
    }

    public void mapToSphere(Point point, Vector3f vector) {
        // Copy paramter into temp point
        Point2f tempPoint = new Point2f(point.x, point.y);

        // Adjust point coords and scale down to range of [-1 ... 1]
        tempPoint.x = (tempPoint.x * this.adjustWidth1.0f;
        tempPoint.y = 1.0f (tempPoint.y * this.adjustHeight);

        // Compute the square of the length of the vector to the point from the center
        float length = (tempPoint.x * tempPoint.x(tempPoint.y * tempPoint.y);

        // If the point is mapped outside of the sphere... (length > radius squared)
        if (length > 1.0f) {
            // Compute a normalizing factor (radius / sqrt(length))
            float norm = (float) (1.0 / Math.sqrt(length));

            // Return the "normalized" vector, a point on the sphere
            vector.x = tempPoint.x * norm;
            vector.y = tempPoint.y * norm;
            vector.z = 0.0f;
        else    //Else it's on the inside
        {
            // Return a vector to a point mapped inside the sphere 
            // sqrt(radius squared - length)
            vector.x = tempPoint.x;
            vector.y = tempPoint.y;
            vector.z = (floatMath.sqrt(1.0f - length);
        }

    }

    public void setBounds(float NewWidth, float NewHeight) {
        assert((NewWidth > 1.0f&& (NewHeight > 1.0f));

        // Set adjustment factor for width/height
        adjustWidth = 1.0f ((NewWidth - 1.0f0.5f);
        adjustHeight = 1.0f ((NewHeight - 1.0f0.5f);
    }

    // Mouse down
    public void click(Point NewPt) {
        mapToSphere(NewPt, this.StVec);

    }

    // Mouse drag, calculate rotation
    public void drag(Point NewPt, Quat4f NewRot) {
        // Map the point to the sphere
        this.mapToSphere(NewPt, EnVec);

        // Return the quaternion equivalent to the rotation
        if (NewRot != null) {
            Vector3f Perp = new Vector3f();

            // Compute the vector perpendicular to the begin and end vectors
            Vector3f.cross(Perp, StVec, EnVec);

            // Compute the length of the perpendicular vector
            if (Perp.length() > Epsilon)    //if its non-zero
            {
                // We're ok, so return the perpendicular vector as the transform 
                // after all
                NewRot.x = Perp.x;
                NewRot.y = Perp.y;
                NewRot.z = Perp.z;
                // In the quaternion values, w is cosine (theta / 2), 
                // where theta is rotation angle
                NewRot.w = Vector3f.dot(StVec, EnVec);
            else                                    //if its zero
            {
                // The begin and end vectors coincide, so return an identity transform
                NewRot.x = NewRot.y = NewRot.z = NewRot.w = 0.0f;
            }
        }
    }

}


package demos.nehe.lesson48;

/**
 * Created by IntelliJ IDEA.
 * User: pepijn
 * Date: Aug 7, 2005
 * Time: 6:01:31 PM
 * To change this template use File | Settings | File Templates.
 */
class Matrix4f {
    float M00;
    float M10;
    float M20;
    float M30;
    float M01;
    float M11;
    float M21;
    float M31;
    float M02;
    float M12;
    float M22;
    float M32;
    float M03;
    float M13;
    float M23;
    float M33;

    public Matrix4f() {
        setIdentity();
    }

    void get(float[] dest) {
        dest[0= M00;
        dest[1= M10;
        dest[2= M20;
        dest[3= M30;
        dest[4= M01;
        dest[5= M11;
        dest[6= M21;
        dest[7= M31;
        dest[8= M02;
        dest[9= M12;
        dest[10= M22;
        dest[11= M32;
        dest[12= M03;
        dest[13= M13;
        dest[14= M23;
        dest[15= M33;
    }

    void setZero() {
        M00 = M01 = M02 = M03 = M10 = M11 = M12 = M13 = M20 = M21 = M22 = 
                M23 = M30 = M31 = M32 = M33 = 0.0f;
    }

    void setIdentity() {
        setZero();
        M00 = M11 = M22 = M33 = 1.0f;
    }

    void setRotation(Quat4f q1) {
        float n, s;
        float xs, ys, zs;
        float wx, wy, wz;
        float xx, xy, xz;
        float yy, yz, zz;

        n = (q1.x * q1.x(q1.y * q1.y(q1.z * q1.z(q1.w * q1.w);
        s = (n > 0.0f(2.0f / n0.0f;

        xs = q1.x * s;
        ys = q1.y * s;
        zs = q1.z * s;
        wx = q1.w * xs;
        wy = q1.w * ys;
        wz = q1.w * zs;
        xx = q1.x * xs;
        xy = q1.x * ys;
        xz = q1.x * zs;
        yy = q1.y * ys;
        yz = q1.y * zs;
        zz = q1.z * zs;

        M00 = 1.0f (yy + zz);
        M01 = xy - wz;
        M02 = xz + wy;
        M03 = 0f;
        M10 = xy + wz;
        M11 = 1.0f (xx + zz);
        M12 = yz - wx;
        M13 = 0f;
        M20 = xz - wy;
        M21 = yz + wx;
        M22 = 1.0f (xx + yy);
        M23 = 0f;
        M30 = 0f;
        M31 = 0f;
        M32 = 0f;
        M33 = 1f;
    }

    public final void set(Matrix4f m1) {
        M00 = m1.M00; M01 = m1.M01; M02 = m1.M02; M03 = m1.M03;
        M10 = m1.M10; M11 = m1.M11; M12 = m1.M12; M13 = m1.M13;
        M20 = m1.M20; M21 = m1.M21; M22 = m1.M22; M23 = m1.M23;
        M30 = m1.M30; M31 = m1.M31; M32 = m1.M32; M33 = m1.M33;
    }

    /**
     * Sets the value of this matrix to the result of multiplying
     * the two argument matrices together.
     *
     @param m1 the first matrix
     @param m2 the second matrix
     */
    public final void mul(Matrix4f m1, Matrix4f m2) {
        // alias-safe way.
        set(
                m1.M00 * m2.M00 + m1.M01 * m2.M10 + m1.M02 * m2.M20 + m1.M03 * m2.M30,
                m1.M00 * m2.M01 + m1.M01 * m2.M11 + m1.M02 * m2.M21 + m1.M03 * m2.M31,
                m1.M00 * m2.M02 + m1.M01 * m2.M12 + m1.M02 * m2.M22 + m1.M03 * m2.M32,
                m1.M00 * m2.M03 + m1.M01 * m2.M13 + m1.M02 * m2.M23 + m1.M03 * m2.M33,

                m1.M10 * m2.M00 + m1.M11 * m2.M10 + m1.M12 * m2.M20 + m1.M13 * m2.M30,
                m1.M10 * m2.M01 + m1.M11 * m2.M11 + m1.M12 * m2.M21 + m1.M13 * m2.M31,
                m1.M10 * m2.M02 + m1.M11 * m2.M12 + m1.M12 * m2.M22 + m1.M13 * m2.M32,
                m1.M10 * m2.M03 + m1.M11 * m2.M13 + m1.M12 * m2.M23 + m1.M13 * m2.M33,

                m1.M20 * m2.M00 + m1.M21 * m2.M10 + m1.M22 * m2.M20 + m1.M23 * m2.M30,
                m1.M20 * m2.M01 + m1.M21 * m2.M11 + m1.M22 * m2.M21 + m1.M23 * m2.M31,
                m1.M20 * m2.M02 + m1.M21 * m2.M12 + m1.M22 * m2.M22 + m1.M23 * m2.M32,
                m1.M20 * m2.M03 + m1.M21 * m2.M13 + m1.M22 * m2.M23 + m1.M23 * m2.M33,

                m1.M30 * m2.M00 + m1.M31 * m2.M10 + m1.M32 * m2.M20 + m1.M33 * m2.M30,
                m1.M30 * m2.M01 + m1.M31 * m2.M11 + m1.M32 * m2.M21 + m1.M33 * m2.M31,
                m1.M30 * m2.M02 + m1.M31 * m2.M12 + m1.M32 * m2.M22 + m1.M33 * m2.M32,
                m1.M30 * m2.M03 + m1.M31 * m2.M13 + m1.M32 * m2.M23 + m1.M33 * m2.M33
        );
    }

    /**
     * Sets 16 values
     */
    private void set(float m00, float m01, float m02, float m03,
                     float m10, float m11, float m12, float m13,
                     float m20, float m21, float m22, float m23,
                     float m30, float m31, float m32, float m33) {
        this.M00 = m00;
        this.M01 = m01;
        this.M02 = m02;
        this.M03 = m03;
        this.M10 = m10;
        this.M11 = m11;
        this.M12 = m12;
        this.M13 = m13;
        this.M20 = m20;
        this.M21 = m21;
        this.M22 = m22;
        this.M23 = m23;
        this.M30 = m30;
        this.M31 = m31;
        this.M32 = m32;
        this.M33 = m33;
    }
}


package demos.nehe.lesson48;

/**
 * Created by IntelliJ IDEA.
 * User: pepijn
 * Date: Aug 7, 2005
 * Time: 5:46:24 PM
 * To change this template use File | Settings | File Templates.
 */
class Point2f {
    public float x, y;

    public Point2f(float x, float y) {
        this.x = x;
        this.y = y;
    }
}


package demos.nehe.lesson48;

/**
 * Created by IntelliJ IDEA.
 * User: pepijn
 * Date: Aug 7, 2005
 * Time: 5:50:25 PM
 * To change this template use File | Settings | File Templates.
 */
class Quat4f {
    public float x, y, z, w;
}


package demos.nehe.lesson48;

/**
 * Created by IntelliJ IDEA.
 * User: pepijn
 * Date: Aug 7, 2005
 * Time: 5:45:22 PM
 * To change this template use File | Settings | File Templates.
 */
class Vector3f {
    public float x, y, z;

    public static void cross(Vector3f Result, Vector3f v1, Vector3f v2) {
        Result.x = (v1.y * v2.z(v1.z * v2.y);
        Result.y = (v1.z * v2.x(v1.x * v2.z);
        Result.z = (v1.x * v2.y(v1.y * v2.x);
    }

    public static float dot(Vector3f v1, Vector3f v2) {
        return (v1.x * v2.x(v1.y * v2.y(v1.z + v2.z);
    }

    public float length() {
        return (float)Math.sqrt(x * x + y * y + z * z);
    }
}


package demos.nehe.lesson48;

import javax.media.opengl.*;
import javax.media.opengl.glu.GLUquadric;
import javax.media.opengl.glu.GLU;

import java.awt.*;

class Renderer implements GLEventListener {
    // User Defined Variables
    private GLUquadric quadratic;   // Used For Our Quadric
    private GLU glu = new GLU();

    private Matrix4f LastRot = new Matrix4f();
    private Matrix4f ThisRot = new Matrix4f();
    private final Object matrixLock = new Object();
    private float[] matrix = new float[16];

    private ArcBall arcBall = new ArcBall(640.0f480.0f);  // NEW: ArcBall Instance

    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        GL gl = drawable.getGL();

        gl.glViewport(00, width, height);  // Reset The Current Viewport
        gl.glMatrixMode(GL.GL_PROJECTION);   // Select The Projection Matrix
        gl.glLoadIdentity();                 // Reset The Projection Matrix
        
        // Calculate The Aspect Ratio Of The Window
        glu.gluPerspective(45.0f(float) (width(float) (height),            
                1.0f100.0f);
        gl.glMatrixMode(GL.GL_MODELVIEW);  // Select The Modelview Matrix
        gl.glLoadIdentity();               // Reset The Modelview Matrix

        //*NEW* Update mouse bounds for arcball
        arcBall.setBounds((floatwidth, (floatheight);                 
    }

    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, 
            boolean deviceChanged) {
        init(drawable);
    }

    public void init(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();

        // Start Of User Initialization
        LastRot.setIdentity();                                // Reset Rotation
        ThisRot.setIdentity();                                // Reset Rotation
        ThisRot.get(matrix);

        gl.glClearColor(0.0f0.0f0.0f0.5f);              // Black Background
        gl.glClearDepth(1.0f);                                // Depth Buffer Setup
        gl.glDepthFunc(GL.GL_LEQUAL);  // The Type Of Depth Testing (Less Or Equal)
        gl.glEnable(GL.GL_DEPTH_TEST);                        // Enable Depth Testing
        gl.glShadeModel(GL.GL_FLAT);   // Select Flat Shading (Nice Definition Of Objects)
        
        // Set Perspective Calculations To Most Accurate
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);                

        quadratic = glu.gluNewQuadric()// Create A Pointer To The Quadric Object
        glu.gluQuadricNormals(quadratic, GLU.GLU_SMOOTH)// Create Smooth Normals
        glu.gluQuadricTexture(quadratic, true)// Create Texture Coords

        gl.glEnable(GL.GL_LIGHT0);     // Enable Default Light
        gl.glEnable(GL.GL_LIGHTING);   // Enable Lighting

        gl.glEnable(GL.GL_COLOR_MATERIAL);  // Enable Color Material
    }

    void reset() {
        synchronized(matrixLock) {
            LastRot.setIdentity();   // Reset Rotation
            ThisRot.setIdentity();   // Reset Rotation
        }
    }

    void startDragPoint MousePt ) {
        synchronized(matrixLock) {
            LastRot.setThisRot );  // Set Last Static Rotation To Last Dynamic One
        }
        arcBall.clickMousePt );    // Update Start Vector And Prepare For Dragging
    }

    void dragPoint MousePt )       // Perform Motion Updates Here
    {
        Quat4f ThisQuat = new Quat4f();

        // Update End Vector And Get Rotation As Quaternion
        arcBall.dragMousePt, ThisQuat)
        synchronized(matrixLock) {
            ThisRot.setRotation(ThisQuat);  // Convert Quaternion Into Matrix3fT
            ThisRot.mulThisRot, LastRot)// Accumulate Last Rotation Into This One
        }
    }

    void torus(GL gl, float MinorRadius, float MajorRadius// Draw A Torus With Normals
    {
        int i, j;
        gl.glBegin(GL.GL_TRIANGLE_STRIP)// Start A Triangle Strip
        for (i = 0; i < 20; i++)          // Stacks
        {
            for (j = -1; j < 20; j++)     // Slices
            {
                float wrapFrac = (j % 20(float20;
                double phi = Math.PI * 2.0 * wrapFrac;
                float sinphi = (float) (Math.sin(phi));
                float cosphi = (float) (Math.cos(phi));

                float r = MajorRadius + MinorRadius * cosphi;

                gl.glNormal3d(
                        (Math.sin(Math.PI * 2.0 (i % 20 + wrapFrac
                        (float20)) * cosphi,
                        sinphi,
                        (Math.cos(Math.PI * 2.0 (i % 20 + wrapFrac
                        (float20)) * cosphi);
                gl.glVertex3d(
                        (Math.sin(Math.PI * 2.0 (i % 20 + wrapFrac
                        (float20)) * r,
                        MinorRadius * sinphi,
                        (Math.cos(Math.PI * 2.0 (i % 20 + wrapFrac
                        (float20)) * r);

                gl.glNormal3d(
                        (Math.sin(Math.PI * 2.0 (i + 20 + wrapFrac
                        (float20)) * cosphi,
                        sinphi,
                        (Math.cos(Math.PI * 2.0 (i + 20 + wrapFrac
                        (float20)) * cosphi);
                gl.glVertex3d(
                        (Math.sin(Math.PI * 2.0 (i + 20 + wrapFrac
                        (float20)) * r,
                        MinorRadius * sinphi,
                        (Math.cos(Math.PI * 2.0 (i + 20 + wrapFrac
                        (float20)) * r);
            }
        }
        gl.glEnd();  // Done Torus
    }

    public void display(GLAutoDrawable drawable) {
        synchronized(matrixLock) {
            ThisRot.get(matrix);
        }

        GL gl = drawable.getGL();

        // Clear Screen And Depth Buffer
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);                
        gl.glLoadIdentity();                  // Reset The Current Modelview Matrix
        
        // Move Left 1.5 Units And Into The Screen 6.0
        gl.glTranslatef(-1.5f0.0f, -6.0f);  

        gl.glPushMatrix();                  // NEW: Prepare Dynamic Transform
        gl.glMultMatrixf(matrix, 0);        // NEW: Apply Dynamic Transform
        gl.glColor3f(0.75f0.75f1.0f);
        torus(gl, 0.30f1.00f);
        gl.glPopMatrix();                   // NEW: Unapply Dynamic Transform

        gl.glLoadIdentity();                // Reset The Current Modelview Matrix
        
        // Move Right 1.5 Units And Into The Screen 7.0
        gl.glTranslatef(1.5f0.0f, -6.0f);  

        gl.glPushMatrix();                  // NEW: Prepare Dynamic Transform
        gl.glMultMatrixf(matrix, 0);        // NEW: Apply Dynamic Transform
        gl.glColor3f(1.0f0.75f0.75f);
        glu.gluSphere(quadratic, 1.3f2020);
        gl.glPopMatrix();                   // NEW: Unapply Dynamic Transform

        gl.glFlush();                       // Flush The GL Rendering Pipeline
    }
}

 Related Tips

 
< Prev   Next >

Page 1 of 0 ( 0 comments )

You can share your information about this topic using the form below!

Please do not post your questions with this form! Thanks.


Name (required)


E-Mail (required)

Your email will not be displayed on the site - only to our administrator
Homepage(optional)



Comment Enable HTML code : Yes No



 
       
         
     
 
 
 
   
 
 
java bottom left
java bottom middle
java bottom right
RSS 0.91 FeedRSS 1.0 FeedRSS 2.0 FeedATOM FeedOPML Feed

Home - About Us - Privacy Policy
Copyright 2005 - 2008 www.java-tips.org
Java is a trademark of Sun Microsystems, Inc.