关于opengl模型坐标转变为最终屏幕坐标

参考: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最终是转化到以左下角为原点的窗口坐标系,如果实际窗口坐标系原点在左上角,还进行一步转换罢了!

个人理解,欢迎指正!

展开阅读全文

没有更多推荐了,返回首页