Browse Source

new:Simple3DCamera(ToBeDone)

master
kdxcxs 5 years ago
parent
commit
7f51a28f34
  1. 29
      README.md
  2. BIN
      assets/Simple3DCamera.gif
  3. 172
      src/python/Simple3DCamera.py

29
README.md

@ -1,7 +1,7 @@
# PlayWith3D # PlayWith3D
A project about [my](cx@kdxcxs.com) 3D exploring journey A project about [my](cx@kdxcxs.com) 3D exploring journey
## projects ## Projects
### First Cube ### First Cube
@ -13,6 +13,11 @@ prototype:
![FirstCubePrototype](assets/FirstCubePrototype.jpg) ![FirstCubePrototype](assets/FirstCubePrototype.jpg)
src:
1. [python](src/python/First_Cube.py)
2. [js](src/js/First_Cube.html)
### Cube Without Perspective ### Cube Without Perspective
Simply fill the two faces nearer to the camera. Simply fill the two faces nearer to the camera.
@ -23,4 +28,24 @@ preview:
prototype: prototype:
![CubeWithoutPerspectivePrototype](assets/CubeWithoutPerspectivePrototype.jpg) ![CubeWithoutPerspectivePrototype](assets/CubeWithoutPerspectivePrototype.jpg)
src:
1. [python](src/python/CubeWithoutPerspective.py)
### Simple 3D Camera
To be done.
I have to prepare for the college entrance examination😥
preview for functional parts:
![Simple3DCameraPreview](assets/Simple3DCamera.gif)
Check the TODO list in [Simple3DCamera.py](src/python/Simple3DCamera.py) for more information.
src:
1. [python](src/python/Simple3DCamera.py)

BIN
assets/Simple3DCamera.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

172
src/python/Simple3DCamera.py

@ -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…
Cancel
Save