使用WebGL实现一个Viewer来显示STL文件

关键字:WebGL,STL,ThreeJS,Chrome,Viewer,Python3.4, HTML5,Canvas。

OS:Windows 10。

本文介绍如何使用ThreeJS来实现一个WebGL的Viewer,用来浏览STL文件。

STL 文件是在计算机图形应用系统中,用于表示三角形网格的一种文件格式。 它的文件格式非常简单, 应用很广泛。

STL是最多快速原型系统所应用的标准文件类型。STL是用三角网格来表现3D CAD模型。

1.新建一个STL.html文件如下:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>WebViewer - STL</title>
        <meta charset="utf-8">
    </head>
    <body>
        <script src="threejs/three.min.js"></script>
        <script src="threejs/loaders/STLLoader.js"></script>
        <script src="threejs/OrbitControls.js"></script>

        <script>
            var container;

            var camera, cameraTarget, scene, renderer;

            var cameraType = 1;
            var perspectiveAngle = 45;
            var cameraPosX = 200;
            var cameraPosY = 200;
            var cameraPosZ = 200;
            var cameraTargetX = 0;
            var cameraTargetY = 0;
            var cameraTargetZ = 0;
            var upVectorX = 0;
            var upVectorY = 1;
            var upVectorZ = 0;
            var cameralScale = 5;

            init();
            animate();

            function getQueryStringByName(name){
                 var result = location.search.match(new RegExp("[\?\&]" + name+ "=([^\&]+)","i"));

                 if(result == null || result.length < 1){
                     return "";
                 }

                 return result[1];
            }

            function init() {

                container = document.createElement( ‘div‘ );
                document.body.appendChild( container );

                // set camera
                var cameraTypeStr = getQueryStringByName(‘cameraType‘);
                cameraType = cameraTypeStr == "" ? cameraType : parseInt(cameraTypeStr);

                var perspectiveAngleStr = getQueryStringByName(‘perspectiveAngle‘);
                perspectiveAngle = perspectiveAngleStr == "" ? perspectiveAngle : parseFloat(perspectiveAngleStr);

                var cameraPosXStr = getQueryStringByName(‘cameraPosX‘);
                cameraPosX = cameraPosXStr == "" ? cameraPosX : parseFloat(cameraPosXStr) * cameralScale;

                var cameraPosYStr = getQueryStringByName(‘cameraPosY‘);
                cameraPosY = cameraPosYStr == "" ? cameraPosY : parseFloat(cameraPosYStr) * cameralScale;

                var cameraPosZStr = getQueryStringByName(‘cameraPosZ‘);
                cameraPosZ = cameraPosZStr == "" ? cameraPosZ : parseFloat(cameraPosZStr) * cameralScale;

                var cameraTargetXStr = getQueryStringByName(‘cameraTargetX‘);
                cameraTargetX = cameraTargetXStr == "" ? cameraTargetX : parseFloat(cameraTargetXStr) * cameralScale;

                var cameraTargetYStr = getQueryStringByName(‘cameraTargetY‘);
                cameraTargetY = cameraTargetYStr == "" ? cameraTargetY : parseFloat(cameraTargetYStr) * cameralScale;

                var cameraTargetZStr = getQueryStringByName(‘cameraTargetZ‘);
                cameraTargetZ = cameraTargetZStr == "" ? cameraTargetZ : parseFloat(cameraTargetZStr) * cameralScale;

                var upVectorXStr = getQueryStringByName(‘upVectorX‘);
                upVectorX = upVectorXStr == "" ? upVectorX : parseFloat(upVectorXStr) * cameralScale;

                var upVectorYStr = getQueryStringByName(‘upVectorY‘);
                upVectorY = upVectorYStr == "" ? upVectorY : parseFloat(upVectorYStr) * cameralScale;

                var upVectorZStr = getQueryStringByName(‘upVectorZ‘);
                upVectorZ = upVectorZStr == "" ? upVectorZ : parseFloat(upVectorZStr) * cameralScale;

                if(cameraType == 0) {
                    camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 10000 );
                }
                else {
                    camera = new THREE.PerspectiveCamera( perspectiveAngle, window.innerWidth / window.innerHeight, 1, 10000 );
                }

                camera.position.set( cameraPosX, cameraPosY, cameraPosZ);
                camera.up.set(upVectorX, upVectorY, upVectorZ);

                cameraTarget = new THREE.Vector3( cameraTargetX, cameraTargetY, cameraTargetZ );
                camera.lookAt( cameraTarget );

                scene = new THREE.Scene();
                scene.fog = new THREE.Fog( 0xffffff, 1, 10000 );

                // load file

                var loader = new THREE.STLLoader();

                var modelName = getQueryStringByName(‘modelName‘);
                loader.load( ‘../Models/‘ + modelName, function ( geometry ) {

                    var material = new THREE.MeshPhongMaterial( { color: 0x808080, specular: 0x111111, shininess: 200 } );
                    var mesh = new THREE.Mesh( geometry, material );

                    mesh.castShadow = true;
                    mesh.receiveShadow = true;

                    scene.add( mesh );

                } );

                // lights

                scene.add( new THREE.AmbientLight( 0x333333 ) );

                addDirectionalLight(-1, 1, 1, 0xFFFFFF, 1.35);
                addDirectionalLight(1, -1, -1, 0xFFFFFF, 1);

                // renderer

                renderer = new THREE.WebGLRenderer( { antialias: true } );
                renderer.setClearColor( scene.fog.color );
                renderer.setSize( window.innerWidth, window.innerHeight );

                renderer.gammaInput = true;
                renderer.gammaOutput = true;

                renderer.shadowMapEnabled = true;
                renderer.shadowMapCullFace = THREE.CullFaceBack;

                container.appendChild( renderer.domElement );

                // orbit control

                control = new THREE.OrbitControls( camera, renderer.domElement );

                // events

                window.addEventListener( ‘resize‘, onWindowResize, false );
            }

            function addDirectionalLight( x, y, z, color, intensity ) {

                var directionalLight = new THREE.DirectionalLight( color, intensity );
                directionalLight.position.set( x, y, z )
                scene.add( directionalLight );
            }

            function onWindowResize() {

                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();

                renderer.setSize( window.innerWidth, window.innerHeight );

            }

            function animate() {

                requestAnimationFrame( animate );

                render();
            }

            function render() {

//                var timer = Date.now() * 0.0005;
//
//                camera.position.x = Math.cos( timer ) * 3;
//                camera.position.z = Math.sin( timer ) * 3;

                renderer.render( scene, camera );
            }

        </script>
    </body>
</html>

2.直接用Chrome打开文件STL.html,将会看到一下错误,那是因为不能打开本地模型文件,需要创建一个http server。

XMLHttpRequest cannot load file:///D:/L/Dev/WebViewer/Models/. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.THREE.XHRLoader.load @ three.min.js:258
three.min.js:258 Uncaught NetworkError: Failed to execute ‘send‘ on ‘XMLHttpRequest‘: Failed to load ‘file:///D:/L/Dev/WebViewer/Models/‘.

3.本文使用python来创建一个http server,新建localServer.py文件,内容如下:

from threading import Thread
import webbrowser, http.server, socketserver
import time;

port_number = 8000

server = None
def startServer(port):
    Handler = http.server.SimpleHTTPRequestHandler
    global server
    server = socketserver.TCPServer(("", port), Handler)

    print("Start server at port", port)
    server.serve_forever()

def start(port):
    thread = Thread(target=startServer, args=[port])
    thread.start()

    startTime = int(time.time())
    while not server:
        if int(time.time()) > startTime + 60:
            print("Time out")
            break
    return server

def stop():
    if server:
        server.shutdown()

def openUrl():
    url = "http://localhost:" + str(port_number)
    webbrowser.open(url)
    print(url + " is opened in browser")

if __name__ == "__main__":
    start(port_number)
    openUrl()

4.文件夹结构如下:

Models - 模型文件夹,放置模型文件,例如bike_frame.stl。

threejs - threejs文件夹,放置threejs相关的库文件

5. 双击运行LocalServer.py启动一个http服务器。

6.在Chrome里面打开http://localhost:8000/WebGLViewer/STL.html?modelName=bike_frame.stl,如下图。

源代码地址:https://github.com/ldlchina/Sample-of-WebGL-with-STL-loader

相关链接: http://threejs.org/

时间: 2024-10-12 21:03:05

使用WebGL实现一个Viewer来显示STL文件的相关文章

创建一个程序读入和显示视频文件,并可以使用滑动条控制视频文件的播放。一个滑动条用来控制视频播放位置,以10为步长跳进。另一个滑动条用来控制停止/播放

/* 创建一个程序读入和显示视频文件,并可以使用滑动条控制视频文件的播放. 一个滑动条用来控制视频播放位置,以10为步长跳进.另一个滑动条用来控制 停止/播放 */ #include <cv.h> #include <highgui.h> int g_slider_position = 0; CvCapture* g_capture = NULL; int index = 0; bool flag = true; int g_slider_position1 = 0; void o

读取STL文件模型

STL是CAD软件中出来的一种3D模型文件格式,wiki已经解释的很清楚了. STL文件两种格式,ASCII STL和Binary STL. ASCII STL,每一个facet由7行数据组成,outer loop后面三个顶点的顺序沿法线矢量逆时针排序,格式如下: solid name // 文件名及文件路径 facet normal ni nj nk // 三角形法向量的三个分量 outer loop vertex v1x v1y v1z // 第一个顶点坐标 vertex v2x v2y v

打开本地STL文件并创建webgl使用的geometry

需求 打开本地STL文件 一个独立基于webgl的viewer,会被别的网站重用 将打开文件的数据传输给viewer,并且在文件加载的时候显示进度条 解决方案 #1可以使用传统的html5 api来打开, #2来说,可以通过iframe来提供独立的viewer, #3来说需要用web worker来实现. 实现细节 数据的流向是网站的main page->iframe中viewer的main page->web worker->iframe的main page 刚打开的数据类型是buff

WebGL画一个10px大小的点

WebGL程序在屏幕上同时使用HTML和javascript来创建和显示三维图形.WebGL中新引入的<canvas>元素标签,它定义了网页上的绘图区域. 由于<canvas>元素可以灵活地同时支持维维图形和三维图形,它不直接提供绘图方法,而是提供一种叫上下文(context)的机制来进行绘图.我们首先获取这个上下文. //获取WebGL绘图上下文var gl = getWebGLContext(canvas, true); getWebGLContext(element, [de

关于一个隐藏和显示物品列表的demo

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <meta http-equiv="Content-Type"

一个日期时间显示框的美化风格示例

一个日期时间显示框的美化风格示例,在网页上显示时间的一个美化示例,为时间显示框增加了一个漂亮的外框,这个外框是基于图片来美化的,,虽然现在都不主张用图片来美化了,不过看上去还真是挺漂亮的.www.srcfans.com为大家分享开源源码. 源码下载:一个日期时间显示框的美化风格示例

Keil MDK 5.14 仿真时System Viewer菜单显示空白和Peripherals菜单无外设寄存器

keil mdk5.14新建工程进行仿真时,进入Debug环境发现System Viewer菜单显示空白,Peripherals菜单没有外设寄存器.如图1和图2所示.打开Oprons for Target 查看System Viewer File选项没有勾选Use Custom File,系统默认的STM32F103xx.svd.如图3所示.查看Debug选项中的Dialog DLL一栏写着DCM.DLL.Parameter一栏写着-pCM3.如图4所示. 图1   System Viewer菜

iOS判断一个View是否显示在屏幕上

有时候做UI的时候,比如需要判断scrollView中一个btn是否显示在屏幕上,可以用以下代码: #pragma mark - 返回一个View所在的位置x,y,是否在rect坐标里面 - (BOOL)isInScreenView:(UIView *)inView withRect:(CGRect)rect{ return CGRectIntersectsRect(inView.frame, rect); } #pragma mark - 返回判断screenRect所在的位置x,y,是否在r

从一个int值显示相应枚举类型的名称或者描述

我正在做一个出入库管理的简单项目,在Models里定义了这样的枚举类型 public enum InOrOut { [Description("出库")] Out = 0, [Description("入库")] In = 1 } 我想在输入参数为数据库字段值1或者0的时候,在页面上显示为枚举Name:In.Out,或者干脆显示为Description:出库.入库. 获取枚举Name其实很简单: return Enum.GetName(typeof(InOrOut)