UNPKG

node-red-node-rdk-3dsim

Version:

配合RDK硬件使用的3D可视化功能包

215 lines (175 loc) 7.04 kB
<script type="text/x-red" data-template-name="rdk-3d 3dlight"> <div class="form-row node-input-name"> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="rdk-3dlight.label.name"></span></label> <input type="text" id="node-input-name" data-i18n="[placeholder]rdk-3dlight.names.3dlight" style="width: 296px;"> </div> </script> <script type="module"> import * as THREE from 'https://cdn.jsdelivr.net/npm/three@latest/build/three.module.min.js'; (function(){ const width = 640; const height = 480; const colorNames = ['red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white']; const colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff, 0xffffff]; let flag = true; let nodeID = ''; let $boxframe = undefined; let offscreenCanvas = undefined; let scene = undefined; let camera = undefined; let renderer = undefined; let pointLight, pointLight2; let model = undefined; let animations = undefined; let clock = undefined; const createFrameImage = (id) => { $boxframe = document.getElementById('boxframe-' + id); if(!$boxframe){ const $container = document.getElementById(id); if (!$container) { return }; const bubble = document.createElementNS("http://www.w3.org/2000/svg", 'polyline'); bubble.setAttribute('id', 'bubble-' + id); bubble.setAttribute('style', 'fill:transparent'); bubble.setAttribute('stroke', '#999999'); $container.insertBefore(bubble, $container.lastChild.nextSibling); const img = document.createElementNS("http://www.w3.org/2000/svg", 'image'); img.setAttribute('id', 'boxframe-' + id); img.setAttribute('x', '1'); img.setAttribute('y', '47'); $container.insertBefore(img, $container.lastChild.nextSibling); $boxframe = img; } } const createOffscreenCanvas = () => { if(!offscreenCanvas){ offscreenCanvas = document.createElement('canvas'); offscreenCanvas.width = width; offscreenCanvas.height = height; } camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 ); camera.position.set( 0, 10, 40 ); scene = new THREE.Scene(); scene.add( new THREE.AmbientLight( 0x111122, 3 ) ); function generateTexture() { const canvas = document.createElement( 'canvas' ); canvas.width = 2; canvas.height = 2; const context = canvas.getContext( '2d' ); context.fillStyle = 'white'; context.fillRect( 0, 1, 2, 1 ); return canvas; } function createLight( color ) { const intensity = 200; const light = new THREE.PointLight( color, intensity, 20 ); light.castShadow = true; light.shadow.bias = - 0.005; // reduces self-shadowing on double-sided objects let geometry = new THREE.SphereGeometry( 0.3, 12, 6 ); let material = new THREE.MeshBasicMaterial( { color: color } ); material.color.multiplyScalar( intensity ); let sphere = new THREE.Mesh( geometry, material ); light.add( sphere ); const texture = new THREE.CanvasTexture( generateTexture() ); texture.magFilter = THREE.NearestFilter; texture.wrapT = THREE.RepeatWrapping; texture.wrapS = THREE.RepeatWrapping; texture.repeat.set( 1, 4.5 ); geometry = new THREE.SphereGeometry( 2, 32, 8 ); material = new THREE.MeshPhongMaterial( { side: THREE.DoubleSide, alphaMap: texture, alphaTest: 0.5 } ); sphere = new THREE.Mesh( geometry, material ); sphere.castShadow = true; sphere.receiveShadow = true; light.add( sphere ); return light; } pointLight = createLight( 0xffffff ); scene.add( pointLight ); pointLight2 = createLight( 0xffffff ); scene.add( pointLight2 ); // const geometry = new THREE.BoxGeometry( 30, 30, 30 ); const material = new THREE.MeshPhongMaterial( { color: 0xa0adaf, shininess: 10, specular: 0x111111, side: THREE.BackSide } ); const mesh = new THREE.Mesh( geometry, material ); mesh.position.y = 10; mesh.receiveShadow = true; scene.add( mesh ); renderer = new THREE.WebGLRenderer( { canvas: offscreenCanvas, antialias: true } ); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.BasicShadowMap; } function animate() { requestAnimationFrame(animate); flag = !flag; if(!flag){ return; } let time = performance.now() * 0.001; pointLight.position.x = Math.sin( time * 0.6 ) * 9; pointLight.position.y = Math.sin( time * 0.7 ) * 9 + 6; pointLight.position.z = Math.sin( time * 0.8 ) * 9; pointLight.rotation.x = time; pointLight.rotation.z = time; time += 10000; pointLight2.position.x = Math.sin( time * 0.6 ) * 9; pointLight2.position.y = Math.sin( time * 0.7 ) * 9 + 6; pointLight2.position.z = Math.sin( time * 0.8 ) * 9; pointLight2.rotation.x = time; pointLight2.rotation.z = time; renderer.render( scene, camera ); if($boxframe){ offscreenCanvas.setAttribute('width', width); offscreenCanvas.setAttribute('height', height); $boxframe.setAttribute('href', offscreenCanvas.toDataURL('image/png')); } } RED.comms.subscribe("switchlight", function(topic, color){ const idx = colorNames.findIndex((name) => { return name === color.toLowerCase(); }) let colorValue = '0xffffff'; if(idx >= 0){ colorValue = colors[idx]; } pointLight.color.set(colorValue); pointLight2.color.set(colorValue); }); RED.nodes.registerType("rdk-3d 3dlight",{ category: "RDK 3D Sim", color: "#ff3019", defaults: { name: {value:""} }, inputs:1, outputs:0, align: 'right', icon: "light.svg", paletteLabel: function() { return this._("rdk-3dlight.names.3dlight"); }, oneditprepare: function() {}, label: function() { if(nodeID === '' || !$boxframe){ nodeID = this.id; createFrameImage(nodeID); if($boxframe){ createOffscreenCanvas(); animate(); } } return this.name || this._("rdk-3dlight.names.3dlight"); } }); })() </script>