Spaces:
Running
Running
| <html> | |
| <head> | |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
| <title>The AI Creature</title> | |
| <!-- Babylon.js --> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script> | |
| <script src="https://preview.babylonjs.com/ammo.js"></script> | |
| <script src="https://preview.babylonjs.com/cannon.js"></script> | |
| <script src="https://preview.babylonjs.com/Oimo.js"></script> | |
| <script src="https://preview.babylonjs.com/earcut.min.js"></script> | |
| <script src="https://preview.babylonjs.com/babylon.js"></script> | |
| <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script> | |
| <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script> | |
| <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script> | |
| <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script> | |
| <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script> | |
| <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script> | |
| <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script> | |
| <!-- tf.js --> | |
| <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js"></script> | |
| <script src="agent_sac.js"></script> | |
| <style> | |
| html, body { | |
| overflow: hidden; | |
| width: 100%; | |
| height: 100%; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| #renderCanvas { | |
| width: 100%; | |
| height: 100%; | |
| touch-action: none; | |
| } | |
| #testCanvas0 { | |
| position:absolute; | |
| width: 128px; | |
| height: 128px; | |
| right:600px; | |
| bottom: 0; | |
| } | |
| #testCanvas1 { | |
| position:absolute; | |
| width: 128px; | |
| height: 128px; | |
| right:450px; | |
| bottom: 0; | |
| } | |
| #testCanvas2 { | |
| position:absolute; | |
| width: 128px; | |
| height: 128px; | |
| right: 300px; | |
| bottom: 0; | |
| } | |
| #testCanvas3 { | |
| position: absolute; | |
| width: 128px; | |
| height: 128px; | |
| right: 150px; | |
| bottom: 0; | |
| } | |
| #testCanvas4 { | |
| position: absolute; | |
| width: 128px; | |
| height: 128px; | |
| right: 0px; | |
| bottom: 0; | |
| } | |
| /* #votes { | |
| position: absolute; | |
| border: 1px solid black; | |
| bottom: 200px; | |
| right: 0px; | |
| width: 100px; | |
| height: 150px; | |
| } */ | |
| .vote { | |
| position: absolute; | |
| width: 60px; | |
| height: 60px; | |
| right: 10px; | |
| } | |
| .vote:hover { | |
| cursor: pointer; | |
| } | |
| #like { | |
| bottom: 200px; | |
| } | |
| #dislike { | |
| bottom: 120px; | |
| -webkit-transform: scaleX(-1); | |
| transform: scaleX(-1); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="renderCanvas"></canvas> | |
| <canvas id="testCanvas0"></canvas> | |
| <canvas id="testCanvas1"></canvas> | |
| <canvas id="testCanvas2"></canvas> | |
| <canvas id="testCanvas3"></canvas> | |
| <canvas id="testCanvas4"></canvas> | |
| <!-- <div id="votes"> --> | |
| <div class="vote" id="like"> | |
| <img src="data:image/png;base64,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" alt="like"> | |
| </div> | |
| <div class="vote" id="dislike"> | |
| <img src="data:image/png;base64,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" alt=""> | |
| </div> | |
| <!-- </div> --> | |
| <script> | |
| window.engine = null; | |
| window.scene = null; | |
| window.sceneToRender = null; | |
| const agent = new AgentSac({trainable: false, verbose: false}) | |
| const canvas = document.getElementById("renderCanvas"); | |
| const createDefaultEngine = () => new BABYLON.Engine(canvas, true, { | |
| preserveDrawingBuffer: true, | |
| stencil: true, | |
| disableWebGL2Support: false | |
| }) | |
| window.vote = 0 | |
| document.getElementById("like").addEventListener("click", () => { | |
| // if (!transitions.length) return | |
| window.reward = 1 | |
| // transitions[transitions.length - 1].reward += reward | |
| // globalReward += reward | |
| // console.log('reward like: ', transitions[transitions.length - 1].reward, globalReward) | |
| }) | |
| document.getElementById("dislike").addEventListener("click", () => { | |
| // if (!transitions.length) return | |
| window.reward = -1 | |
| // transitions[transitions.length - 1].reward += reward | |
| // globalReward += reward | |
| // console.log('reward dislike: ', transitions[transitions.length - 1].reward, globalReward) | |
| }) | |
| window.transitions = [] | |
| window.globalReward = 0 | |
| const BINOCULAR = true | |
| const createScene = async () => { | |
| await agent.init() | |
| // This creates a basic Babylon Scene object (non-mesh) | |
| const scene = new BABYLON.Scene(engine); | |
| scene.collisionsEnabled = true | |
| // Environment | |
| const hdrTexture = BABYLON.CubeTexture.CreateFromPrefilteredData("3d/env/environment.dds", scene); | |
| hdrTexture.name = "envTex"; | |
| hdrTexture.gammaSpace = false; | |
| scene.environmentTexture = hdrTexture; | |
| const skybox = BABYLON.MeshBuilder.CreateBox("skyBox", {size:1000.0}, scene); | |
| const skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene); | |
| skyboxMaterial.backFaceCulling = false; | |
| skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("3d/env/skybox", scene); | |
| skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE; | |
| skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0); | |
| skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0); | |
| skybox.material = skyboxMaterial; | |
| //CAMERA | |
| const camera = new BABYLON.ArcRotateCamera("Camera", BABYLON.Tools.ToRadians(-120), BABYLON.Tools.ToRadians(80), 65, new BABYLON.Vector3(0, -15, 0), scene); | |
| camera.attachControl(canvas, true); | |
| camera.lowerRadiusLimit = 10; | |
| camera.upperRadiusLimit = 120; | |
| camera.collisionRadius = new BABYLON.Vector3(2, 2, 2); | |
| camera.checkCollisions = true; | |
| //enable Physics in the scene vector = gravity | |
| scene.enablePhysics(new BABYLON.Vector3(0, 0, 0), new BABYLON.AmmoJSPlugin(false)); | |
| const physicsEngine = scene.getPhysicsEngine() | |
| // physicsEngine.setSubTimeStep(physicsEngine.getTimeStep()/3 * 1000) | |
| physicsEngine.setTimeStep(1 / 60) | |
| physicsEngine.setSubTimeStep(1) | |
| //LIGHTS | |
| const light1 = new BABYLON.PointLight("light1", new BABYLON.Vector3(0, 5,-6), scene); | |
| const light2 = new BABYLON.PointLight("light2", new BABYLON.Vector3(6, 5, 3.5), scene); | |
| const light3 = new BABYLON.DirectionalLight("light3", new BABYLON.Vector3(20, -5, 20), scene); | |
| light1.intensity = 15; | |
| light2.intensity = 5; | |
| engine.displayLoadingUI(); | |
| await Promise.all([ | |
| BABYLON.SceneLoader.AppendAsync("3d/marbleTower.glb"), | |
| BABYLON.SceneLoader.AppendAsync("https://models.babylonjs.com/Marble/marble/marble.gltf") | |
| ]) | |
| scene.getMeshByName("marble").isVisible = false | |
| const tower = scene.getMeshByName("tower"); | |
| tower.setParent(null) | |
| tower.checkCollisions = true; | |
| tower.impostor = new BABYLON.PhysicsImpostor(tower, BABYLON.PhysicsImpostor.MeshImpostor, { | |
| mass: 0, | |
| friction: 1 | |
| }, scene); | |
| tower.material = scene.getMaterialByName("stone") | |
| tower.material.backFaceCulling = false | |
| /* CREATURE */ | |
| const creature = BABYLON.MeshBuilder.CreateSphere("creature", {diameter: 1, segments:32}, scene) | |
| creature.parent = null | |
| creature.setParent(null) | |
| creature.position = new BABYLON.Vector3(0,-5,0) | |
| creature.isPickable = false | |
| const crMat = new BABYLON.StandardMaterial("cr_mat", scene); | |
| crMat.alpha = 0 // for screenshots | |
| creature.material = crMat | |
| creature.impostor = new BABYLON.PhysicsImpostor(creature, BABYLON.PhysicsImpostor.SphereImpostor, { | |
| mass: 1, | |
| friction: 0, | |
| stiffness: 0, | |
| restitution: 0 | |
| }, scene) | |
| BABYLON.ParticleHelper.SnippetUrl = "3d/snippet"; | |
| // Sparks | |
| creature.sparks = await BABYLON.ParticleHelper.CreateFromSnippetAsync("UY098C-3.json", scene, false); | |
| creature.sparks.emitter = creature; | |
| // Core | |
| creature.glow = await BABYLON.ParticleHelper.CreateFromSnippetAsync("EXUQ7M-5.json", scene, false); | |
| creature.glow.emitter = creature; | |
| /* CREATURE's CAMERA */ | |
| const crCameraLeft = new BABYLON.UniversalCamera("cr_camera_l", new BABYLON.Vector3(0, 0, 0), scene) | |
| crCameraLeft.parent = creature | |
| crCameraLeft.position = new BABYLON.Vector3(-0.5, 0, 0)//new BABYLON.Vector3(0, 5, -10) | |
| crCameraLeft.fov = 2 | |
| crCameraLeft.setTarget(new BABYLON.Vector3(-1, 0, 0.6)) | |
| const crCameraRight = new BABYLON.UniversalCamera("cr_camera_r", new BABYLON.Vector3(0, 0, 0), scene) | |
| crCameraRight.parent = creature | |
| crCameraRight.position = new BABYLON.Vector3(0.5, 0, 0)//new BABYLON.Vector3(0, 5, -10) | |
| crCameraRight.fov = 2 | |
| crCameraRight.setTarget(new BABYLON.Vector3(1, 0, 0.6)) | |
| const crCameraLeftPl = BABYLON.MeshBuilder.CreateSphere("crCameraLeftPl", {diameter: 0.1, segments: 32}, scene); | |
| crCameraLeftPl.parent = creature | |
| crCameraLeftPl.position = new BABYLON.Vector3(-0.5, 0, 0) | |
| const crCameraLeftPlclMat = new BABYLON.StandardMaterial("crCameraLeftPlclMat", scene) | |
| crCameraLeftPlclMat.alpha = 0.3 // for screenshots | |
| crCameraLeftPlclMat.diffuseColor = new BABYLON.Color3(0, 0, 0) | |
| crCameraLeftPl.material = crCameraLeftPlclMat | |
| const crCameraRightPl = BABYLON.MeshBuilder.CreateSphere("crCameraRightPl", {diameter: 0.1, segments: 32}, scene); | |
| crCameraRightPl.parent = creature | |
| crCameraRightPl.position = new BABYLON.Vector3(0.5, 0, 0) | |
| const crCameraRightPlclMat = new BABYLON.StandardMaterial("crCameraRightPlclMat", scene) | |
| crCameraRightPlclMat.alpha = 0.3 // for screenshots | |
| crCameraRightPlclMat.diffuseColor = new BABYLON.Color3(0, 0, 0) | |
| crCameraRightPl.material = crCameraRightPlclMat | |
| // crCameraLeft.rotation = new BABYLON.Vector3(0, -(Math.PI - 0.3), 0) | |
| // crCameraLeft.fovMode = BABYLON.Camera.PERSPECTIVE_CAMERA; | |
| // crCameraRight.rotation = new BABYLON.Vector3(0, +(Math.PI - 0.3), 0) | |
| // crCameraRight.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED; | |
| // crCameraRight.checkCollisions = true; | |
| // crCamera.rotation = (new BABYLON.Vector3(0.5, 0, 0)) | |
| // crCamera.ellipsoid = new BABYLON.Vector3(1, 1, 1); | |
| // crCamera.ellipsoidOffset = new BABYLON.Vector3(3, 3, 3); | |
| // creature.checkCollisions = true; | |
| // scene.collisionsEnabled = true; | |
| // crCamera.applyGravity = true; | |
| // crCamera.fovMode = BABYLON.Camera.PERSPECTIVE_CAMERA; | |
| // crCamera.fovMode = BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED; | |
| // crCamera.inertia = 2 | |
| // crCamera.setTarget(new BABYLON.Vector3(2, 0, 0)) | |
| // const crCameraMesh = BABYLON.MeshBuilder.CreateSphere("cr_camera_mesh", {diameter: 1, segments: 32}, scene); | |
| // crCameraMesh.parent = crCamera | |
| // crCameraMesh.isVisible = 1 | |
| /* CLIENT */ | |
| const client = BABYLON.MeshBuilder.CreateSphere("client", {diameter: 3, segments: 32}, scene); | |
| client.parent = camera | |
| client.setParent(camera) | |
| // client.position = new BABYLON.Vector3(0, -12,0) | |
| const clMat = new BABYLON.StandardMaterial("cl_mat", scene) | |
| clMat.diffuseColor = new BABYLON.Color3(0, 0, 0) | |
| client.material = clMat | |
| engine.hideLoadingUI(); | |
| /* CAGE */ | |
| const cage = BABYLON.MeshBuilder.CreateSphere("cage", { | |
| segements: 64, | |
| diameter: 50 | |
| }, scene) | |
| // const cage = BABYLON.MeshBuilder.CreateBox("cage", { | |
| // width: 100, | |
| // depth: 100, | |
| // height: 40 | |
| // }, scene) | |
| cage.parent = null | |
| cage.setParent(null) | |
| cage.position = new BABYLON.Vector3(0, -12,0) | |
| cage.isPickable = true | |
| const cageMat = new BABYLON.StandardMaterial("cage_mat", scene); | |
| cageMat.alpha = 0.1 // for ray hit | |
| cage.material = cageMat | |
| cage.material.backFaceCulling = false | |
| cage.impostor = new BABYLON.PhysicsImpostor(cage, BABYLON.PhysicsImpostor.MeshImpostor, { | |
| mass: 0, | |
| friction: 1 | |
| }, scene); | |
| /* MIRROR */ | |
| /* const mirror = BABYLON.MeshBuilder.CreateBox("mirror", { | |
| width: 10, | |
| depth: 0.1, | |
| height: 5 | |
| }, scene) | |
| mirror.material = new BABYLON.StandardMaterial("mirror_mat", scene) | |
| mirror.position = new BABYLON.Vector3(20, 0, 0) | |
| // mirror.addRotation(0, Math.PI/2, 0) | |
| mirror.isVisible = true | |
| // How to use: mirror.material.diffuseTexture = new BABYLON.Texture(base64Data, scene) // timer ~1ms | |
| */ | |
| // const [ballRed, ballGreen, ballBlue, ballPurple, ballYellow] = ['red', 'green', 'blue', 'purple', 'yellow'].map(color => { | |
| const ballPos = [[-10,-10,10], [10,-10,-10], [-10,-10,-10], [10,-10,10]] | |
| // const balls = ['red', 'green', 'blue', 'purple'].map((color, i) => { | |
| const balls = ['green', 'green', 'red', 'red'].map((color, i) => { | |
| const ball = BABYLON.MeshBuilder.CreateSphere("ball_"+ color + i, {diameter: 7, segments: 64}, scene) | |
| ball.position = new BABYLON.Vector3(...ballPos[i]) | |
| ball.parent = null | |
| ball.setParent(null) | |
| ball.isPickable = true | |
| ball.impostor = new BABYLON.PhysicsImpostor(ball, BABYLON.PhysicsImpostor.SphereImpostor, { | |
| mass: 7, | |
| friction: 1, | |
| stiffness: 1, | |
| restitution: 1 | |
| }, scene); | |
| ball.material = scene.getMaterialByName(color + "Mat") | |
| ball.checkCollisions = true | |
| ball.material.backFaceCulling = false | |
| return ball | |
| }) | |
| // balls[0].position = new BABYLON.Vector3(10, 0, 0) | |
| /* SHuffle */ | |
| // scene.onPointerDown = function(evt, pickInfo) { | |
| // if(pickInfo.hit && pickInfo.pickedMesh.id.startsWith('cage')) { | |
| // const getRand = () => new BABYLON.Vector3(Math.random()/10 - 0.1, Math.random()/10 - 0.1, Math.random()/10 - 0.1) | |
| // balls.forEach(ball => ball.impostor.applyImpulse(getRand(), BABYLON.Vector3.Zero())) | |
| // } | |
| // } | |
| // setInterval(()=>{ | |
| // const getRand = () => new BABYLON.Vector3(Math.random()/10 - 0.1, Math.random()/10 - 0.1, Math.random()/10 - 0.1) | |
| // balls.forEach(ball => ball.impostor.applyImpulse(getRand(), BABYLON.Vector3.Zero())) | |
| // }, 1000) | |
| // ballRed.impostor.applyImpulse(new BABYLON.Vector3(0, -20, 0), BABYLON.Vector3.Zero()) | |
| // ballGr.impostor.applyImpulse(new BABYLON.Vector3(0, -20, 0), BABYLON.Vector3.Zero()) | |
| /* WORKER */ | |
| const worker = new Worker('worker.js') | |
| let inited = false | |
| worker.addEventListener('message', e => { | |
| const { weights, frame } = e.data | |
| tf.tidy(() => { | |
| if (weights) { | |
| inited = true | |
| agent.actor.setWeights(weights.map(w => tf.tensor(w))) // timer ~30ms | |
| if (Math.random() > 0.99) console.log('weights:', weights) | |
| } | |
| }) | |
| }) | |
| /* COLLISIONS DETECTION */ | |
| const impostors = scene.getPhysicsEngine()._impostors.filter(im => im.object.id !== creature.id) | |
| creature.impostor.registerOnPhysicsCollide(impostors, (body1, body2) => {}) | |
| impostors.forEach(impostor => { | |
| impostor.onCollide = e => { | |
| if (window.onCollide) { | |
| const collision = e.point.subtract(creature.position).normalize() | |
| window.onCollide(collision, impostor.object.id) | |
| } | |
| } | |
| }) | |
| // ;(() => { | |
| // let coll | |
| // creature.impostor.onCollide = e => { | |
| // coll = e.point.subtract(creature.position).normalize() | |
| // console.log('crea', coll) | |
| // if (window.onCollide) | |
| // window.onCollide(coll) | |
| // } | |
| // balls.forEach(ball => { | |
| // ball.impostor.onCollide = e => { | |
| // const collision = e.point.subtract(creature.position).normalize() | |
| // console.log('crea ball', coll, collision) | |
| // if (window.onCollide) | |
| // window.onCollide(collision, ball.id) | |
| // // if (ball.id.endsWith('_red')) | |
| // console.log('onCollide mesh:', ball.id) | |
| // } | |
| // }) | |
| // })() | |
| const base64ToImg = (base64) => new Promise((res, _) => { | |
| const img = new Image() | |
| img.src = base64 | |
| img.onload = () => res(img) | |
| }) | |
| const TRANSITIONS_BUFFER_SIZE = 2 | |
| const frameEvery = 1000/30 // ~33ms ~24frames/sec | |
| const frameStack = [] | |
| // const transitions = [] | |
| // let start = Date.now() + frameEvery | |
| let timer = Date.now() | |
| let busy = false | |
| let stateId = 0 | |
| let prevLinearVelocity = BABYLON.Vector3.Zero() | |
| window.collision = BABYLON.Vector3.Zero() | |
| window.reward = 0 | |
| window.globalReward = 0 | |
| // let collisionMesh = null | |
| const testLayer = agent.actor.layers[4] | |
| const spy = tf.model({inputs: agent.actor.inputs, outputs: testLayer.output}) | |
| scene.registerAfterRender(async () => { // timer ~ 20-90ms | |
| if (/*Date.now() < start || */busy || !inited) return | |
| // const delta = (Date.now() - timestamp) / 1000 // sec | |
| // timestamp = Date.now() | |
| // start = Date.now() + frameEvery | |
| busy = true | |
| // const timerLbl = 'TimerLabel-' + start | |
| /* | |
| console.time(timerLbl) | |
| console.timeEnd(timerLbl) | |
| console.log('numTensors BEFORE: ' + tf.memory().numTensors) | |
| console.log('numTensors AFTER: ' + tf.memory().numTensors) | |
| */ | |
| // const screenShots = [] | |
| // screenShots.push( | |
| // BABYLON.Tools.CreateScreenshotUsingRenderTargetAsync(engine, crCameraLeft, { // ~ 7-60ms | |
| // height: agent._frameShape[0], | |
| // width: agent._frameShape[1] | |
| // }) | |
| // ) | |
| // screenShots.push( | |
| // BABYLON.Tools.CreateScreenshotUsingRenderTargetAsync(engine, crCameraRight, { // ~ 7-60ms | |
| // height: agent._frameShape[0], | |
| // width: agent._frameShape[1] | |
| // }) | |
| // ) | |
| // const base64Data = await Promise.all(screenShots) | |
| // frameStack.push(base64Data) | |
| //delay | |
| if (!frameStack.length) { | |
| frameStack.push([ | |
| await BABYLON.Tools.CreateScreenshotUsingRenderTargetAsync(engine, crCameraLeft, { // ~ 7-60ms | |
| height: agent._frameShape[0], | |
| width: agent._frameShape[1] | |
| }) | |
| ]) | |
| } else { | |
| frameStack[0].push( | |
| await BABYLON.Tools.CreateScreenshotUsingRenderTargetAsync(engine, crCameraRight, { // ~ 7-60ms | |
| height: agent._frameShape[0], | |
| width: agent._frameShape[1] | |
| }) | |
| ) | |
| } | |
| if (frameStack.length >= agent._nFrames && frameStack[0].length == 2) { // ~20ms | |
| if (frameStack.length > agent._nFrames) | |
| throw new Error("(⊙_⊙')") | |
| const imgs = await Promise.all(frameStack.flat().map(fr => base64ToImg(fr))) | |
| const framesNorm = tf.tidy(() => { | |
| const greyScaler = tf.tensor([0.299, 0.587, 0.114], [1, 1, 3]) | |
| let imgTensors = imgs.map(img => tf.browser.fromPixels(img) | |
| //.mul(greyScaler).sum(-1, true) | |
| ) | |
| // optic chiasma | |
| // imgTensors = imgTensors.map(img => tf.split(img, 2, 1)) | |
| // for (let i = 0; i < imgTensors.length; i = i + 2) { | |
| // const first = tf.concat([imgTensors[i][0], imgTensors[i+1][0]], -1) | |
| // const second = tf.concat([imgTensors[i][1], imgTensors[i+1][1]], -1) | |
| // imgTensors[i] = first | |
| // imgTensors[i+1] = second | |
| // } | |
| // imgTensors = [ | |
| // imgTensors[0].concat(imgTensors[1], 1), | |
| // //imgTensors[2].concat(imgTensors[3], 1) | |
| // ] | |
| // if (collisionMesh) { | |
| imgTensors = imgTensors.map((t, i) => { | |
| const canv = document.getElementById('testCanvas' + (i+3)) | |
| if (canv) { | |
| tf.browser.toPixels(t, canv) // timer ~1ms | |
| } | |
| return t | |
| .sub(255/2) | |
| .div(255/2) | |
| }) | |
| // } | |
| const resL = tf.concat(imgTensors.filter((el, i) => i%2==0), -1) | |
| const resR = tf.concat(imgTensors.filter((el, i) => i%2==1), -1) | |
| return [resL, resR] | |
| // return [tf.concat(imgTensors, -1)] | |
| // let frTest = tf.unstack(res, -1) | |
| // // frTest = [tf.concat(frTest.slice(0,3), -1), tf.concat(frTest.slice(3), -1)] | |
| // console.log(frTest[0].arraySync()[30][0][0], frTest[3].arraySync()[30][0][0]) | |
| // console.log(tf.concat(tf.unstack(tf.concat(imgTensors, 2), -1), -1).arraySync()[30][0][0]) | |
| }) | |
| const framesBatch = framesNorm.map(fr => tf.stack([fr])) | |
| const delta = (Date.now() - timer) / 1000 // sec | |
| console.log('delta (s)', delta) | |
| const linearVelocity = creature.impostor.getLinearVelocity() | |
| const linearVelocityNorm = linearVelocity.normalize() | |
| const acceleration = linearVelocity.subtract(prevLinearVelocity).scale(1/delta).normalize() | |
| timer = Date.now() | |
| prevLinearVelocity = linearVelocity | |
| const ray = new BABYLON.Ray(creature.position, linearVelocityNorm) | |
| const hit = scene.pickWithRay(ray) | |
| let lidar = 0 | |
| if (hit.pickedMesh) { | |
| lidar = Math.tanh((hit.distance - creature.impostor.getRadius())/10) // stretch tanh by 10 for precision | |
| // console.log('Hit: ', hit.pickedMesh.name, hit.distance, lidar, linearVelocity, collision) | |
| } | |
| const telemetry = [ | |
| linearVelocityNorm.x, | |
| linearVelocityNorm.y, | |
| linearVelocityNorm.z, | |
| acceleration.x, | |
| acceleration.y, | |
| acceleration.z, | |
| window.collision.x, | |
| window.collision.y, | |
| window.collision.z, | |
| lidar | |
| ] | |
| const reward = window.reward | |
| //collisionMesh && | |
| // if (collisionMesh && transitions.length) { | |
| // tf.tidy(() => { | |
| // let frTest = tf.unstack(tf.tensor(transitions[transitions.length - 1].state[1], [64,128, agent._nFrames]), -1) | |
| // // frTest = [tf.stack(frTest.slice(0,3), -1), tf.stack(frTest.slice(3), -1)] | |
| // let i = 0 | |
| // for (const fr of frTest) { | |
| // i++ | |
| // tf.browser.toPixels(fr, document.getElementById('testCanvas' + i)) // timer ~1ms | |
| // } | |
| // }) | |
| // } | |
| window.collision = BABYLON.Vector3.Zero() // reset collision point | |
| window.reward = -0.01 | |
| window.onCollide = undefined | |
| const telemetryBatch = tf.tensor(telemetry, [1, agent._nTelemetry]) | |
| const action = agent.sampleAction([telemetryBatch, ...framesBatch]) // timer ~5ms | |
| // TODO: !!!!!await find the way to avoid framesNorm.array() | |
| console.time('await') | |
| const [framesArrL, framesArrR,[actionArr]] = await Promise.all([...(framesNorm.map(fr => fr.array())), action.array()]) // action come as a batch of size 1 | |
| console.timeEnd('await') | |
| // DEBUG Conv encoder | |
| tf.tidy(() => { // timer ~2.5ms | |
| const testOutput = spy.predict([telemetryBatch, ...framesBatch], {batchSize: 1}) | |
| console.log('spy', testLayer.name, testOutput.arraySync()) | |
| return | |
| let tiles = tf.clipByValue(tf.squeeze(testOutput), 0, 1) | |
| tiles = tf.transpose(tiles, [2,0,1]) | |
| tiles = tf.unstack(tiles) | |
| let res = [], line = [] | |
| for (const [i, tile] of tiles.entries()) { | |
| line.push(tile) | |
| if ((i+1) % 8 == 0 && i) { | |
| res.push(tf.concat(line, 1)) | |
| line = [] | |
| } | |
| } | |
| const testFr = tf.concat(res) | |
| tf.browser.toPixels(testFr, document.getElementById('testCanvas2')) // timer ~1ms | |
| }) | |
| const | |
| impulse = actionArr.slice(0, 3)//.map(el => el/10)//, // [0,-1, 0], // | |
| // rotation = actionArr.slice(3, 7).map(el => el), | |
| // color = actionArr.slice(3, 6).map(el => el)/.map(el => el) // [-1,1] => [0,2] => [0, 255] | |
| // look = actionArr.slice(3, 6) | |
| // console.log('tel tel: ', telemetry.map(t=> t.toFixed(3))) | |
| // console.log('tel imp:', impulse.map(t=> t.toFixed(3))) | |
| console.assert(actionArr.length === 3, actionArr.length) | |
| console.assert(impulse.length === 3) | |
| // console.assert(look.length === 3) | |
| // console.assert(rotation.length === 4) | |
| // console.assert(color.length === 3) | |
| // [0,-1,0] | |
| creature.impostor.setAngularVelocity(BABYLON.Quaternion.Zero()) // just in case, probably redundant | |
| // creature.impostor.setLinearVelocity(BABYLON.Vector3.Zero()) // contact point zero | |
| creature.impostor.applyImpulse(new BABYLON.Vector3(...impulse), creature.getAbsolutePosition()) // contact point zero | |
| creature.impostor.setAngularVelocity(BABYLON.Quaternion.Zero()) | |
| // creature.glow.color2 = new BABYLON.Color4(...color) | |
| // after applyImpulse the linear velocity is recalculated right away | |
| const newLinearVelocity = creature.impostor.getLinearVelocity().normalize() | |
| // creature.lookAt(new BABYLON.Vector3(0, -1, 0), 0, 0, 0, BABYLON.Space.LOCAL) | |
| creature.lookAt(creature.position.add(newLinearVelocity)) | |
| //if (!window.rr) window.rr = | |
| // creature.lookAt(creature.position.add(new BABYLON.Vector3(0,1,0))) | |
| const transtion = { | |
| id: stateId++, | |
| state: [telemetry, framesArrL, framesArrR], // 20ms vs 50ms || size 200kb vs 1.5mb | |
| action: actionArr, | |
| reward | |
| } | |
| transitions.push(transtion) | |
| window.onCollide = (collision, mesh) => { | |
| window.collision = collision | |
| window.reward += -0.05 | |
| if (mesh.startsWith('ball_')) { | |
| console.log('reward', mesh) | |
| window.reward = 1 | |
| if (mesh.includes('red')) | |
| window.reward = -1 | |
| } | |
| window.onCollide = undefined | |
| } | |
| if (transitions.length >= TRANSITIONS_BUFFER_SIZE) { | |
| if (transitions.length > TRANSITIONS_BUFFER_SIZE || TRANSITIONS_BUFFER_SIZE < 2) | |
| throw new Error("(⊙_⊙')") | |
| const transition = transitions.shift() | |
| // if (transition.reward > 0) { | |
| // transition.priority = 7 | |
| // console.log('reward prio:', transition, transition.state[0]) | |
| // } | |
| window.globalReward += transition.reward | |
| console.log('reward', transition.reward, window.globalReward) | |
| worker.postMessage({action: 'newTransition', transition}) // timer ~ 6ms | |
| } | |
| // imgTensors.forEach(t => t.dispose()) | |
| // frames.dispose() | |
| framesNorm.map(fr => fr.dispose()) | |
| framesBatch.map(fr => fr.dispose()) | |
| telemetryBatch.dispose() | |
| action.dispose() | |
| // if (stateId%1 == 0) | |
| // frameStack.forEach((base64Data, i) => { | |
| // const img = new Image() | |
| // img.onload = () => document.getElementById('testCanvas' + (i+2)) | |
| // .getContext('2d') | |
| // .drawImage(img, 0, 0, 256, 128) | |
| // img.src = base64Data | |
| // }) | |
| frameStack.length = 0 // I will regret about this :D | |
| } | |
| //mirror.material.diffuseTexture = new BABYLON.Texture(base64Data, scene) // timer ~1ms | |
| // const img = await base64ToImg(base64Data) // timer ~2-12ms | |
| // const tensor = tf.browser.fromPixels(img) // timer ~ 1ms | |
| // const arr = await tensor.array() // timer ~ 6-15ms | |
| // worker.postMessage(arr) // timer ~ 6ms | |
| // tensor.dispose() | |
| busy = false | |
| }) | |
| return scene | |
| }; | |
| window.initFunction = async function() { | |
| await Ammo(); | |
| const asyncEngineCreation = async function() { | |
| try { | |
| return createDefaultEngine(); | |
| } catch(e) { | |
| console.log("the available createEngine function failed. Creating the default engine instead"); | |
| return createDefaultEngine(); | |
| } | |
| } | |
| window.engine = await asyncEngineCreation(); | |
| if (!engine) throw 'engine should not be null.'; | |
| window.scene = await createScene(); | |
| }; | |
| initFunction().then(() => { | |
| sceneToRender = scene; | |
| engine.runRenderLoop(function () { | |
| if (sceneToRender && sceneToRender.activeCamera) { | |
| sceneToRender.render(); | |
| } | |
| }); | |
| }); | |
| window.addEventListener("resize", function () { | |
| engine.resize(); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |