博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python>>>创建一个简单的3D场景(2)
阅读量:5272 次
发布时间:2019-06-14

本文共 8739 字,大约阅读时间需要 29 分钟。

使用trackball 来旋转场景

工程文件

效果如下:

当鼠标点击和在窗口移动时,x,y的值以左上角为原点,

首先变换成左下角为原点。然后整个窗口map到【-1,1】,【-1,1】

的平面上。

x  = (x*2.0 - width)/width dx = (2.*dx)/width y  = (y*2.0 - height)/height dy = (2.*dy)/height

trackball 原理,在viewport上“增加”一个半球体,x,y值都和平面上的一样。

从p1移动到p2

计算出移动轴

 

和角度。

 

 

trackball代码

__docformat__ = 'restructuredtext'__version__ = '1.0'import mathimport OpenGL.GL as glfrom OpenGL.GL import GLfloat# Some useful functions on vectors# -----------------------------------------------------------------------------def _v_add(v1, v2):    return [v1[0]+v2[0], v1[1]+v2[1], v1[2]+v2[2]]def _v_sub(v1, v2):    return [v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]]def _v_mul(v, s):    return [v[0]*s, v[1]*s, v[2]*s]def _v_dot(v1, v2):    return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]def _v_cross(v1, v2):    return [(v1[1]*v2[2]) - (v1[2]*v2[1]),            (v1[2]*v2[0]) - (v1[0]*v2[2]),            (v1[0]*v2[1]) - (v1[1]*v2[0])]def _v_length(v):    return math.sqrt(_v_dot(v,v))def _v_normalize(v):    try:                      return _v_mul(v,1.0/_v_length(v))    except ZeroDivisionError: return v# Some useful functions on quaternions# -----------------------------------------------------------------------------def _q_add(q1,q2):    t1 = _v_mul(q1, q2[3])    t2 = _v_mul(q2, q1[3])    t3 = _v_cross(q2, q1)    tf = _v_add(t1, t2)    tf = _v_add(t3, tf)    tf.append(q1[3]*q2[3]-_v_dot(q1,q2))    return tfdef _q_mul(q, s):    return [q[0]*s, q[1]*s, q[2]*s, q[3]*s]def _q_dot(q1, q2):    return q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2] + q1[3]*q2[3]def _q_length(q):    return math.sqrt(_q_dot(q,q))def _q_normalize(q):    try:                      return _q_mul(q,1.0/_q_length(q))    except ZeroDivisionError: return qdef _q_from_axis_angle(v, phi):    q = _v_mul(_v_normalize(v), math.sin(phi/2.0))    q.append(math.cos(phi/2.0))    return qdef _q_rotmatrix(q):    m = [0.0]*16    m[0*4+0] = 1.0 - 2.0*(q[1]*q[1] + q[2]*q[2])    m[0*4+1] = 2.0 * (q[0]*q[1] - q[2]*q[3])    m[0*4+2] = 2.0 * (q[2]*q[0] + q[1]*q[3])    m[0*4+3] = 0.0    m[1*4+0] = 2.0 * (q[0]*q[1] + q[2]*q[3])    m[1*4+1] = 1.0 - 2.0*(q[2]*q[2] + q[0]*q[0])    m[1*4+2] = 2.0 * (q[1]*q[2] - q[0]*q[3])    m[1*4+3] = 0.0    m[2*4+0] = 2.0 * (q[2]*q[0] - q[1]*q[3])    m[2*4+1] = 2.0 * (q[1]*q[2] + q[0]*q[3])    m[2*4+2] = 1.0 - 2.0*(q[1]*q[1] + q[0]*q[0])    m[3*4+3] = 1.0    return mclass Trackball(object):    ''' Virtual trackball for 3D scene viewing. '''    def __init__(self, theta=0, phi=0, zoom=1, distance=3):        ''' Build a new trackball with specified view '''        self._rotation = [0,0,0,1]        self.zoom = zoom        self.distance = distance        self._count = 0        self._matrix=None        self._RENORMCOUNT = 97        self._TRACKBALLSIZE = 0.8        self._set_orientation(theta,phi)        self._x = 0.0        self._y = 0.0    def drag_to (self, x, y, dx, dy):        ''' Move trackball view from x,y to x+dx,y+dy. '''        viewport = gl.glGetIntegerv(gl.GL_VIEWPORT)        width,height = float(viewport[2]), float(viewport[3])        x  = (x*2.0 - width)/width        dx = (2.*dx)/width        y  = (y*2.0 - height)/height        dy = (2.*dy)/height        q = self._rotate(x,y,dx,dy)        self._rotation = _q_add(q,self._rotation)        self._count += 1        if self._count > self._RENORMCOUNT:            self._rotation = _q_normalize(self._rotation)            self._count = 0        m = _q_rotmatrix(self._rotation)        self._matrix = (GLfloat*len(m))(*m)    def zoom_to (self, x, y, dx, dy):        ''' Zoom trackball by a factor dy '''        viewport = gl.glGetIntegerv(gl.GL_VIEWPORT)        height = float(viewport[3])        self.zoom = self.zoom-5*dy/height    def pan_to (self, x, y, dx, dy):        ''' Pan trackball by a factor dx,dy '''        self.x += dx*0.1        self.y += dy*0.1    def push(self):        viewport = gl.glGetIntegerv(gl.GL_VIEWPORT)        gl.glMatrixMode(gl.GL_PROJECTION)        gl.glPushMatrix()        gl.glLoadIdentity ()        aspect = viewport[2]/float(viewport[3])        aperture = 35.0        near = 0.1        far = 100.0        top = math.tan(aperture*3.14159/360.0) * near * self._zoom        bottom = -top        left = aspect * bottom        right = aspect * top        gl.glFrustum (left, right, bottom, top, near, far)        gl.glMatrixMode (gl.GL_MODELVIEW)        gl.glPushMatrix()        gl.glLoadIdentity ()        # gl.glTranslate (0.0, 0, -self._distance)        gl.glTranslate (self._x, self._y, -self._distance)        gl.glMultMatrixf (self._matrix)    def pop(void):        gl.glMatrixMode(gl.GL_MODELVIEW)        gl.glPopMatrix()        gl.glMatrixMode(gl.GL_PROJECTION)        gl.glPopMatrix()    def _get_matrix(self):        return self._matrix    matrix = property(_get_matrix,                     doc='''Model view matrix transformation (read-only)''')    def _get_zoom(self):        return self._zoom    def _set_zoom(self, zoom):        self._zoom = zoom        if self._zoom < .25: self._zoom = .25        if self._zoom > 10: self._zoom = 10    zoom = property(_get_zoom, _set_zoom,                     doc='''Zoom factor''')    def _get_distance(self):        return self._distance    def _set_distance(self, distance):        self._distance = distance        if self._distance < 1: self._distance= 1    distance = property(_get_distance, _set_distance,                        doc='''Scene distance from point of view''')    def _get_theta(self):        self._theta, self._phi = self._get_orientation()        return self._theta    def _set_theta(self, theta):        self._set_orientation(math.fmod(theta,360.0),                              math.fmod(self._phi,360.0))    theta = property(_get_theta, _set_theta,                     doc='''Angle (in degrees) around the z axis''')    def _get_phi(self):        self._theta, self._phi = self._get_orientation()        return self._phi    def _set_phi(self, phi):        self._set_orientation(math.fmod(self._theta,360.),                              math.fmod(phi,360.0))    phi = property(_get_phi, _set_phi,                     doc='''Angle around x axis''')    def _get_orientation(self):        ''' Return current computed orientation (theta,phi). '''         q0,q1,q2,q3 = self._rotation        ax = math.atan(2*(q0*q1+q2*q3)/(1-2*(q1*q1+q2*q2)))*180.0/math.pi        az = math.atan(2*(q0*q3+q1*q2)/(1-2*(q2*q2+q3*q3)))*180.0/math.pi        return -az,ax    def _set_orientation(self, theta, phi):        ''' Computes rotation corresponding to theta and phi. '''         self._theta = theta        self._phi = phi        angle = self._theta*(math.pi/180.0)        sine = math.sin(0.5*angle)        xrot = [1*sine, 0, 0, math.cos(0.5*angle)]        angle = self._phi*(math.pi/180.0)        sine = math.sin(0.5*angle);        zrot = [0, 0, sine, math.cos(0.5*angle)]        self._rotation = _q_add(xrot, zrot)        m = _q_rotmatrix(self._rotation)        self._matrix = (GLfloat*len(m))(*m)    def _project(self, r, x, y):        ''' Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet            if we are away from the center of the sphere.        '''        d = math.sqrt(x*x + y*y)        if (d < r * 0.70710678118654752440):    # Inside sphere            z = math.sqrt(r*r - d*d)        else:                                   # On hyperbola            t = r / 1.41421356237309504880            z = t*t / d        return z    def _rotate(self, x, y, dx, dy):         ''' Simulate a track-ball.            Project the points onto the virtual trackball, then figure out the            axis of rotation, which is the cross product of x,y and x+dx,y+dy.            Note: This is a deformed trackball-- this is a trackball in the            center, but is deformed into a hyperbolic sheet of rotation away            from the center.  This particular function was chosen after trying            out several variations.        '''        if not dx and not dy:            return [ 0.0, 0.0, 0.0, 1.0]        last = [x, y,       self._project(self._TRACKBALLSIZE, x, y)]        new  = [x+dx, y+dy, self._project(self._TRACKBALLSIZE, x+dx, y+dy)]        a = _v_cross(new, last)        d = _v_sub(last, new)        t = _v_length(d) / (2.0*self._TRACKBALLSIZE)        if (t > 1.0): t = 1.0        if (t < -1.0): t = -1.0        phi = 2.0 * math.asin(t)        return _q_from_axis_angle(a,phi)    def __str__(self):        phi = str(self.phi)        theta = str(self.theta)        zoom = str(self.zoom)        return 'Trackball(phi=%s,theta=%s,zoom=%s)' % (phi,theta,zoom)    def __repr__(self):        phi = str(self.phi)        theta = str(self.theta)        zoom = str(self.zoom)        return 'Trackball(phi=%s,theta=%s,zoom=%s)' % (phi,theta,zoom)

 

转载于:https://www.cnblogs.com/legion/p/6273565.html

你可能感兴趣的文章
Java 序列化
查看>>
Java 时间处理实例
查看>>
Java 多线程编程
查看>>
Java 数组实例
查看>>
mysql启动过程
查看>>
2017前端面试题总结
查看>>
Http GetPost网络请求
查看>>
SWIFT国际资金清算系统
查看>>
Sping注解:注解和含义
查看>>
站立会议第四天
查看>>
如何快速掌握一门技术
查看>>
利用AMPScript获取Uber用户数据的访问权限
查看>>
vagrant 同时设置多个同步目录
查看>>
python接口自动化28-requests-html爬虫框架
查看>>
生成随机数的模板
查看>>
Mysql 数据库操作
查看>>
转:linux终端常用快捷键
查看>>
UVa 11059 最大乘积
查看>>
数组分割问题求两个子数组的和差值的小
查看>>
composer 报 zlib_decode(): data error
查看>>