Palash 3D Projector

Palash 3D Projector

Sun Lee
Palash 3D 投影機
Palash 3D 投影機

簡介

此投影機的原理為透過螢幕將畫面照設置透明壓克力板,透過壓克力的折射,產生出立體的影像,以下我將從3個部份來介紹我們的3D投影機

  1. 硬體架構
  2. 畫面呈現
  3. 遠端控制


1.硬體架構

螢幕:我們使用22吋螢幕*1

透明壓克力板*3:設計圖參考如下:

壓克力板設計圖


根據螢幕大小,我們的所需木頭如下:

薄木板:58公分*38公分

木框長邊:58公分角木頭*4

木框短邊:33公分角木頭*4

木框支撐:30公分角木頭*2

木框支撐:角落固定架*4

黑色噴漆:1灌

角木頭可至建材行採買
所需木頭材料

組裝過程:使用釘子將框釘好

組裝1
組裝2

裝訂完成後,建議再加上角落固定架,確保整體的支撐穩定度

組裝完成圖

組裝完成之後,為了之後整體效果,建議漆上全黑色,以確保展示之品質

漆成黑色

2.畫面呈現

我們採用播放影片的方式,將預錄好的畫面,折射至壓克力板上,使其產生立體效果。

而立體米果畫面來源為:http://palashntub.000webhostapp.com/projector.html

由我們自行開發的米果展示網頁,改變背景而成,使用Three.js技術將立體圖案呈現於HTML網頁上。

網頁原始碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Palash Rice Cracker 3d viewer</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="Description" content="Check the 3D Palash Rice Cracker by THREE.js">
    <link rel="icon" href="favicon.ico" type="image/x-icon" />
    <link rel="stylesheet" href="assets/css/3d.css" />
        
</head>
<body style="margin:0;" onload="myFunction()">
    <div id="logos">
        <div class="logos_img">
            <img src="images/logos.png" alt="Palash3D">
        </div>
        <div id="loader"></div>
    </div>
    <div id="canvas" style="display:none">
        <div class="link">
            <p>Palash Rice Cracker 3D simulation</p>
            <a target="_blank" href="index.html">Click to Palash Home page</a>
        </div>
    </div>
    

    <script>
        var myVar;
        function myFunction() {
          myVar = setTimeout(showPage, 5000);
        }
        
        function showPage() {
          document.getElementById("logos").style.display = "none";
          document.getElementById("canvas").style.display = "block";
          //document.getElementsByTagName("canvas").style.display = "none";
        }
    </script>

    <script type="module">
        import * as THREE from 'https://threejs.org/build/three.module.js';
        import { OBJLoader } from 'https://threejs.org/examples/jsm/loaders/OBJLoader.js';
        import { MTLLoader } from 'https://threejs.org/examples/jsm/loaders/MTLLoader.js';
        import { DDSLoader } from 'https://threejs.org/examples/jsm/loaders/DDSLoader.js';
        import Stats from 'https://threejs.org/examples/jsm/libs/stats.module.js';
        import { GUI } from 'https://threejs.org/examples/jsm/libs/dat.gui.module.js';
        import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';
        import { RGBELoader } from 'https://threejs.org/examples/jsm/loaders/RGBELoader.js';

        draw();

        var renderer;
        function initRender() {
            renderer = new THREE.WebGLRenderer({antialias:true});
            renderer.setSize(window.innerWidth, window.innerHeight);
            //陰影效果
            renderer.setClearColor(0xffffff);
            document.getElementById("canvas").appendChild(renderer.domElement);
        }

        var camera;
        function initCamera() {
            camera = new THREE.PerspectiveCamera(100, window.innerWidth/window.innerHeight, 0.1, 1000);
            camera.position.set(-35, 55, 95);
            camera.lookAt(new THREE.Vector3(0,0,0));
        }

        var scene;
        function initScene() {
            scene = new THREE.Scene();
        }

        function initLight() {
            var ambientLight = new THREE.AmbientLight(0xcccccc, 1.5);
            scene.add(ambientLight);

            
            var pointLight = new THREE.PointLight(0xffffff, 1);
            camera.add(pointLight);

            //告訴平行光需要開啟陰影投射
            pointLight.castShadow = false;

            scene.add(pointLight);
        }

        function initModel() {            
            new RGBELoader()
                .setDataType(THREE.UnsignedByteType)
                .load('https://cdn.jsdelivr.net/gh/nyy28477590/palash/background.hdr', function(texture) {
                    var envMap = pmremGenerator.fromEquirectangular(texture).texture;
                    
                    scene.background = envMap;
                    scene.environment = envMap;

                    texture.dispose();
                    pmremGenerator.dispose();

                    render();

                    //model
                    var onProgress = function ( xhr ) {
                    if ( xhr.lengthComputable ) {
                        var percentComplete = xhr.loaded / xhr.total * 100;
                        console.log( Math.round( percentComplete, 2 ) + '% downloaded' );
                        }
                    };
                    var onError = function () { };
                    var manager = new THREE.LoadingManager();
                    manager.addHandler( /\.dds$/i, new DDSLoader() );
                
                new MTLLoader( manager )
                    .load( 'https://cdn.jsdelivr.net/gh/nyy28477590/palash/palash5.mtl', function ( materials ) {
                        materials.preload();
                        new OBJLoader( manager )
                            .setMaterials( materials )
                            .load( 'https://cdn.jsdelivr.net/gh/nyy28477590/palash/palash5.obj', function ( object ) {
                                object.scale.set(1.3, 1.3, 1.3); //縮放
                                object.position.y = 0;
                                object.position.x = 0;
                                scene.add( object );
                            }, onProgress, onError );
                    } );
            })                   
            var pmremGenerator = new THREE.PMREMGenerator( renderer );
            pmremGenerator.compileEquirectangularShader();
        }

        //初始化性能顯示
        var stats;
        function initStats() {
            stats = new Stats();
            document.getElementById("canvas").appendChild(stats.dom);
        }
        


        //滑鼠左鍵可以旋轉,右鍵重新平移,滾輪縮放
        var controls;
        function initControls() {

            controls = new OrbitControls( camera, renderer.domElement );

            //是否有慣性
            controls.enableDamping = true;
            //滑鼠靈敏度
            controls.dampingFactor = 0.25;
            //是否可以縮放
            controls.enableZoom = true;
            //是否自動旋轉
            controls.autoRotate = true;
            controls.autoRotateSpeed = 0.5;
            //相機距離原點的最進距離
            controls.minDistance  = 1;
            //相機距離原點的最遠距離
            controls.maxDistance  = 200;
            //開啟右鍵拖移
            controls.enablePan = true;
        }

        function render() {
            renderer.render( scene, camera );
        }

        //變動觸發的函數
        function onWindowResize() {

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            render();
            renderer.setSize( window.innerWidth, window.innerHeight );

        }


        function animate() {
            //更新控制器
            render();
            controls.update();
            requestAnimationFrame(animate);
        }

        function draw() {
            initRender();
            initScene();
            initCamera();
            initLight();
            initModel();
            initControls();
            animate();
            window.onresize = onWindowResize;
        }
    </script>

</body>
</html>


米果呈現影片:

米果影片

LOGO漂浮影片:

LOGO影片

3.遠端控制

我們使用了樹莓派3做為控制中心,將呈現畫面放到樹莓派裡

樹莓派3

再將分別根據播放的影片寫成獨立的Python檔案

程式碼如下:

from omxplayer
import OMXPlayer.player from pathlib import Path
from time import sleep
VIDEO_PATH = Path("/home/pi/Videos/palash.mp4")#自行更換要播放的影片位址
player = OMXPlayer(VIDEO_PATH)
sleep(15)
player.quit()

接者使用Node-red(事先安裝好),建立按鈕(左邊藍色部分),將樹莓派Lunix指令與按鈕連接起來

範例程式碼:

執行Python檔:python3 /home/pi/Desktop/palash.py

停止播放:pkill omxplayer

Node-red操作介面

完成之後,部署應用程式完成後,即可透過區域連線控制此樹莓派,適用裝置包括手機、筆電、平板電腦等可以連上網的裝置都行!

控制網址:區域網路ip:1880/ui

手機控制介面
手機控制展示

參考資料

Holographic Audio Visualizer with Motion Control: https://www.hackster.io/hackershack/holographic-audio-visualizer-with-motion-control-e72fee

Three.js: https://threejs.org/


特別感謝

國際商務系 林純如 副教授

山雲創新科技執行長 Kent Su

國際商務系 系辦公室

同學爸爸

協助製作


如果有任何問題歡迎聯絡我,聯絡方式:

Email: nyy28477590@gmail.com

Line: sunlee0329

Instagram: sunlee0329

GitHub: https://github.com/nyy28477590




Report Page