VPython中控制场景的类为canvas,参考见官网网址:
https://www.glowscript.org/docs/VPythonDocs/canvas.html
常用选项
场景创建与设置大小、颜色
场景大小和颜色可以在创建canvas对象时设置,width参数设置场景宽度,height参数设置场景高度,background参数设置背景颜色,title参数为窗口的名称,显示在浏览器内容窗口左上角。以下创建一个场景scene1,宽1200,高700,背景白色,如图1。
scene1=canvas(title='No.1',width=1200,height=700,background=vec(1,1,1))
图1
场景中心
center属性控制场景开始时,视口中心的位置,显示画面中心平移至center位置处。
例如
scene1=canvas(title='No.1',center=vector(1,4,8))
或
scene1=canvas(title='No.1')
scene1.center=vector(1,4,8)
截屏
Scene1.capture(“filename”)可将屏幕画面保存到文件filename.png中,注意截取画面内容的时机。
显示文字
title属性可设置显示在图形窗口左上方的文字,可以显示多行文字,可显示Html文本。
title="Now \n <b>click the box</b>."
显示如图2。
图2
控制显示窗口
控制显口(View)的属性有range、center、forward、fov、camera.pos
定义见图3。
图3
测试各属性
以下代码按下P键后输出range、center、forward、fov、camera.pos的值,可观察不同动作影响的数据。鼠标滚轮缩放改变camera.pos的值;Ctrl+鼠标左键旋转场景,改变forward值;Shift+鼠标左键移动场景,改变center和camera.pos的值。以上操作fov不会改变。
while True:
ev=scene1.waitfor('keyup')
if ev.event=='keyup':
if ev.key=='p':
print("fov:"+str(scene1.fov))
print("camera.pos:"+str(scene1.camera.pos))
print("center:"+str(scene1.center))
print("forward:"+str(scene1.forward))
print("range:"+str(scene1.range))
print("======")
控制策略
经测试,不要设置camera.pos,camera.pos设置后,center会自动改变,导致看不到模型;
在程序中控制视口需要先设置center、forward,设置range控制远近,camera.pos会自动设置到使模型可见,以上设置过程fov不变。
fov越大,近大远小的透视效果越明显,fov默认设置为60度。
以下代码改变range可改变可视范围,相当于缩放。
scene1.center=vector(0,0,0)
scene1.forward=vector(-0.5,-0.5,-0.5)
scene1.range=5000
range=10000与range=5000如图4。
图4
使用摄像机控制窗口
控制摄像机的属性见下图。
视口跟踪目标
scene.camera.follow(aa) #视口跟随飞机
scene.camera.follow函数简化了视口跟随模型的代码,否则需要获取模型当前位置并赋值给scene.camera.pos。视口跟随模型后,scence.forward控制视口相对模型的角度。
视口角度控制
以下使视口从上方斜向下指向飞机
scene1.forward = scene1.forward.rotate(angle=-PI / 6, axis=vec(1, 0, 0)) #绕x轴转30度
scene1.forward = scene1.forward.rotate(angle=PI / 4, axis=vec(0, 1, 0)) #绕y轴转45度
摄像机上方向
scene.up=vector(1,0,0) #指定视口的上方向的指向
示例
视口跟随模型的动画如下。
视口跟随飞机
代码
飞行.py
# -*- coding: utf-8 -*-
import pandas as pd
from vpython import *
from VPython_Lib import *
PI=3.1415926
scene1 = canvas(title="视口跟随目标", width=600, height=500, background=vec(1,1,1))
scene1.center=vector(0,0,0)
scene1.range=5000
scene1.autoscale = False
scene1.camera.pos=vector(6000,6000,6000)
#飞机飞行
def Flying(target):
#k=1
#移动目标
m=1000 #m为单位米
i=0
kk=3.14*2/250 #飞机绕圆心转动每帧角度增量
target.pos.y = 3*m #固定飞行高度50米
target.rotate(angle=-30*3.14/180,axis=vec(1,0,0)) #飞机倾斜30度
while True:
rate(25) #每秒25帧
ang=i*kk #飞行绕圆心角度
target.pos.x = 3*m*sin(ang)
target.pos.z = 3*m*cos(ang)
target.rotate(angle=kk,axis=vec(0,1,0)) #飞机绕Y轴转动
i += 1
#print(str(scene1.camera.pos)+" "+str(scene1.center))
'''if k==1:
scene1.capture("123") #截屏到文件123.png
k=0'''
def main():
#画坐标系
Coord_Sys(5000,50,100)
#生成飞机
aa=FileToModel('plane1.stl',makeComp=True,tail=True,model_color=vec(1,1,0))
#视口跟踪目标
scene1.camera.follow(aa)
scene1.forward = scene1.forward.rotate(angle=-PI / 6, axis=vec(1, 0, 0))
scene1.forward = scene1.forward.rotate(angle=PI / 4, axis=vec(0, 1, 0))
scene1.up=vector(0,1,0)
#飞机飞行
Flying(aa)
#以下测试控制视口属性
'''while True:
ev=scene1.waitfor('keyup')
if ev.event=='keyup':
if ev.key=='p':
print("fov:"+str(scene1.fov))
print("camera.pos:"+str(scene1.camera.pos))
print("center:"+str(scene1.center))
print("forward:"+str(scene1.forward))
print("range:"+str(scene1.range))
print("======")'''
if __name__ == '__main__':
main()
VPython_Lib.py为导入STL模型和创建直角坐标系的函数库。
#VPython_Lib.py
#导入STL模型和创建直角坐标系的函数库
# -*- coding: utf-8 -*-
from vpython import *
import numpy
from stl import mesh
#从stl文件中读取数据构建模型
#file:stl文件名
#makeComp:是否构建compound,True输出compound,False输出0
#tail:是否有尾迹
#model_color:模型颜色
def FileToModel(file,makeComp=False,tail=False,model_color=vec(0.5,0.5,0.5)):
temp_mesh = mesh.Mesh.from_file(file) #STL数据读入temp_mesh
tris=[]
num=int(temp_mesh.normals.size/3) #三角面数量
for a in range(num):
aa = temp_mesh.vectors[a][0] #三角面顶点1
bb = temp_mesh.vectors[a][1] #三角面顶点2
cc = temp_mesh.vectors[a][2] #三角面顶点3
nn = temp_mesh.normals[a] #三角面方向向量
#建立三角形三个顶点,normal顶点方向向量,colord顶点颜色
p=vector(0,0,0)
a = vertex(pos=vector(aa[0], aa[1], aa[2])+p,normal=vector(nn[0], nn[1], nn[2]),color=model_color)
b = vertex(pos=vector(bb[0], bb[1], bb[2])+p,normal=vector(nn[0], nn[1], nn[2]),color=model_color)
c = vertex(pos=vector(cc[0], cc[1], cc[2])+p,normal=vector(nn[0], nn[1], nn[2]),color=model_color)
t=triangle(v0=a,v1=b,v2=c) #由三个顶点生成三角面
tris.append(t) #三角面数组
if makeComp==True:
tt=compound(tris,make_trail=tail) #将三角面组成组件
return tt
return 0
#构建坐标系/
#axis_lenth:坐标轴长度
#axis_rad:坐标轴直径
#cone_rad:坐标箭头直径
def Coord_Sys(axis_len=100,axis_radius=1,cone_radius=1):
cone_len = 3*cone_radius
x_axis_line = cylinder(pos=vector(0, 0, 0), axis=vec(axis_len, 0, 0), radius=axis_radius)
x_axis_line.color = vector(255, 0, 0)
x_axis_cone = cone(pos=vector(axis_len, 0, 0), axis=vec(cone_len, 0, 0), radius=cone_radius)
x_axis_cone.color = vector(255, 0, 0)
# y轴线和箭头
y_axis_line = cylinder(pos=vector(0, 0, 0), axis=vec(0, axis_len, 0), radius=axis_radius)
y_axis_line.color = vector(0, 255, 0)
y_axis_cone = cone(pos=vector(0, axis_len, 0), axis=vec(0, cone_len, 0), radius=cone_radius)
y_axis_cone.color = vector(0, 255, 0)
# z轴线和箭头
z_axis_line = cylinder(pos=vector(0, 0, 0), axis=vec(0, 0, axis_len), radius=axis_radius)
z_axis_line.color = vector(0, 0, 255)
z_axis_cone = cone(pos=vector(0, 0, axis_len), axis=vec(0, 0, cone_len), radius=cone_radius)
z_axis_cone.color = vector(0, 0, 255)