我正在尝试使用OpenGL移动和旋转球体。为此,我保存我的矩阵状态,我加载单位矩阵,然后我转换到我想要的点,最后,我旋转并推送状态,如上面的代码所示。因为这些过程是从结束到开始完成的,所以旋转是从(0,0,0)开始,只有在此之后,它才会移动到所需的点。翻译很好,但我有旋转问题。为此,我想用2个角度来描述旋转:theta和phi(只需按照你在这里看到的物理惯例https://en.wikipedia.org/wiki/Spherical_coordinate_system)。如果我首先在phi中旋转然后在theta中,则结果与以相反顺序进行的操作不同。我知道这是因为矩阵产品。此外,我已经读过,使用万向节锁定的欧拉角存在问题,我应该使用四元数但是,我还没有这么清楚。我正在查看我的数据作为正视图,由于上述原因,我不确定我所做的是否正确,或者只是我用我试过的角度运气。你会怎么做?
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
gl.glTranslatef(x, y, z);
gl.glRotatef(theta, 0,1,0);
gl.glRotatef(phi, 0,0,1);
GLUquadric earth = glu.gluNewQuadric();
glu.gluQuadricTexture(earth, true);
glu.gluQuadricDrawStyle(earth, GLU.GLU_FILL);
glu.gluQuadricNormals(earth, GLU.GLU_FLAT);
glu.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE);
glu.gluSphere(earth, radius, slices, stacks);
glu.gluDeleteQuadric(earth);
gl.glPopMatrix();
答案 0 :(得分:1)
我怎么理解,旋转后gl.glRotatef(theta,0,1,0)vector(0,0,1)也改变了。对于您的代码,gl.glRotatef(phi,0,0,1)在对象本地坐标中工作。我想你想在全球范围内做这件事。我想如果你将0,1,0周围的矢量(0,0,1)旋转到θ度,并使用新矢量进行第二次旋转。
这是伪代码示例:
gl.glRotatef(theta, 0,1,0);
glm::mat4 rotationMatrix = glm::rotate(glm::mat4(1.0f), theta, glm::vec3(0.0, 1.0, 0.0));
glm::mat4 rotateVector = rotationMatrix * glm::vec4(0.0, 0.0, 1.0));
gl.glRotatef(phi, rotateVector.x, rotateVector.y, rotateVector.z);
我认为这段代码无法编译。我尝试用glm函数来表示我的意思。
答案 1 :(得分:0)
最后我改变主意,而不是使用ortho,我试图通过使用透视来理解问题。起初,我注意到我的粒子是否旋转了一个额外的角度。但最后,我认为这是因为如何将纹理添加到粒子中。我尝试了几个像这里所说的那样的事情:https://stackoverflow.com/a/7725601/1200914但这是不可能的。在尝试了很多东西后,我尝试画出轴线,经过大量的测试后我发现我忘记了Math.sin和Math.cos是弧度的,而不是像OpenGl那样的度数。当我意识到这一点时,我注意到线条很完美。一切都发生在全球坐标上。简而言之:
gl.glRotatef(theta, 0, 1, 0);
gl.glRotatef(phi, 0, 0, 1);
没问题。我让我的代码让我理解这一点。请将路径更改为“ROUTE TO IMAGE”到png图像,该图像是分为4种不同颜色的正方形(如windows标志)。你可以用油漆来制作。
import java.awt.BorderLayout;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.glu.GLUquadric;
import com.jogamp.opengl.awt.GLCanvas;
import javax.swing.JFrame;
import com.jogamp.opengl.util.FPSAnimator;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureData;
import com.jogamp.opengl.util.texture.TextureIO;
/**
* Test developed using:
*
* A minimal JOGL demo.
*
* @author <a href="mailto:kain@land-of-kain.de">Kai Ruhl</a>
* @since 26 Feb 2009
*/
public class test3d extends GLCanvas implements GLEventListener {
/** Serial version UID. */
private static final long serialVersionUID = 1L;
/** The GL unit (helper class). */
private GLU glu;
/** The frames per second setting. */
private int fps = 24;
/** The OpenGL animator. */
private FPSAnimator animator;
/** The earth texture. */
private Texture earthTexture;
private int see_ = 0;
/**
* A new mini starter.
*/
public test3d(int see) {
addGLEventListener(this);
see_ = see;
}
/**
* Sets up the screen.
*
* @see javax.media.opengl.GLEventListener#init(javax.media.opengl.GLAutoDrawable)
*/
public void init(GLAutoDrawable drawable) {
final GL2 gl = (GL2) drawable.getGL();
// Enable z- (depth) buffer for hidden surface removal.
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
// Enable smooth shading.
gl.glShadeModel(GL2.GL_SMOOTH);
// Define "clear" color.
gl.glClearColor(0f, 0f, 0f, 0f);
// We want a nice perspective.
gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
// Create GLU.
glu = new GLU();
GLProfile profile = GLProfile.get(GLProfile.GL2);
// Load earth texture.
try {
FileInputStream stream = new FileInputStream(ROUTE TO IMAGE);
TextureData data = TextureIO.newTextureData(profile, stream, false, "png");
earthTexture = TextureIO.newTexture(data);
}
catch (IOException exc) {
exc.printStackTrace();
System.exit(1);
}
// Start animator.
animator = new FPSAnimator(this, fps);
animator.start();
}
/**
* The only method that you should implement by yourself.
*
* @see javax.media.opengl.GLEventListener#display(javax.media.opengl.GLAutoDrawable)
*/
public void display(GLAutoDrawable drawable) {
if (!animator.isAnimating()) {
return;
}
final GL2 gl = (GL2) drawable.getGL();
// Clear screen.
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// Set camera.
setCamera(gl, glu, 30);
// Prepare light parameters.
float SHINE_ALL_DIRECTIONS = 1;
float[] lightPos = {0, 0, 0, SHINE_ALL_DIRECTIONS};
float[] lightColorAmbient = {1f, 1f, 1f, 1f};
float[] lightColorSpecular = {1f, 1f, 1f, 1f};
// Set light parameters.
gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, lightPos, 0);
gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_AMBIENT, lightColorAmbient, 0);
gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPECULAR, lightColorSpecular, 0);
// Enable lighting in GL.
gl.glEnable(GL2.GL_LIGHT1);
gl.glEnable(GL2.GL_LIGHTING);
// Set material properties.
float[] rgba = {1f, 0f, 0f};
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
gl.glBegin(gl.GL_LINES); //RED == X
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(10, 0, 0);
gl.glEnd();
rgba[0] = 0f;
rgba[1] = 1f;
rgba[2] = 0f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
gl.glBegin(gl.GL_LINES); //GREEN == Y
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(0, 10, 0);
gl.glEnd();
rgba[0] = 0f;
rgba[1] = 0f;
rgba[2] = 1f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
gl.glBegin(gl.GL_LINES); //BLUE == Z
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(0, 0, 10);
gl.glEnd();
// Set material properties.
float theta = 45f;
float phi = 270f;
/*
////////////////////////////////////////////////////LINES 1 ROT//////////////////////////////////////////////////////////
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
rgba[0] = 1f;
rgba[1] = 0f;
rgba[2] = 1f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
gl.glRotatef(phi, 0, 0, 1);
gl.glBegin(gl.GL_LINES); //VIOLET == X'
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(10, 0, 0);
gl.glEnd();
gl.glPopMatrix();
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
rgba[0] = 1f;
rgba[1] = 1f;
rgba[2] = 0f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
gl.glRotatef(phi, 0, 0, 1);
gl.glBegin(gl.GL_LINES); //YELLOW == Y'
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(0, 10, 0);
gl.glEnd();
gl.glPopMatrix();
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
rgba[0] = 0f;
rgba[1] = 1f;
rgba[2] = 1f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
gl.glRotatef(phi, 0, 0, 1);
gl.glBegin(gl.GL_LINES); //CYAN == Z'
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(0, 0, 10);
gl.glEnd();
gl.glPopMatrix();
*/
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
rgba[0] = 1f;
rgba[1] = 1f;
rgba[2] = 1f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
//gl.glRotatef(theta, (float) Math.sin(phi), (float) Math.cos(phi), 0);
gl.glTranslatef(3, 0, 0);
gl.glRotatef(theta, 0, 1, 0);
gl.glRotatef(phi, 0, 0, 1);
gl.glBegin(gl.GL_LINES); //WHITE == NEW Y'
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(0, 0, 10.f);
gl.glEnd();
gl.glPopMatrix();
////////////////////////////////////////////////////LINES 2 ROT//////////////////////////////////////////////////////////
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
rgba[0] = 1f;
rgba[1] = 0f;
rgba[2] = 1f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
//gl.glRotatef(theta, (float) -Math.sin(phi), (float) Math.cos(phi),0);
//gl.glRotatef(theta, (float) Math.sin(phi*Math.PI/180), (float) Math.cos(phi*Math.PI/180),0);
gl.glRotatef(theta, 0, 1, 0);
gl.glRotatef(phi, 0, 0, 1);
gl.glBegin(gl.GL_LINES); //VIOLET == X'
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(10, 0, 0);
gl.glEnd();
gl.glPopMatrix();
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
rgba[0] = 1f;
rgba[1] = 1f;
rgba[2] = 0f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
//gl.glRotatef(theta, (float) -Math.sin(phi), (float) Math.cos(phi),0);
//gl.glRotatef(theta, (float) Math.sin(phi*Math.PI/180), (float) Math.cos(phi*Math.PI/180),0);
gl.glRotatef(theta, 0, 1, 0);
gl.glRotatef(phi, 0, 0, 1);
gl.glBegin(gl.GL_LINES); //YELLOW == Y'
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(0, 10, 0);
gl.glEnd();
gl.glPopMatrix();
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
rgba[0] = 0f;
rgba[1] = 1f;
rgba[2] = 1f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
//gl.glRotatef(theta, (float) -Math.sin(phi), (float) Math.cos(phi),0);
//gl.glRotatef(theta, (float) Math.sin(phi*Math.PI/180), (float) Math.cos(phi*Math.PI/180),0);
gl.glRotatef(theta, 0, 1, 0);
gl.glRotatef(phi, 0, 0, 1);
gl.glBegin(gl.GL_LINES); //CYAN == Z'
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(0, 0, 10);
gl.glEnd();
gl.glPopMatrix();
//////////////////////////////////////////SPHERES////////////////////////////////////////////
// Apply texture.
rgba[0] = 1f;
rgba[1] = 1f;
rgba[2] = 1f;
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL2.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL2.GL_SHININESS, 1f);
earthTexture.enable(gl);
earthTexture.bind(gl);
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
GLUquadric earth = glu.gluNewQuadric();
glu.gluQuadricTexture(earth, true);
glu.gluQuadricDrawStyle(earth, GLU.GLU_FILL);
glu.gluQuadricNormals(earth, GLU.GLU_FLAT);
glu.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE);
glu.gluSphere(earth, 0.5, 64, 64);
glu.gluDeleteQuadric(earth);
gl.glPopMatrix();
earthTexture.disable(gl);
earthTexture.enable(gl);
earthTexture.bind(gl);
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
gl.glTranslatef(1.5f, 0, 0);
gl.glRotatef(phi, 0,0,1);
GLUquadric earth1 = glu.gluNewQuadric();
glu.gluQuadricTexture(earth1, true);
glu.gluQuadricDrawStyle(earth1, GLU.GLU_FILL);
glu.gluQuadricNormals(earth1, GLU.GLU_FLAT);
glu.gluQuadricOrientation(earth1, GLU.GLU_OUTSIDE);
glu.gluSphere(earth1, 0.5, 64, 64);
glu.gluDeleteQuadric(earth1);
gl.glPopMatrix();
earthTexture.disable(gl);
earthTexture.enable(gl);
earthTexture.bind(gl);
gl.glPushMatrix();
gl.glLoadIdentity(); //I reset the matrix. Now the translation and rotation is from the origin (0,0,0)
gl.glTranslatef(3.f, 0, 0);
gl.glRotatef(theta, 0, 1,0);
gl.glRotatef(phi, 0,0,1);
GLUquadric earth2 = glu.gluNewQuadric();
glu.gluQuadricTexture(earth2, true);
glu.gluQuadricDrawStyle(earth2, GLU.GLU_FILL);
glu.gluQuadricNormals(earth2, GLU.GLU_FLAT);
glu.gluQuadricOrientation(earth2, GLU.GLU_OUTSIDE);
glu.gluSphere(earth2, 0.5, 64, 64);
glu.gluDeleteQuadric(earth2);
gl.glPopMatrix();
earthTexture.disable(gl);
}
/**
* Resizes the screen.
*
* @see javax.media.opengl.GLEventListener#reshape(javax.media.opengl.GLAutoDrawable,
* int, int, int, int)
*/
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
final GL gl = drawable.getGL();
gl.glViewport(0, 0, width, height);
}
/**
* Changing devices is not supported.
*
* @see javax.media.opengl.GLEventListener#displayChanged(javax.media.opengl.GLAutoDrawable,
* boolean, boolean)
*/
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
throw new UnsupportedOperationException("Changing display is not supported.");
}
/**
* @param gl The GL context.
* @param glu The GL unit.
* @param distance The distance from the screen.
*/
private void setCamera(GL2 gl, GLU glu, float distance) {
// Change to projection matrix.
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
// Perspective.
float widthHeightRatio = (float) getWidth() / (float) getHeight();
glu.gluPerspective(45, widthHeightRatio, 1, 10000);
if (see_ == 0){
glu.gluLookAt(10, 10, 10, 0, 0, 0, 0, 0, 1);
}else if (see_ == 1){
glu.gluLookAt(10, 0, 0, 0, 0, 0, 0, 0, 1);
}else if (see_ == 2){
glu.gluLookAt(0, 10, 0, 0, 0, 0, 0, 0, 1);
}else if (see_ == 3){
glu.gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
}
// Change back to model view matrix.
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
}
/**
* Starts the JOGL mini demo.
*
* @param args Command line args.
*/
public final static void main(String[] args) {
GLProfile profile = GLProfile.get(GLProfile.GL2);
GLCapabilities capabilities = new GLCapabilities(profile);
capabilities.setRedBits(8);
capabilities.setBlueBits(8);
capabilities.setGreenBits(8);
capabilities.setAlphaBits(8);
int size = 640;
test3d canvas = new test3d(0);
JFrame frame = new JFrame("Mini JOGL Demo (breed)");
frame.getContentPane().add(canvas, BorderLayout.CENTER);
frame.setBounds(0, 200, size, size);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
test3d canvas2 = new test3d(1);
JFrame frame2 = new JFrame("Mini JOGL Demo (breed)");
frame2.getContentPane().add(canvas2, BorderLayout.CENTER);
frame2.setBounds(0, 200, size, size);
frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame2.setVisible(true);
test3d canvas3 = new test3d(2);
JFrame frame3 = new JFrame("Mini JOGL Demo (breed)");
frame3.getContentPane().add(canvas3, BorderLayout.CENTER);
frame3.setBounds(0, 200, size, size);
frame3.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame3.setVisible(true);
test3d canvas4 = new test3d(3);
JFrame frame4 = new JFrame("Mini JOGL Demo (breed)");
frame4.getContentPane().add(canvas4, BorderLayout.CENTER);
frame4.setBounds(0, 200, size, size);
frame4.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame4.setVisible(true);
}
@Override
public void dispose(GLAutoDrawable drawable) {
// TODO Auto-generated method stub
}
}