Boids Simulation { "packages":["numpy"] } Parameter 01 0.0 from pyodide.ffi import create_proxy, to_js from js import window from js import Math from js import THREE from js import Object from js import document import asyncio import js, pyodide scene = THREE.Scene.new() setcolor = "#bbbbbb" scene.background = THREE.Color.new(setcolor) renderer = THREE.WebGLRenderer.new() renderer.antialias = True renderer.setSize(window.innerWidth, window.innerHeight) document.body.appendChild( renderer.domElement ) camera = THREE.PerspectiveCamera.new(75, window.innerWidth / window.innerHeight, 0.1, 1000.0 ) camera.position.set(40,40,45) controls = THREE.OrbitControls.new(camera, renderer.domElement) controls.listenToKeyEvents(window) def window_onsize(event): camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize( window.innerWidth, window.innerHeight ) window.onresize = window_onsize scene.pause = True # ================ Light setting ==================== ambientLight = THREE.AmbientLight.new(0xaaaaaa) scene.add(ambientLight) dirLight = THREE.DirectionalLight.new(0xffffff) dirLight.position.set(1,1,1) dirLight.castSHadow = True scene.add(dirLight) lightBack = THREE.PointLight.new(0x0FFFFF, 1) lightBack.position.set(0, -3, -1) scene.add(lightBack) # ===========Creating Bound Box ============ ## You can modify the size of box boundRange = 25 bound_material = THREE.MeshStandardMaterial.new() bound_material.color = THREE.Color.new(0x444488) bound_material.transparent = True bound_material.opacity = 0.1 edge_material = THREE.LineBasicMaterial.new() edge_material.color = THREE.Color.new(0xfffffff) bound = THREE.Mesh.new(THREE.BoxGeometry.new(boundRange * 2, boundRange * 2, boundRange * 2), bound_material) edges = THREE.LineSegments.new(THREE.EdgesGeometry.new(THREE.BoxGeometry.new(boundRange * 2, boundRange * 2, boundRange * 2)), ) scene.add(bound) scene.add(edges) #===================== CORE ===================== import numpy as np import math boidsP = None boidsV = None boidsN = 0 boidsShapes = [] def create_boids(num): global boidsN, boidsP, boidsV, boidsShapes boidsN = num boidsP = -np.random.rand(num, 3) * (boundRange * 2) + boundRange boidsV = -np.random.rand(num, 3) * 3 + 1.5 for i in range(num): geometry = THREE.CylinderGeometry.new(0.0,0.75,2.25,4,1) material = THREE.MeshPhongMaterial.new() material.color = THREE.Color.new(0x993333) material.flatShading = True boidShape = THREE.Mesh.new(geometry, material) boidsShapes.append(boidShape) scene.add(boidShape) def reset_boids(): global boidsP, boidsV, boidsN, boundRange boidsP = -np.random.rand(boidsN, 3) * (boundRange * 2) + boundRange boidsV = -np.random.rand(boidsN, 3) * 3 + 1.5 def draw_boids(): ## Sync boidData and boidShape global boidsV, boidsShapes for i in range(boidsN): boidsShapes[i].position.set(boidsP[i][0], boidsP[i][1], boidsP[i][2]) ## TODO Update rotation to align the boid heading direction with its velocity ## Hint : boidsShapes[i].setRotationFromAxisAngle(THREE.Vector3.new(axis[0], axis[1], axis[2]), angle) (Find the axis and angle) def update_boids(): global boidsP, boidsV, boidsN ## TODO Implement the velocity update rules ## vel1 = rule1() ## vel2 = rule2() ## vel3 = rule3() ## Dummy (Remove this line) boidsV = -np.random.rand(boidsN, 3) * 2.0 + 1.0 boidsP += boidsV ## + vel1 + vel2 + vel3 ... def run(): scene.pause = not scene.pause def animate(): if not scene.pause: update_boids() draw_boids() renderer.render(scene, camera) ## Example code for slider def slider01_function(event): value = int(Element("Slider01").value) * 0.01 document.getElementById("SliderValue01").innerHTML = str(round(value, 2)) document.getElementById("Slider01").oninput = slider01_function async def main(): boid_num = 50 create_boids(boid_num) draw_boids() while True: animate() await asyncio.sleep(0.0001) asyncio.ensure_future(main())