This flow loads the three.js library (from cdnjs.cloudflare.com) and serves an http endpoint (/cube) that displays a spinning 3D cube. The websockets are used to communicate both ways, in this example, the cube sends a message each time it changes direction, which is used in Node-Red to change the cube's color.
-
-
Save Hugobox/079151b53f63261911684acc015f9166 to your computer and use it in GitHub Desktop.
Three.js http 3D cube example with websockets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[{"id":"82bc22cb.914be","type":"http in","z":"c33009bf.64c1c8","name":"","url":"/cube","method":"get","upload":false,"swaggerDoc":"","x":270,"y":1020,"wires":[["ab9b0e5e.f8f8b"]]},{"id":"6752712.7f98a9","type":"http response","z":"c33009bf.64c1c8","name":"","statusCode":"","headers":{},"x":815,"y":1020,"wires":[]},{"id":"ab9b0e5e.f8f8b","type":"template","z":"c33009bf.64c1c8","name":"three.js","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n<head>\n\n <title>Test</title>\n\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n \n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js\"></script>\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.min.js\"></script>\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.module.js\"></script>\n \n<script>\nvar server = window.location.href.split(\"http://\")[1].split(\"/\")[0]\nconsole.log(\"Page location is \" + server)\n\nvar socket1 = new WebSocket(\"ws://\" + server + \"/ws/receive\");\nvar socket2 = new WebSocket(\"ws://\" + server + \"/ws/publish\");\nvar cubeRotationSpeed = 0.02;\nlet cubeColor = \"blue\"\nvar socket1Opened = false\n\nsocket1.onopen = function() {\n socket1Opened = true\n var message = {\n 'payload': 'Client connected'\n };\n socket1.send(JSON.stringify(message));\n};\n\nsocket2.onopen = function() {\n var message = {\n 'payload': 'Client connected'\n };\n socket1.send(JSON.stringify(message));\n};\n\nsocket2.onclose = function(){\n console.log('Connection closed');\n};\n\nsocket2.onerror = function(error) {\n console.log('Error detected: ' + JSON.stringify(error));\n};\n\nsocket2.onmessage = function(e) {\n var server_message = e.data;\n responseObject = JSON.parse(server_message);\n\n //alert(JSON.stringify(responseObject));\n //Do the required stuff\n console.log(responseObject.payload)\n if (responseObject.payload.cubeRotationSpeed){\n cubeRotationSpeed = responseObject.payload.cubeRotationSpeed\n }else if(responseObject.payload.cubeColor){\n cubeColor = responseObject.payload.cubeColor\n }\n}\n\nvar scene = new THREE.Scene();\n\n// Make highly-transparent plane\nvar fadeMaterial = new THREE.MeshBasicMaterial({\n color: 0x000000,\n transparent: true,\n opacity: 0.02\n});\nvar fadePlane = new THREE.PlaneBufferGeometry(1, 1);\nvar fadeMesh = new THREE.Mesh(fadePlane, fadeMaterial);\n\n// Create Object3D to hold camera and transparent plane\nvar camGroup = new THREE.Object3D();\nvar camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);\ncamGroup.add(camera);\ncamGroup.add(fadeMesh);\n\n// Put plane in front of camera\nfadeMesh.position.z = -0.1;\n\n// Make plane render before particles\nfadeMesh.renderOrder = -1;\n\n// Add camGroup to scene\nscene.add(camGroup);\n\n\nrenderer = new THREE.WebGLRenderer( { preserveDrawingBuffer: true, antialias: true } );\nrenderer.autoClearColor = false;\nrenderer.setSize(window.innerWidth, window.innerHeight);\n\ndocument.addEventListener('DOMContentLoaded', function () { \n document.body.appendChild(renderer.domElement);\n});\n\nvar geometry = new THREE.BoxGeometry(1,1,1);\n//var color = new THREE.Color(0xff0000)\nvar material = new THREE.MeshBasicMaterial({color: \"blue\"});\nvar cube = new THREE.Mesh(geometry, material);\nscene.add(cube);\n\ncube.position.z = -5;\n\nvar step = .03;\nfunction animate(){\n\n cube.rotation.x += cubeRotationSpeed;\n cube.rotation.y += 0.02;\n cube.position.x += step;\n cube.material.color = new THREE.Color(cubeColor);\n if(Math.abs(cube.position.x) > 5.0)\n {\n step = -step;\n if (socket1Opened){\n socket1.send(\"ping\");\n }\n }\n renderer.render(scene, camera);\n\n requestAnimationFrame(animate);\n}\n\nanimate();\n\n</script>\n\n\n","output":"str","x":480,"y":1020,"wires":[["f195cd.89a76a3"]]},{"id":"f8262338.541b2","type":"websocket out","z":"c33009bf.64c1c8","name":"","server":"c6bb1eb5.edd3d","client":"","x":1010,"y":1140,"wires":[]},{"id":"1f953c53.234544","type":"inject","z":"c33009bf.64c1c8","name":"Spin slow","topic":"","payload":"{\"cubeRotationSpeed\":0.02}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":615,"y":1140,"wires":[["f8262338.541b2"]]},{"id":"ae4b9f83.855ed","type":"inject","z":"c33009bf.64c1c8","name":"Spin fast","topic":"","payload":"{\"cubeRotationSpeed\":0.1}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":615,"y":1185,"wires":[["f8262338.541b2"]]},{"id":"f195cd.89a76a3","type":"change","z":"c33009bf.64c1c8","name":"Set Headers","rules":[{"t":"set","p":"headers","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"headers.content-type","pt":"msg","to":"text/html","tot":"str"},{"t":"set","p":"headers.Access-Control-Allow-Origin","pt":"msg","to":"*","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":1020,"wires":[["6752712.7f98a9"]]},{"id":"eba548fa.e65d98","type":"change","z":"c33009bf.64c1c8","name":"","rules":[{"t":"delete","p":"_session","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":805,"y":1080,"wires":[["f8262338.541b2"]]},{"id":"c1fc2e6e.bd70e","type":"websocket in","z":"c33009bf.64c1c8","name":"","server":"a5db9e65.7dd36","client":"","x":290,"y":1080,"wires":[["22fc2d8b.025e32"]]},{"id":"22fc2d8b.025e32","type":"switch","z":"c33009bf.64c1c8","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"ping","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":455,"y":1080,"wires":[["eaae5e3a.3f284"]]},{"id":"eaae5e3a.3f284","type":"function","z":"c33009bf.64c1c8","name":"change color","func":"let colors = [\"white\",\"red\",0x00ff00,0x0000ff] //both hex or string are fine\nmsg.payload = {\"cubeColor\": colors[Math.floor(Math.random()*colors.length)]}\nreturn msg;","outputs":1,"noerr":0,"x":610,"y":1080,"wires":[["eba548fa.e65d98"]]},{"id":"94b2919c.8d227","type":"comment","z":"c33009bf.64c1c8","name":"Three.js example with websockets","info":"","x":350,"y":960,"wires":[]},{"id":"c6bb1eb5.edd3d","type":"websocket-listener","z":"","path":"/ws/publish","wholemsg":"true"},{"id":"a5db9e65.7dd36","type":"websocket-listener","z":"","path":"/ws/receive","wholemsg":"true"}] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment