使用WebGL实现一个Viewer来显示STL文件
关键字:WebGL,STL,ThreeJS,Chrome,Viewer,Python3.4, HTML5,Canvas。
OS:Windows 10。
本文介绍如何使用ThreeJS来实现一个WebGL的Viewer,用来浏览STL文件。
<!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/
使用WebGL实现一个Viewer来显示STL文件的更多相关文章
- 与STL文件相关的各类学习地址
几个网址: 1.STL :https://en.wikipedia.org/wiki/STL_(file_format)#ASCII_STL 2.一个博客的文章地址: 三维图形数据格式 STL的 读取 ...
- 打开本地STL文件并创建webgl使用的geometry
需求 打开本地STL文件 一个独立基于webgl的viewer,会被别的网站重用 将打开文件的数据传输给viewer,并且在文件加载的时候显示进度条 解决方案 #1可以使用传统的html5 api来打 ...
- VTK中导入并显示STL、3DS文件
VTK(visualization toolkit)是一个开源的免费软件系统,主要用于三维计算机图形学.图像处理和科学计算可视化.VTK是在三维函数库OpenGL 的基础上采用面向对象的设计方法发展起 ...
- 使一个div始终显示在页面中间
使一个div始终显示在页面中间 假设我们有一个div层:<div id=”myDiv”></div> 首先,我们用css来控制它在水平上始终居中,那么我们的css代码应该是这样 ...
- 关于一个隐藏和显示物品列表的demo
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...
- Keil MDK 5.14 仿真时System Viewer菜单显示空白和Peripherals菜单无外设寄存器
keil mdk5.14新建工程进行仿真时,进入Debug环境发现System Viewer菜单显示空白,Peripherals菜单没有外设寄存器.如图1和图2所示.打开Oprons for Targ ...
- Sublime Text 如何一个代码双屏显示代码上下部分?
Sublime Text 如何一个代码双屏显示代码上下部分? sublime text如何一个代码双屏显示代码上下部分 先显示2行实图 把想要分屏显示的文件,打开新窗口,然后再拖过去就可以了. 快捷操 ...
- SharePoint server 2016中文版导出list template,在另外一个环境不能显示
SharePoint server 2016中文版导出list template,在另外一个环境不能显示,解决方案: $web = Get-SPWeb <url of web> $web. ...
- Qt for Android (三) 打开Android相册并选一个图片进行显示
Qt for Android (三) 这两天弄了一下android相册的相关功能.还是花了挺长时间的,这里总结一下,避免以后再踩坑.同时也在这篇文章里面补齐一些android开发的基础支持 打开And ...
随机推荐
- 深入研究Block用weakSelf、strongSelf、@weakify、@strongify解决循环引用(上)
深入研究Block捕获外部变量和__block实现原理 前言 在上篇中,仔细分析了一下Block的实现原理以及__block捕获外部变量的原理.然而实际使用Block过程中,还是会遇到一些问题,比如R ...
- How to solve Original Tango programmer”Hardware not Found”?
Original Tango programmer is a new generation of transponder programmer which is developed to cover, ...
- css笔记14:css文件之间可以相互引用
css文件之间相互引用是通过@import指令完成的 格式: @import url("被引用的css文件"); 顺便说一句,如果希望在html或者php文件中引用某个xxx.c ...
- 移动互联网(APP)产品设计的经验分享【转】
随着移动互联网的发展,越来越多的Web产品开始布局移动端,因此最近经常碰到PM们在交流讨论移动APP产品的设计.我从事移动互联网已经有一年多了,通过不断的学习和实践也积累了一些心得,今天整理并分享一下 ...
- python(3)-深浅拷贝
import copy copy.copy() 浅拷贝 copy.deepcopy() 深拷贝 >>> import copy >>> a1 = 123 ...
- MSP430常见问题之复位系统类
Q1:请问msp430 怎么手动复位啊?是不是连到RST/NMI 上?但是这个脚不是和JTAG 连吗?我看到一些资料上说复位的话还要上拉电阻或者复位电路.A1:JTAG 功能只在下载程序时候使用,正常 ...
- DAG的动态规划 (UVA 1025 A Spy in the Metro)
第一遍,刘汝佳提示+题解:回头再看!!! POINT: dp[time][sta]; 在time时刻在车站sta还需要最少等待多长时间: 终点的状态很确定必然是的 dp[T][N] = 0 ---即在 ...
- T-SQL使用JOIN执行UPDATE语句
问题: In SQL Server, it's possible to insert into a table using a SELECT statement: INSERT INTO Table ...
- SSRS:之为用户“NT AUTHORITY\NETWORK SERVICE”授予的权限不足,无法执行此操作。 (rsAccessDenied)
错误信息: 为用户"NT AUTHORITY\NETWORK SERVICE"授予的权限不足,无法执行此操作. (rsAccessDenied) 如图: 解决方案之检查顺序: 1. ...
- 【Cocos2d入门教程七】三分钟看懂Cocos2d坐标系
无论是搞2d还是3d开发,最需要搞清楚的就是坐标系,这部分混乱的话就没啥搞头了.所以玩cocos2d,一上来就需要先把各种与坐标有关的东西搞清楚. 1.OpenGL坐标系 Cocos2d-x使用的是O ...