-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpyscript-threejs-trees-cylinder.html
155 lines (153 loc) · 5.79 KB
/
pyscript-threejs-trees-cylinder.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<!DOCTYPE html><html><head>
<!--code at: https://github.com/ostad-ai/Miscellaneous-->
<script defer src="https://pyscript.net/alpha/pyscript.min.js"></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js'></script>
</head><body>
<h1 style="color:#20ee84;">Python inside HTML: 2.5D fractal trees with fruits in 3D </h1>
<h3>Code by <i>Hamed Shah-Hosseini</i>, at: https://github.com/ostad-ai/Miscellaneous </h3>
<button style="font-size:18px" id="mybutton" pys-onClick="Run">
Click to draw Tree</button>
<button style="font-size:18px" id="mybutton2" pys-onClick="ClearTrees">
Click to Clear</button>
<button style="font-size:18px" id="mybutton3" pys-onClick="IncreaseY">
UP (A)</button>
<button style="font-size:18px" id="mybutton4" pys-onClick="DecreaseY">
DOWN (D)</button>
<button style="font-size:18px" id="mybutton5" pys-onClick="IncreaseDepth">
FORWARD (W)</button>
<button style="font-size:18px" id="mybutton6" pys-onClick="DecreaseDepth">
BACKWARD (S)</button>
<div id="container"></div>
<py-script>
from js import THREE
from js import window
from pyodide import create_proxy,to_js
import random
from math import pi,sin,cos
#------------------------
container=Element("container").element
renderer = THREE.WebGLRenderer.new()
renderer.setSize( window.innerWidth, window.innerHeight)
#-----------
scene = THREE.Scene.new();
camera =THREE.PerspectiveCamera.new( 75, window.innerWidth / window.innerHeight, 1, 500 )
camera.position.z = 5; camera.position.y=2
#----------
light = THREE.PointLight.new( color="#ffffff",intensity=100 )
light.position.set(0,12,1)
scene.add( light )
#-------------------
loader=THREE.TextureLoader.new()
texture=loader.load('https://raw.githubusercontent.com/ostad-ai/Miscellaneous/main/Media/texture-brick-bright.jpg')
texture.wrapS=THREE.RepeatWrapping
texture.wrapT=THREE.RepeatWrapping
texture.repeat.set(3,3)
texture.needsUpdate=True
#-----
geometry_plane = THREE.PlaneGeometry.new( 200, 200 ,32,32)
material_plane = THREE.MeshStandardMaterial.new(color="#ffff99",side=THREE.DoubleSide )
material_plane.map=texture
plane = THREE.Mesh.new( geometry_plane, material_plane )
plane.position.z=-15
plane.rotation.x=-pi/2.01
scene.add(plane)
#-----------------
scene.background = THREE.Color.new("#ffeeee")
cylinders=[]
def branch(X,Y,bColor,fColor,level):
direction =THREE.Vector3.new().subVectors(Y,X)
arrow = THREE.ArrowHelper.new(direction.clone().normalize(),X,1)
if level==1:
material=THREE.MeshStandardMaterial.new(color=fColor)
geometry=THREE.SphereGeometry.new(.11,10,10)
P=X.clone()
else:
material=THREE.MeshStandardMaterial.new(color=bColor)
geometry = THREE.CylinderGeometry.new( .02*level,.02*level, direction.length(), 4,4 )
P=THREE.Vector3.new().addVectors(X, direction.multiplyScalar(0.5))
geometry.applyQuaternion(arrow.quaternion.clone())
geometry.translate(P.x,P.y,P.z)
cylinder=THREE.Mesh.new( geometry,material)
return cylinder
class Tree:
def __init__(self,level=8,angle=pi/6):
self.width,self.height=window.innerWidth,window.innerHeight
x=random.randint(-int(self.width/90),int(self.width/90)); y=0
self.cp=[x,y]; self.cd=pi/2; self.angle=angle; self.level=level
self.size=1+.002*self.width*random.random(); self.ratio=.7+.1*random.random()
r,g,b=random.randint(20,200),random.randint(40,200),random.randint(20,200)
self.color=f"rgb({r},{g},{b})"
self.colorFruit=f"rgb({200-r},{200-g},{200-b})"
self.z=-random.randint(5,30)
def forward(self,d):
x,y=self.cp
xd,yd=x+d*cos(self.cd),y+d*sin(self.cd)
points=[]
points.append(THREE.Vector3.new(x,y,self.z))
points.append(THREE.Vector3.new(xd,yd,self.z))
#---------
cylinder=branch(points[0],points[1],self.color,self.colorFruit,self.level)
#----------
scene.add(cylinder)
cylinders.append(cylinder)
self.cp=[xd,yd]
def moveTo(self,d):
x,y=self.cp
xd,yd=x+d*cos(self.cd),y+d*sin(self.cd)
self.cp=[xd,yd]
def right(self,teta):
self.cd=(self.cd-teta)%(2*pi)
def left(self,teta):
self.cd=(self.cd+teta)%(2*pi)
def draw(self):
if self.level<=0: return
self.forward(self.size)
self.right(self.angle)
self.size*=self.ratio; self.level-=1
self.draw()
self.left(2*self.angle)
self.draw()
self.right(self.angle)
self.size/=self.ratio; self.level+=1
self.moveTo(-self.size)
def Run(*args,**kwargs):
tree=Tree(); tree.draw()
renderer.render( scene, camera )
def ClearTrees(*args,**kwargs):
for cylinder in cylinders:
scene.remove(cylinder)
cylinder.clear()
renderer.render( scene, camera )
def IncreaseY(*args,**kwargs):
camera.position.y+=.5
if camera.position.y>=10:
camera.position.y=10
renderer.render( scene, camera )
def DecreaseY(*args,**kwargs):
camera.position.y-=.5
if camera.position.y<.5:
camera.position.y=.5
renderer.render( scene, camera )
def IncreaseDepth(*args,**kwargs):
camera.position.z-=.5
if camera.position.z<=-25:
camera.position.z=-25
renderer.render( scene, camera )
def DecreaseDepth(*args,**kwargs):
camera.position.z+=.5
if camera.position.z>=15:
camera.position.z=15
renderer.render( scene, camera )
def handleKeys(event):
keyCode=event.which
if keyCode==87: # key=w
IncreaseDepth(None,None)
if keyCode==83: # key=s
DecreaseDepth(None,None)
if keyCode==65: # key=a
IncreaseY(None,None)
if keyCode==68: # key=d
DecreaseY(None,None)
document.addEventListener('keydown',create_proxy(handleKeys))
container.appendChild(renderer.domElement)
</py-script></body></html>