Three.js Demo源码分析1.MorphTargets与BufferGeometry

摘要:
在Three的主页上有很多漂亮的Demo。js,这是学习的绝佳材料。renderer=newTHREE。WebGLRenderer();渲染器。setSize;文档正文。appendChild;camera=新三个。透视摄像机;摄像头位置。z=400;scene=newTHREE。场景();创建立方体网格,粘贴纹理,然后将其添加到场景中。vargeometry=newTHREE。立方体几何;vartexture=THREE.ImageUtils。loadTexture;texture.isotropic=渲染器。getMax各向异性();varmaterial=newTHREE。MeshBasicMaterial;mesh=新三个。网格场景添加在animate()中渲染,结束。MorphTargets First Look MorphTarget允许对象变形。这样做的好处显而易见。只要之前设置了morphTargetInfluences数组,就可以简单地调整它以使对象变形。BufferGeometry是具有最高自由度的几何体类型。您可以自由指定每个顶点的位置、颜色和法线。

Three.js主页上有很多绚丽的Demo,是学习的极佳素材。我正利用闲暇时间学习这些Demo,并将心得体会记录下来。

老调重弹

先睹为快

空间中旋转的立方体板条箱,恐怕是主页上最简单的一个例子了。在WebGL原生API教程中就有这个例子,用Three.js实现起来更加方便了。但是,作为开始的开始,还是再重弹一遍老调吧。

较简单的例子多采用这种一目了然的结构:

    // 在<body>尾部:
    // 一些全局变量
    var camera, scene, renderer;
    var mesh;
    // 初始化函数,仅运行一次
    function init(){
        // 初始化这些全局变量
    }
    // 动画函数,每一帧运行一次
    function animate(){
        requestAnimationFrame(animate);
        // 动画和绘图
    }
    init();
    animate();

 在init()中初始化相机,场景,渲染器,轻车熟路。

    renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(70, window.innerWidth/window.innerHeight, 1, 1000);
    camera.position.z = 400;

    scene = new THREE.Scene();

创建一个立方体mesh,贴上纹理,并加入到场景中。

    var geometry = new THREE.CubeGeometry(200, 200, 200);

    var texture = THREE.ImageUtils.loadTexture('code.JPG');
    texture.anisotropy = renderer.getMaxAnisotropy();

    var material = new THREE.MeshBasicMaterial({map:texture});

    mesh = new THREE.Mesh(geometry, material);

    scene.add(mesh);

在animate()中渲染,结束。

    function animate(){
        requestAnimationFrame(animate);

        mesh.rotation.x += 0.005;
        mesh.rotation.y += 0.01;

        renderer.render(scene, camera);
    }

这个例子就不多说了,代码放在这里只是作为最简单的开始。如果你之前使用过Three.js,一段时间不用后有所生疏,这个例子可以迅速将你唤醒。

MorphTargets

先睹为快

MorphTargets允许物体发生变形。如果该物体的geometry有 $n$ 个顶点,那么MorphTargets允许你再指定 $n$ 个, $2n$ 个, $3n$ 个甚至更多个顶点(比如,$ p\cdot n$ 个),同时mesh对象提供一个数组morphTargetInfluences(公式中$ f_{j} $表示morphTargetInfluences[j]),具有 $p$ 个元素,每个元素取值在0-1之间。渲染这个物体的时候,某个顶点 $V_{i}$ 的位置其实变了,成了:

$$V_{i}=V_{i}+\sum_{j=0}^{p}f_{j}\cdot (V_{j,i}-V_{i})$$

举个简单的例子,一个立方体有8个顶点,MorphTargets又指定了8个顶点,立方体的一个顶点为(1,1,1),而在MorphTargets中与之对应的顶点为(2,2,2),那么当morphTargetInfluences[0]为0.5的时候,实际渲染的时候该顶点的位置就成了(1.5,1.5,1.5)。这样做的好处是显而易见的,你可以通过简单地调整morphTargetInfluences数组来使物体形变,只要之前你设置好了。

向物体加入morphTargets的方法很简单:

    var geometry = new THREE.CubeGeometry(100,100,100);
    var material = new THREE.MeshLambertMaterial({color:0xffffff, morphTargets:true});

    var vertices = [];
    for(var i=0; i<geometry.vertices.length; i++)
    {
        var f = 2;
        vertices.push(geometry.vertices[i].clone());
        vertices[i].x *= f;
        vertices[i].y *= f;
        vertices[i].z *= f;
    }
    geometry.morphTargets.push({name:'target0', vertices:vertices});

 在其他什么地方(比如animate()或render()方法中)改变morphTargetInfluences,实在方便

var s = 0;
function render()
{
    s += 0.03;
    mesh.morphTargetInfluences[0] = Math.abs(Math.sin(s));
    ...
}

最关键的问题是,我相信,这个功能是通过着色器来完成的。我阅读过一些简单的着色器,因此我发现在着色器中完成这件事实在太合适了。如果某个geometry有几千甚至上万个顶点,使用JavaScript逐个计算变形后顶点的位置会造成很大压力,而显卡大规模并行计算的能力很适合处理这个任务(毕竟每个顶点是独立地)。

BufferGeometry

先睹为快

BufferGeometry是自由度最高的geometry类型了,你可以自由指定每个顶点的位置、颜色、法线(影响光照)。

所谓Buffer,缓冲区,就是指顶点位置数组、顶点颜色数组等JavaScript二进制数组。这样定义一个BufferGeometry:

var geometry = new THREE.BufferGeometry();
geometry.attributes = {
    index:{
        itemSize:1,
        array:new Uint16Array(triangles*3),
        numItems:triangles*3
    },
    position:{
        itemSize:3,
        array:new Float32Array(triangles*3*3),
        numItems:triangles*3*3
    },
    normal:{
        itemSize:3,
        array:new Float32Array(triangles*3*3),
        numItems:triangles*3*3
    },
    color:{
        itemSize:3,
        array:new Float32Array(triangles*3*3),
        numItems:triangles*3*3
    }
};

这个例子通过好几个循环,在一个800宽度的立方体范围内随机构造了16万个尺寸1-12的小三角形,计算了法向,并按照位置赋值了颜色,指定了材质。最后的效果相当壮观。

接着创建一个旁氏反射类型的材质和mesh。

var material = new THREE.MeshPhongMaterial({
    color: 0xaaaaaa,
    ambient: 0xaaaaaa,
    specular: 0xffffff,
    shininess: 250,
    side: THREE.DoubleSide,
    vertexColors: THREE.VertexColors
});
mesh = new THREE.Mesh(geometry, material); 

如果顶点的个数过多,超过了整型数index表示的范围(65536),则可以使用offset来处理。在这个例子中有16万个三角形,48万个顶点,使用了8个offset,每个offset相当于重置了index值。

geometry.offsets = [];
for(var i=0; i<offsets; i++){
    var offset = {
      start:i*chunkSize*3,
      index:i*chunkSize*3,
      count:Math.min(triangles-(i*chunkSize), chunkSize)*3
    };
    geometry.offsets.push(offset);
}

如果看过WebGL原生API教程,就会发现这与其中构建几何体的过程实在是太相似了。

另两个类似的例子,是线类型和点类型的。

先睹为快(线)

先睹为快(点)

这两种类型声明geometry时只需要position属性和color属性,不需要normal(没有面自然没有法向)属性。 

geometry.attributes = {
    position:{
        itemSize:3,
        array:new Float32Array(segments*3),
        numItems:segments*3
    },
    color:{
        itemSize:3,
        array:new Float32Array(segments*3),
        numItems:segments*3
    }
};

用自己的逻辑填充完数组后,创建材质及相应的line对象或particleSystem对象,而不是mesh对象。

对线类型:

var material = new THREE.LineBasicMaterial({vertexColors:true});
line = new THREE.Line(geometry, material);

对点类型

var material = new THREE.ParticleBasicMaterial({
    size:15,
    vertexColors:true
});
particleSystem = new THREE.ParticleSystem(geometry, material);

这一篇先以一个最简单的例子“热身”,之后记录了MorphTargets和BufferGeometry的用法。

免责声明:文章转载自《Three.js Demo源码分析1.MorphTargets与BufferGeometry》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用jmeter HTTP代理服务器录制APP脚本php curl 错误 cURL error 60 unable to get local issuer certificate【转】下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Cesium快速上手8-Appearance&amp;amp;Material

image.png 比较通用的有两个: Cesium.MaterialAppearance(options) 可以设置纹理图案 Cesium.PerInstanceColorAppearance(options) 主要用于颜色属性,与 Cesium.GeometryInstance中attributes中 colo属性 ; 每个GeometryInsta...

【Unity插件】NGUI核心组件之UIPanel .

转自:http://blog.csdn.net/daiguangda/article/details/7840084   UIPanel负责创建实际的集合图形。你不需要手动的添加UIPanel-一旦你创建一个控件,它会自动被添加。如果你想将你的UI渲染拆分到不同的Draw Call中,你可以手动创建你自己的UIPanel,例如你要创建一个分屏的游戏,每个屏...

22种开源Vue模板和主题框架「干货」

前言 在Internet上搜索模板和主题时,很难找到免费的Vue资源。 即使您不在乎质量,它们似乎也很难被发现,并出于好奇而感动,我花了数小时在Google和Github上四处挖掘,结果得到了收集22种开源Vue模板和主题框架集合。我不会对此打赌,但是它们也是高质量的资源。 Bootstrap Vue 现场演示:https://bootstrap-vue...

Cesium原理篇:Material【转】

https://www.cnblogs.com/fuckgiser/p/6171245.html Shader 首先,在本文开始前,我们先普及一下材质的概念,这里推荐材质,普及材质的内容都是截取自该网站,我觉得他写的已经够好了。在开始普及概念前,推荐一首我此刻想到的歌《光---陈粒》。 在真实世界里,每个物体会对光产生不同的反应。钢看起来比陶瓷花瓶更闪闪...

GitHub 和 Gitee 开源免费 10 个超赞后台管理面板,看完惊呆了!

软件工程师在实际项目开发中不可避免需要依赖一些前后端的后台管理系统框架,而不是从零开始一点点的搭建,浪费人力。目前市面上有很多开放源码、且免费的后台管理面板,样式色彩也比较丰富美观。 今天整理了一下GitHub和Gitee上比较优秀的后台管理面板,这些后台管理面板有的是包含前后端代码有的是UI框架含前端代码,都支持Git命令下载编译,运行即可正常访问。 1...

Unity MeshRender更换材质球方法

https://blog.csdn.net/ystistheking/article/details/70207792 转载自CSDN布莱克汉; 干活的时候遇到了这样一个问题,当要用代码给这个模型换材质球的时候,单独获取renderer组件里的materials数组里的materials[1]或者materials[2]是无法改变材质球的,此时采用以下...