参考:https://zhidao.baidu.com/question/560324903.html
比如如果你设置各个变换的代码是 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslate3f(0, 0, 100); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glViewport(100, 100, 400, 400); 那么ModelView矩阵是一个平移(前三行代码)(OpenGL里model变换和view变换用同一个矩阵表示,可以理解为这两个矩阵已经乘在一起了): 1 0 0 0 0 1 0 0 0 0 1 100 0 0 0 1 Projection矩阵就是单位矩阵(中间两行代码): 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 最后一行设置viewport变换,把(-1, -1)到(1, 1)这个矩形映射到(100, 100)到(500, 500),相当于缩放200倍后平移(+300, +300)。 施加变换的过程如下:先把(100, 100, 100)变成四维向量(补上w分量,成为齐次坐标),变成(100, 100, 100, 1),然后把第一个矩阵左乘到这个向量上,得到(100, 100, 200, 1),然后再把第二个矩阵左城到这个新向量上,得到的仍是(100, 100, 200, 1),再把它转化回三维向量,方法是所有分量都除以w分量1,所以得到(100, 100, 200)。最后取xy分量(100, 100),进行最后一个变换(viewport),放大200倍后平移(+300, +300),变成(20300, 20300)。这就是屏幕上的坐标。当然这个位置肯定是在屏幕能显示的区域之外了。实际上进行viewport变换之前,因为xy分量是(100, 100)已经超出(-1, -1)到(1, 1)的范围,所以在这一步就已经可以确定这个像素不用画了,肯定在屏幕之外。
下面给出个人测试代码
为了简单起见,模型视图,投影都取单位阵吧,直接进行视口变换
import javax.swing.JFrame;
import com.jogamp.newt.Window;
import com.jogamp.newt.event.MouseAdapter;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
import com.jogamp.newt.event.awt.AWTMouseAdapter;
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.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
public class TestScreenCoordinate implements GLEventListener{
private GLU glu = new GLU();
@Override
public void init(GLAutoDrawable drawable) {
// TODO Auto-generated method stub
MouseListener tennisMouse = new MyMouseAdapter();
if (drawable instanceof Window) {
Window window = (Window) drawable;
window.addMouseListener(tennisMouse);
} else if (GLProfile.isAWTAvailable() && drawable instanceof java.awt.Component) {
java.awt.Component comp = (java.awt.Component) drawable;
new AWTMouseAdapter(tennisMouse, drawable).addTo(comp);
}
//set up state
GL2 gl = drawable.getGL().getGL2();
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
/* gl.glTranslatef(0, 0, 0);*/
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
}
@Override
public void dispose(GLAutoDrawable drawable) {
// TODO Auto-generated method stub
}
@Override
public void display(GLAutoDrawable drawable) {
// TODO Auto-generated method stub
GL2 gl = drawable.getGL().getGL2();
gl.glBegin(GL2.GL_LINES);
gl.glColor3f(255, 0, 0);
gl.glVertex3f(0f,0f, 0f);
gl.glVertex3f(0.5f, 0.5f, 0f);
gl.glEnd();
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
// TODO Auto-generated method stub
final GL2 gl = drawable.getGL().getGL2();
// get the OpenGL 2 graphics object
if(height <=0)
height =1;
//preventing devided by 0 exception height =1;
final float h = (float) width / (float) height;
// display area to cover the entire window
gl.glViewport(0, 0, 200, 200);
//transforming projection matrix
/* gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0f, h, 1.0, 20.0);
//transforming model view gl.glLoadIdentity();
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();*/
}
class MyMouseAdapter extends MouseAdapter{
public void mousePressed(MouseEvent e){
}
public void mouseReleased(MouseEvent e) {
}
public void mouseDragged(MouseEvent e){
}
public void mouseClicked(MouseEvent e){
System.out.println("PointX:"+e.getX()+"PointY:"+e.getY());
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
final GLProfile profile = GLProfile.get( GLProfile.GL2 );
GLCapabilities capabilities = new GLCapabilities( profile );
// The canvas
final GLCanvas glcanvas = new GLCanvas( capabilities );
TestScreenCoordinate test = new TestScreenCoordinate();
glcanvas.addGLEventListener( test );
glcanvas.setSize( 400, 400 );
//creating frame
final JFrame frame = new JFrame ( "TestScreenCoordinate" );
//adding canvas to it
frame.getContentPane().add( glcanvas );
frame.setSize( frame.getContentPane().getPreferredSize() );
frame.setVisible( true );
//Instantiating and Initiating Animator
final FPSAnimator animator = new FPSAnimator( glcanvas, 300,true );
//animator.start();
}
}
结果应该是
窗口坐标系的原点应该在左下角,不过鼠标获取的坐标是左上角为原点,此结果是窗口坐标系原点在左下角的效果!
只能说,opengl最终是转化到以左下角为原点的窗口坐标系,如果实际窗口坐标系原点在左上角,还进行一步转换罢了!
个人理解,欢迎指正!