kdxcxs
5 years ago
3 changed files with 199 additions and 2 deletions
After Width: | Height: | Size: 183 KiB |
@ -0,0 +1,172 @@ |
|||
# coding:utf-8 |
|||
|
|||
# TODO: |
|||
# 0.Debug┑( ̄Д  ̄)┍ |
|||
# 1.物体有部分在相对相机X负半轴的情况(TkRender.run中) |
|||
# 2.object增加 棱 属性,渲染时作出棱就行了,相应改变render |
|||
# 3.搞懂成像原理,缩放后放大多少(Camera.scale) |
|||
# 4.实现perspective开关 |
|||
# 5.相机的旋转只做了Z的旋转(应该是成功了吧……)我现在的想法是记录旋转的顺时针弧度数 |
|||
# 然后计算另外两个轴的新坐标,一个轴一个轴地转.从旋转轴的正半轴朝原点看,另外两个轴的方向 |
|||
# 分别向右,向上,以向上轴为0°记录顺时针弧度数 |
|||
# 6.Tk canvas的Y轴向下为正方向,尝试转换 |
|||
|
|||
from tkinter import Tk, Canvas |
|||
import math, threading, time |
|||
|
|||
|
|||
class Camera(object): |
|||
def __init__(self, position=[0, 0, 0], rotating=[0, 0, 0]): |
|||
self.position = position # coordinates in x,y and z |
|||
self.focus = 0.8 # 焦距 |
|||
self.scale = 200 |
|||
self.rotating = rotating # 用于确定相机朝向,x,y和z轴的顺时针旋转角度,参考blender设定 |
|||
|
|||
def moveTo(self, pst): |
|||
self.position = pst |
|||
|
|||
|
|||
class Scen(object): |
|||
def __init__(self): |
|||
self.objects = [] |
|||
|
|||
def addObjects(self, objs): |
|||
self.objects += objs |
|||
|
|||
|
|||
class TkRender(object): # including render and screen(a canvas) |
|||
def __init__(self, cam, scen, dgb=False): |
|||
self.cam: Camera = cam # camera |
|||
self.pits = [] # points in 2d e.g. [[[1,1],[2,2]],[[3,3],[4,4]]] => [object,object] object => [point,point] |
|||
self.perspective = True # 是否透视 |
|||
self.size = [800, 600] # screen size |
|||
self.offset = [self.size[0] / 2, self.size[1] / 2] # 让画面中心在窗口中心 |
|||
self.scen: Scen = scen |
|||
self.debug = dgb # debug mode |
|||
self.fps = 60 |
|||
self.st = 1 / self.fps # sleep time |
|||
self.runThread = threading.Thread(target=self.run) |
|||
self.tkroot = Tk() |
|||
self.cvs = [Canvas(self.tkroot, bg='white', width=800, height=600), # canvas |
|||
Canvas(self.tkroot, bg='white', width=800, height=600)] |
|||
self.cvs[0].pack() |
|||
self.showingCv = 0 |
|||
self.hiddenCv = 1 |
|||
self.running = False |
|||
|
|||
def run(self): |
|||
angle = 0 |
|||
while self.running: |
|||
angle += apf |
|||
rotateCamera(self, angle) |
|||
self.cvs[self.hiddenCv].delete('all') |
|||
for ob in self.scen.objects: |
|||
pit = [] # points in 2d |
|||
for tpt in ob.points: # tpt:3D point |
|||
rc = [] # relative coordinate相对坐标 |
|||
ra = 0 # relative angle点在旋转平面相对相机正方向顺时针旋转角度 |
|||
dis = 0 # 点到相机的距离 |
|||
for i in range(3): |
|||
rc.append(tpt[i] + ob.center[i] - self.cam.position[i]) |
|||
# 先只转动X轴,暂时想不出什么转相机的好方法(就是没想出来┑( ̄Д  ̄)┍) |
|||
# for ras, aas in [[0, [1, 2]], # rotating axis,anfected axises |
|||
# [1, [0, 2]], # 处理相机旋转,rc更新为相机旋转后轴的相对坐标 |
|||
# [2, [0, 1]]]: # 旋转一个轴,影响其他两个轴 |
|||
# dis = math.sqrt(rc[aas[0]] ** 2 + rc[aas[1]] ** 2) # 在旋转平面上点与相机间距离 |
|||
# ra = math.acos(rc[0] / dis) + self.cam.rotating[ras] |
|||
# if ras == 2: # Y轴与X或Z的旋转不同,画个图看看就知道了(大概) |
|||
# rc[0] = - dis * math.sin(ra) |
|||
# rc[2] = dis * math.cos(ra) |
|||
# else: |
|||
# rc[aas[0]] = dis * math.sin(ra) |
|||
# rc[aas[1]] = dis * math.cos(ra) |
|||
# # rc += [0,0,0] # 为了保证计算相对屏幕坐标时旋转前坐标不改变,新坐标用后三位,前三位在计算完成后去除 |
|||
# # for era in range(3): # each relative angle一个轴一个轴的转 |
|||
# # rc[] |
|||
dis = math.sqrt(rc[0] ** 2 + rc[1] ** 2) |
|||
if rc[0] > 0 and rc[1] > 0: # 第一象限 |
|||
ra = math.asin(rc[0] / dis) |
|||
elif rc[0] > 0 and rc[1] < 0: |
|||
ra = math.pi - math.asin(rc[0] / dis) |
|||
elif rc[1] < 0: |
|||
ra = math.asin(-rc[0] / dis) + math.pi |
|||
else: |
|||
ra = math.pi - math.asin(- rc[0] / dis) |
|||
rc[0] = dis * math.sin(ra - self.cam.rotating[2]) |
|||
rc[1] = dis * math.cos(ra - self.cam.rotating[2]) |
|||
# Z轴转完了 |
|||
rate = self.cam.focus / rc[1] # 根据焦距和点离相机垂直距离确定转2d的缩放比例 |
|||
pit.append([rc[0] * rate * self.cam.scale, - rc[2] * rate * self.cam.scale]) # *(-1):cvsY轴是倒置的 |
|||
for i in range(len(pit)): # 让画面中心在窗口中心 |
|||
pit[i] = [pit[i][0] + self.offset[0], pit[i][1] + self.offset[1]] |
|||
for dcp, nps in [[1, [0, 3, 5]], # drawing central point |
|||
[2, [0, 3, 6]], # 以1,2,4,7四个点为中心,分别连接相邻的三个点即可绘成正方体 |
|||
[4, [0, 5, 6]], |
|||
[7, [3, 5, 6]]]: |
|||
for np in nps: # nearby point |
|||
self.cvs[self.hiddenCv].create_line(pit[dcp][0], pit[dcp][1], |
|||
pit[np][0], pit[np][1]) |
|||
if self.debug: |
|||
self.cvs[self.hiddenCv].create_text(pit[dcp][0], pit[dcp][1], |
|||
text=str(dcp)) |
|||
# text=str(ob.center[0])) |
|||
self.cvs[self.hiddenCv].create_text(pit[np][0], pit[np][1], |
|||
text=str(np)) |
|||
# text=str(ob.center[0])) |
|||
if self.debug: |
|||
self.cvs[self.hiddenCv].create_text(self.cam.position[0] * 50 + 400, - self.cam.position[1] * 50 + 300, |
|||
text='C') |
|||
self.cvs[self.hiddenCv].create_text(400, 300, text='O') |
|||
self.cvs[self.hiddenCv].create_line(self.cam.position[0] * 50 + 400, -self.cam.position[1] * 50 + 300, |
|||
self.cam.position[0] * 50 + 400 + 20 * math.sin( |
|||
self.cam.rotating[2]), |
|||
-self.cam.position[1] * 50 + 300 - 20 * math.cos( |
|||
self.cam.rotating[2])) |
|||
# 切换canvas |
|||
self.cvs[self.showingCv].pack_forget() |
|||
self.cvs[self.hiddenCv].pack() |
|||
self.showingCv, self.hiddenCv = self.hiddenCv, self.showingCv |
|||
self.cvs[self.hiddenCv].delete('all') |
|||
time.sleep(self.st) |
|||
|
|||
def start(self): |
|||
self.running = True |
|||
self.runThread.start() |
|||
self.tkroot.mainloop() |
|||
|
|||
|
|||
class TDObject(object): # 3D object |
|||
def __init__(self, centerpoint=[0, 0, 0], points=None): |
|||
self.center = centerpoint # coordinates in three axises e.g. [0,0,0] |
|||
self.points = [] # 物体每个点对于center point的相对坐标 |
|||
self.setPoints(points) |
|||
|
|||
def setPoints(self, points): # points e.g. [[1,1,1],[2,2,2]] |
|||
self.points += points |
|||
|
|||
|
|||
# 主体结束,下面开始测试 |
|||
|
|||
def rotateCamera(rd: TkRender, angle): |
|||
angle += apf |
|||
if angle > 2 * math.pi: |
|||
angle -= 2 * math.pi |
|||
rd.cam.rotating[2] = -angle |
|||
rd.cam.position[0] = 6 * math.sin(angle) |
|||
rd.cam.position[1] = -6 * math.cos(angle) |
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
ca = Camera(position=[0, 0, 0]) |
|||
sc = Scen() |
|||
rd = TkRender(ca, sc, True) |
|||
# c1 = TDObject([0, 0, 0], |
|||
# [[-1, 1, -1], [1, 1, -1], [-1, -1, -1], [1, -1, -1], [-1, 1, 1], [1, 1, 1], [-1, -1, 1], [1, -1, 1]]) |
|||
# sc.addObjects([c1]) # cube1,cube2 |
|||
c1 = TDObject([2, 2, 2], |
|||
[[-1, 1, -1], [1, 1, -1], [-1, -1, -1], [1, -1, -1], [-1, 1, 1], [1, 1, 1], [-1, -1, 1], [1, -1, 1]]) |
|||
c2 = TDObject([-2, -2, 0], |
|||
[[-1, 1, -1], [1, 1, -1], [-1, -1, -1], [1, -1, -1], [-1, 1, 1], [1, 1, 1], [-1, -1, 1], [1, -1, 1]]) |
|||
sc.addObjects([c1, c2]) # cube1,cube2 |
|||
apf = math.pi / 60 |
|||
rd.start() |
Loading…
Reference in new issue