3DSDK

导语

非均匀有理B样条,通常简称为NURBS(Non-Uniform Rational B-Splines),实际上已经成为利用计算机处理集合信息时用于形状的表示、设计和数据交换的工业标准。许多国内和国际标准,如IGES,STEP和PHIGS都把NURBS作为集合设计的一个强有力的工具。NURBS取得的巨大成功主要由于以下事实:

  1. NURBS为解析曲线曲面(如圆锥截线和二次曲面)和自由型曲线曲面(如汽车车身和船体外形)的表示提供一种统一的数学方法;

  1. 利用NURBS进行设计非常直观,几乎每个工具和算法都有一个易于理解的几何解释;

  2. NURBS的算法执行速度很快,并且数值稳定;

  3. NURBS曲线曲面在通常的几何变换(如平移、旋转、平行和透视投影)下是不变的;

  4. NURBS是非有理B样条、有理以及非有理Bezier曲线曲面的推广;

对于大部分人来说,B样条、有理B样条和NURBS有点神秘,有人成NURBS为无人能理解的有理B样条曲线(NoBody Understand Relation B-Splines);研究NURBS的当前首要目的在于呈现三维数据场的可视化,可参考书籍《三维数据场可视化》;

先睹为快


若有所思

技术无极限,技术是研究不完的,将现有的技术应用的实际的场景中,也验证了技术的能力,又促进了技术推进的动力;那么如上效果,在实际应用中,哪里可能会使用到呢?

实验天地

上述效果图是基于twaver的3D引擎开发的,自然不能暴露太多的代码;对底层实现比较感兴趣的可以研究three.js的NURB曲线;

mono.NurbsCurve使用
/*** {[TGL.Line]}  line  * {[Array of vector(3|4)]]}  ctrlPoints  曲线的控制点* {[Number]}  degree 曲线的最高指数* {[Number]} count  曲线每段需要插入点的个数* {[Object]} ctrlCond 线条控制条件*/
TGL.Line.createNurbs = function(line, ctrlPoints, degree, count, ctrlCond){}
弹簧
 var ctrlPoints = [];var a = 300;var n = 10;var offset = 2 * Math.PI / 100 /n ;var b = 100;for(var t= 0;t<= 2*Math.PI;t+= offset){var x = -b * b /a * Math.cos(n * t);var y = - 1 * b * b / a * Math.sin(n * t);var z = b * t;ctrlPoints.push(new TGL.Vec3(x,z,y));}var line = mono.Line.createNurbs(ctrlPoints, 1, 1,{skyY : 500,skyColor : new mono.Color('orange'),horizonY: 0,horizonColor: new mono.Color('orange'),earthY : -100,earthColor: new mono.Color('orange'),});line.s({'m.type': 'phong',});box.add(line);

mono.NurbsSurface的使用
/*** NurbsSurface 非均匀有理样条B样条曲面* NURBS是非有理B样条、有理以及非有理Bezier曲线曲面的推广* @class mono.NurbsSurface* @constructor* @extends mono.Curve* @param {Number} [degreeU] U方向阶数 <= U点数 - 1* @param {Number} [degreeV] V方向阶数 <= V点数 - 1* @param {Number} [ctrlPoints] 曲面的控制点* @return {mono.NurbsSurface} NurbsSurface对象* @example* */
曲面
<!DOCTYPE html>
<html>
<head><title>Mono Test</title><script type="text/javascript" src = "../src/t.js"></script><script type="text/javascript">function init(){var box = new mono.DataBox();var network= new mono.Network3D(box, null, monoCanvas);mono.Utils.autoAdjustNetworkBounds(network,document.documentElement,'clientWidth','clientHeight');network.setClearColor('#CDCDCD');box.add(new mono.AmbientLight(0x888888));var ctlPoints = [[new mono.Vec4(-200, 0, -200, 1 ),new mono.Vec4(-200, 100, -100, 1 ),new mono.Vec4(-200, -100, 100, 1 ),new mono.Vec4(-200, 0, 200, 1 ),new mono.Vec4(-200, 100, 200, 1 ),new mono.Vec4(-200, 0, 300, 1 ),],[new mono.Vec4(0, 0, -200, 1 ),new mono.Vec4(0, 100, -100, 1 ),new mono.Vec4(0, -100, 100, 1 ),new mono.Vec4(0, 0, 200, 1 ),new mono.Vec4(0, 100, 200, 1 ),new mono.Vec4(0, 0, 300, 1 ),],];var degreeU = 0;// 阶数 <= 点数 - 1 = 3 -1 var degreeV = 3;//阶数 <= 点数 - 1 = 6 - 1var nurbsSurface = new mono.NurbsSurface(degreeU, degreeV, ctlPoints);var surface = window.surface = new mono.Surface(nurbsSurface, 3,150,{skyY : 100,horizonY: 0,earthY : -100,skyColor : new mono.Color('red'),horizonColor: new mono.Color('gray'),earthColor: new mono.Color('green'),});surface.s({'m.type': 'basic','m.color': 'orange','m.side':mono.DoubleSide,'m.ambient': 'orange','m.texture.image':'./images/collage.jpg','m.wireframe':true,'m.wireframeLinewidth': 1,'m.wireframeLinecolor': 'orange','m.wireframeLineopacity': 1,});surface.setSelectable(false);box.add(surface);}</script>
</head>
<body 'init()'><div><canvas id="monoCanvas"/></div>
</body>
</html>

温度云场
<!DOCTYPE html>
<html>
<head><title>Mono Test</title><script type="text/javascript" src = "../src/t.js"></script><script type="text/javascript">function init(){var box = new mono.DataBox();var network= new mono.Network3D(box, null, monoCanvas);mono.Utils.autoAdjustNetworkBounds(network,document.documentElement,'clientWidth','clientHeight');network.setClearColor('#CDCDCD');// network.setShowAxis(true);box.add(new mono.AmbientLight(0x888888));var myImage = new Image();  myImage.src = "./images/hot.png"; myImage. function(){var canvas = document.createElement('canvas');var ctx = canvas.getContext('2d');ctx.drawImage(myImage,0,0);var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);var ctlPoints = [];for(var i = 0; i < imgData.height; ++i){var vpoints = [] ;for(var j = 0; j < imgData.width; ++j){var x = i*4*imgData.width + 4*j, r = imgData.data[x],g = imgData.data[x+1],b = imgData.data[x+2],a = imgData.data[x+3];vpoints.push(new mono.Vec4((j-imgData.width/2)*50,20 * ((r+g+b)/3 - 250/2),(i - imgData.height/2)*50,1));}ctlPoints.push(vpoints);}// var degreeU = imgData.height - 1;// 阶数 <= 点数 - 1 = 3 -1 // var degreeV = imgData.width - 1;//阶数 <= 点数 - 1 = 6 - 1var degreeU = 3;var degreeV = 4;var nurbsSurface = new mono.NurbsSurface(degreeU, degreeV, ctlPoints);var surface = window.surface = new mono.Surface(nurbsSurface, 200,200,{skyY : 2000,horizonY: 1000,earthY : 500,skyColor : new mono.Color('red'),horizonColor: new mono.Color('yellow'),earthColor: new mono.Color('green'),});surface.s({'m.type': 'basic','m.color': 'white',// 'm.side':mono.DoubleSide,'m.ambient': 'white','m.wireframe':true,'m.wireframeLinewidth': 0.1,'m.wireframeLinecolor': 'orange','m.wireframeLineopacity': 1,// 'm.texture.image':'./images/hot.png',});surface.setSelectable(false);box.add(surface);}}</script>
</head>
<body 'init()'><div><canvas id="monoCanvas"/></div>
</body>
</html>

引力场
<!DOCTYPE html>
<html>
<head><title>Mono Test</title><script type="text/javascript" src = "../src/t.js"></script><script type="text/javascript">function init(){var box = new mono.DataBox();var network= new mono.Network3D(box, null, monoCanvas);network.setClearColor('black');network.setClearAlpha(1);// network.setBackgroundImage('sky.jpg');mono.Utils.autoAdjustNetworkBounds(network,document.documentElement,'clientWidth','clientHeight');var pointLight = new mono.PointLight(0xFFFFFF,1.5);pointLight.setPosition(1000,1000,1000);box.add(pointLight);box.add(new mono.AmbientLight(0x888888));var camera=network.getCamera();camera.setPosition(200, 200, 500);  var cube = new mono.Sphere(50, 30, 30, 0, Math.PI*2, 0, Math.PI);cube.setPosition(0,40,0);cube.s({'m.type': 'phong','m.color': 'white','m.texture.image':'world1.jpg'});cube.setSelectable(false);box.add(cube);var ctrlPoints = [];var n = 100;var offset = 2 * Math.PI/n ;var points = [];var a = 400;for(var t= 0;t<= 2*Math.PI;t+= offset){var x = a*Math.cos(t);var y = 0;// var y = a * Math.sin(t);var z = a*Math.sin(t);points.push(new mono.Vec4(x,y,z,100));}ctrlPoints.push(points);a= 200;var points = [];for(var t= 0;t<= 2*Math.PI;t+= offset){var x = a*Math.cos(t);var y = 40;// var y = a * Math.sin(t);var z = a*Math.sin(t);points.push(new mono.Vec4(x,y,z,200));}ctrlPoints.push(points);a= 5;var points = [];for(var t= 0;t<= 2*Math.PI;t+= offset){var x = a*Math.cos(t);var y = -120;// var y = a * Math.sin(t);var z = a*Math.sin(t);points.push(new mono.Vec4(x,y,z,400));}ctrlPoints.push(points);a= 0;var points = [];for(var t= 0;t<= 2*Math.PI;t+= offset){var x = a*Math.cos(t);var y = -110;// var y = a * Math.sin(t);var z = a*Math.sin(t);points.push(new mono.Vec4(x,y,z,400));}ctrlPoints.push(points);var degree1 = 2;var degree2 = n - 1;var nurbsSurface = new mono.NurbsSurface(degree1, degree2, ctrlPoints);var surface  = new mono.Surface(nurbsSurface, 100,60,{skyY : 40,horizonY: 0,earthY : -100,skyColor : new mono.Color('#80B9B3'),horizonColor: new mono.Color('#A9DCD7'),earthColor: new mono.Color('#8CEBF4'),});surface.s({'m.type': 'phong','m.side':mono.DoubleSide,// 'm.texture.image':'UV_Grid_Sm.jpg','m.texture.image':'./images/sky.jpg',// 'm.tansparent':true,// 'm.opacity':0.2,// 'm.texture.image':'sky.jpg','m.wireframe':true,'m.wireframeLinewidth': 1,'m.wireframeLinecolor': '#33726c','m.wireframeLineopacity': 0.9,});box.add(surface);surface.setPosition(0,40,0);surface.setSelectable(false);}</script>
</head>
<body onload = 'init()'><div><canvas id="monoCanvas"/></div>
</body>
</html>

天空盒中的温度云

参考资料

[1]. 权威书籍:《非均匀有理B样条(第2版)》
[2]. 《三维数据场可视化》
[3]. /...
[4].B 样条曲线、样条曲面 NURBS
[5]./
[6]./
[7]./...
[8].BURBS Book 书籍 ...
...

3DSDK

导语

非均匀有理B样条,通常简称为NURBS(Non-Uniform Rational B-Splines),实际上已经成为利用计算机处理集合信息时用于形状的表示、设计和数据交换的工业标准。许多国内和国际标准,如IGES,STEP和PHIGS都把NURBS作为集合设计的一个强有力的工具。NURBS取得的巨大成功主要由于以下事实:

  1. NURBS为解析曲线曲面(如圆锥截线和二次曲面)和自由型曲线曲面(如汽车车身和船体外形)的表示提供一种统一的数学方法;

  1. 利用NURBS进行设计非常直观,几乎每个工具和算法都有一个易于理解的几何解释;

  2. NURBS的算法执行速度很快,并且数值稳定;

  3. NURBS曲线曲面在通常的几何变换(如平移、旋转、平行和透视投影)下是不变的;

  4. NURBS是非有理B样条、有理以及非有理Bezier曲线曲面的推广;

对于大部分人来说,B样条、有理B样条和NURBS有点神秘,有人成NURBS为无人能理解的有理B样条曲线(NoBody Understand Relation B-Splines);研究NURBS的当前首要目的在于呈现三维数据场的可视化,可参考书籍《三维数据场可视化》;

先睹为快


若有所思

技术无极限,技术是研究不完的,将现有的技术应用的实际的场景中,也验证了技术的能力,又促进了技术推进的动力;那么如上效果,在实际应用中,哪里可能会使用到呢?

实验天地

上述效果图是基于twaver的3D引擎开发的,自然不能暴露太多的代码;对底层实现比较感兴趣的可以研究three.js的NURB曲线;

mono.NurbsCurve使用
/*** {[TGL.Line]}  line  * {[Array of vector(3|4)]]}  ctrlPoints  曲线的控制点* {[Number]}  degree 曲线的最高指数* {[Number]} count  曲线每段需要插入点的个数* {[Object]} ctrlCond 线条控制条件*/
TGL.Line.createNurbs = function(line, ctrlPoints, degree, count, ctrlCond){}
弹簧
 var ctrlPoints = [];var a = 300;var n = 10;var offset = 2 * Math.PI / 100 /n ;var b = 100;for(var t= 0;t<= 2*Math.PI;t+= offset){var x = -b * b /a * Math.cos(n * t);var y = - 1 * b * b / a * Math.sin(n * t);var z = b * t;ctrlPoints.push(new TGL.Vec3(x,z,y));}var line = mono.Line.createNurbs(ctrlPoints, 1, 1,{skyY : 500,skyColor : new mono.Color('orange'),horizonY: 0,horizonColor: new mono.Color('orange'),earthY : -100,earthColor: new mono.Color('orange'),});line.s({'m.type': 'phong',});box.add(line);

mono.NurbsSurface的使用
/*** NurbsSurface 非均匀有理样条B样条曲面* NURBS是非有理B样条、有理以及非有理Bezier曲线曲面的推广* @class mono.NurbsSurface* @constructor* @extends mono.Curve* @param {Number} [degreeU] U方向阶数 <= U点数 - 1* @param {Number} [degreeV] V方向阶数 <= V点数 - 1* @param {Number} [ctrlPoints] 曲面的控制点* @return {mono.NurbsSurface} NurbsSurface对象* @example* */
曲面
<!DOCTYPE html>
<html>
<head><title>Mono Test</title><script type="text/javascript" src = "../src/t.js"></script><script type="text/javascript">function init(){var box = new mono.DataBox();var network= new mono.Network3D(box, null, monoCanvas);mono.Utils.autoAdjustNetworkBounds(network,document.documentElement,'clientWidth','clientHeight');network.setClearColor('#CDCDCD');box.add(new mono.AmbientLight(0x888888));var ctlPoints = [[new mono.Vec4(-200, 0, -200, 1 ),new mono.Vec4(-200, 100, -100, 1 ),new mono.Vec4(-200, -100, 100, 1 ),new mono.Vec4(-200, 0, 200, 1 ),new mono.Vec4(-200, 100, 200, 1 ),new mono.Vec4(-200, 0, 300, 1 ),],[new mono.Vec4(0, 0, -200, 1 ),new mono.Vec4(0, 100, -100, 1 ),new mono.Vec4(0, -100, 100, 1 ),new mono.Vec4(0, 0, 200, 1 ),new mono.Vec4(0, 100, 200, 1 ),new mono.Vec4(0, 0, 300, 1 ),],];var degreeU = 0;// 阶数 <= 点数 - 1 = 3 -1 var degreeV = 3;//阶数 <= 点数 - 1 = 6 - 1var nurbsSurface = new mono.NurbsSurface(degreeU, degreeV, ctlPoints);var surface = window.surface = new mono.Surface(nurbsSurface, 3,150,{skyY : 100,horizonY: 0,earthY : -100,skyColor : new mono.Color('red'),horizonColor: new mono.Color('gray'),earthColor: new mono.Color('green'),});surface.s({'m.type': 'basic','m.color': 'orange','m.side':mono.DoubleSide,'m.ambient': 'orange','m.texture.image':'./images/collage.jpg','m.wireframe':true,'m.wireframeLinewidth': 1,'m.wireframeLinecolor': 'orange','m.wireframeLineopacity': 1,});surface.setSelectable(false);box.add(surface);}</script>
</head>
<body 'init()'><div><canvas id="monoCanvas"/></div>
</body>
</html>

温度云场
<!DOCTYPE html>
<html>
<head><title>Mono Test</title><script type="text/javascript" src = "../src/t.js"></script><script type="text/javascript">function init(){var box = new mono.DataBox();var network= new mono.Network3D(box, null, monoCanvas);mono.Utils.autoAdjustNetworkBounds(network,document.documentElement,'clientWidth','clientHeight');network.setClearColor('#CDCDCD');// network.setShowAxis(true);box.add(new mono.AmbientLight(0x888888));var myImage = new Image();  myImage.src = "./images/hot.png"; myImage. function(){var canvas = document.createElement('canvas');var ctx = canvas.getContext('2d');ctx.drawImage(myImage,0,0);var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);var ctlPoints = [];for(var i = 0; i < imgData.height; ++i){var vpoints = [] ;for(var j = 0; j < imgData.width; ++j){var x = i*4*imgData.width + 4*j, r = imgData.data[x],g = imgData.data[x+1],b = imgData.data[x+2],a = imgData.data[x+3];vpoints.push(new mono.Vec4((j-imgData.width/2)*50,20 * ((r+g+b)/3 - 250/2),(i - imgData.height/2)*50,1));}ctlPoints.push(vpoints);}// var degreeU = imgData.height - 1;// 阶数 <= 点数 - 1 = 3 -1 // var degreeV = imgData.width - 1;//阶数 <= 点数 - 1 = 6 - 1var degreeU = 3;var degreeV = 4;var nurbsSurface = new mono.NurbsSurface(degreeU, degreeV, ctlPoints);var surface = window.surface = new mono.Surface(nurbsSurface, 200,200,{skyY : 2000,horizonY: 1000,earthY : 500,skyColor : new mono.Color('red'),horizonColor: new mono.Color('yellow'),earthColor: new mono.Color('green'),});surface.s({'m.type': 'basic','m.color': 'white',// 'm.side':mono.DoubleSide,'m.ambient': 'white','m.wireframe':true,'m.wireframeLinewidth': 0.1,'m.wireframeLinecolor': 'orange','m.wireframeLineopacity': 1,// 'm.texture.image':'./images/hot.png',});surface.setSelectable(false);box.add(surface);}}</script>
</head>
<body 'init()'><div><canvas id="monoCanvas"/></div>
</body>
</html>

引力场
<!DOCTYPE html>
<html>
<head><title>Mono Test</title><script type="text/javascript" src = "../src/t.js"></script><script type="text/javascript">function init(){var box = new mono.DataBox();var network= new mono.Network3D(box, null, monoCanvas);network.setClearColor('black');network.setClearAlpha(1);// network.setBackgroundImage('sky.jpg');mono.Utils.autoAdjustNetworkBounds(network,document.documentElement,'clientWidth','clientHeight');var pointLight = new mono.PointLight(0xFFFFFF,1.5);pointLight.setPosition(1000,1000,1000);box.add(pointLight);box.add(new mono.AmbientLight(0x888888));var camera=network.getCamera();camera.setPosition(200, 200, 500);  var cube = new mono.Sphere(50, 30, 30, 0, Math.PI*2, 0, Math.PI);cube.setPosition(0,40,0);cube.s({'m.type': 'phong','m.color': 'white','m.texture.image':'world1.jpg'});cube.setSelectable(false);box.add(cube);var ctrlPoints = [];var n = 100;var offset = 2 * Math.PI/n ;var points = [];var a = 400;for(var t= 0;t<= 2*Math.PI;t+= offset){var x = a*Math.cos(t);var y = 0;// var y = a * Math.sin(t);var z = a*Math.sin(t);points.push(new mono.Vec4(x,y,z,100));}ctrlPoints.push(points);a= 200;var points = [];for(var t= 0;t<= 2*Math.PI;t+= offset){var x = a*Math.cos(t);var y = 40;// var y = a * Math.sin(t);var z = a*Math.sin(t);points.push(new mono.Vec4(x,y,z,200));}ctrlPoints.push(points);a= 5;var points = [];for(var t= 0;t<= 2*Math.PI;t+= offset){var x = a*Math.cos(t);var y = -120;// var y = a * Math.sin(t);var z = a*Math.sin(t);points.push(new mono.Vec4(x,y,z,400));}ctrlPoints.push(points);a= 0;var points = [];for(var t= 0;t<= 2*Math.PI;t+= offset){var x = a*Math.cos(t);var y = -110;// var y = a * Math.sin(t);var z = a*Math.sin(t);points.push(new mono.Vec4(x,y,z,400));}ctrlPoints.push(points);var degree1 = 2;var degree2 = n - 1;var nurbsSurface = new mono.NurbsSurface(degree1, degree2, ctrlPoints);var surface  = new mono.Surface(nurbsSurface, 100,60,{skyY : 40,horizonY: 0,earthY : -100,skyColor : new mono.Color('#80B9B3'),horizonColor: new mono.Color('#A9DCD7'),earthColor: new mono.Color('#8CEBF4'),});surface.s({'m.type': 'phong','m.side':mono.DoubleSide,// 'm.texture.image':'UV_Grid_Sm.jpg','m.texture.image':'./images/sky.jpg',// 'm.tansparent':true,// 'm.opacity':0.2,// 'm.texture.image':'sky.jpg','m.wireframe':true,'m.wireframeLinewidth': 1,'m.wireframeLinecolor': '#33726c','m.wireframeLineopacity': 0.9,});box.add(surface);surface.setPosition(0,40,0);surface.setSelectable(false);}</script>
</head>
<body onload = 'init()'><div><canvas id="monoCanvas"/></div>
</body>
</html>

天空盒中的温度云

参考资料

[1]. 权威书籍:《非均匀有理B样条(第2版)》
[2]. 《三维数据场可视化》
[3]. /...
[4].B 样条曲线、样条曲面 NURBS
[5]./
[6]./
[7]./...
[8].BURBS Book 书籍 ...
...