专栏首页郭先生的博客three.js 着色器材质之变量(一)

three.js 着色器材质之变量(一)

上一篇说顶点着色器和片元着色器的皮毛,这篇郭先生说一说着色器变量,通过变量可以设置材质。先看看今天要做的如下图。在线案例请点击红绿灯

捕获42.PNG

在这个案例之前,我们先复习一下着色器变量

  • Uniforms是所有顶点都具有相同的值的变量。 比如灯光,雾,和阴影贴图就是被储存在uniforms中的数据。 uniforms可以通过顶点着色器和片元着色器来访问。
  • Varyings 是从顶点着色器传递到片元着色器的变量。因此需要在两个着色器中同时定义,对于每一个片元,每一个varying的值将是相邻顶点值的平滑插值。
  • Attributes 与每个顶点关联的变量。例如,顶点位置,法线和顶点颜色都是存储在attributes中的数据。attributes 只可以在顶点着色器中访问。

嗯,现在我们知道了这些变量的用法,接下来我们使用它。

1. 制作红绿灯几何体

要制作这样一个红绿灯,我们考虑使用Geometry的merge方法

var shape = new THREE.Shape();
shape.moveTo(-10, 20);
shape.absarc(0, 20, 10,  Math.PI, Math.PI * 2, true);
shape.lineTo(10, -20);
shape.absarc(0, -20, 10, 0, Math.PI, true );
shape.lineTo(-10, 20);

var extrudeSettings = {
    steps: 2, //用于沿着挤出样条的深度细分的点的数量,默认值为1
    depth: 5, //挤出的形状的深度,默认值为100
    bevelEnabled: true, //对挤出的形状应用是否斜角,默认值为true
    bevelThickness: 1, //设置原始形状上斜角的厚度。默认值为6
    bevelSize: 1, //斜角与原始形状轮廓之间的延伸距离
    bevelSegments: 10, //斜角的分段层数,默认值为3
    curveSegments: 12, //曲线上点的数量,默认值是12
};
var frame = new THREE.ExtrudeGeometry(shape, extrudeSettings);
// var material = new THREE.MeshPhongMaterial({color: 0x222222, emissive: 0x222222});

var cylinGeom = new THREE.CylinderGeometry(6, 6, 6, 30, 20);
frame.merge(cylinGeom.clone(), new THREE.Matrix4().compose(new THREE.Vector3(0, 15, 3.1), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2), new THREE.Vector3(1,1,1)));
frame.merge(cylinGeom.clone(), new THREE.Matrix4().compose(new THREE.Vector3(0, 0, 3.1), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2), new THREE.Vector3(1,1,1)));
frame.merge(cylinGeom.clone(), new THREE.Matrix4().compose(new THREE.Vector3(0, -15, 3.1), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2), new THREE.Vector3(1,1,1)));

通过ExtrudeGeometry挤压出我们想要的几何体,然后添加三个圆柱体,形成我们想要的几何体。

2. 设置uniform变量

现在使用uniform变量

uniforms = {
    time: {
        type: 'f', value: 0.0
    }
}

这里我们在其中设置一个叫做time的变量,它的类型是一个float类型,默认值设置成0.0。然后我们在requestAnimationFrame的每一帧动画中调用uniforms.time.value += 0.01;让着色器动起来。

3. 顶点着色器

顶点着色器我们不做太多操作

varying vec3 vPosition;
uniform float time;
void main() {
    vPosition = position;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}

这里我们定义一个三维向量vPosition,用来将顶点着色器里面的position属性传递到片元着色器中(three.js会默认传入一些属性,像uv,position,normal等)

4. 片元着色器

varying vec3 vPosition;
uniform float time;
void main() {
    float time = mod(time, 3.0);//time值对3取模,得到[0,3)范围内的值。
		//由于我们制作红绿灯时用了小技巧,让其z分量比较大,所以可以根据z的值判断是否为红绿灯面。然后在根据y值,判断为哪个灯。
    if(vPosition.z == 6.1 && vPosition.y > 8.0) {
        if(time < 1.0) {//时间为[0,1)红灯
            gl_FragColor=vec4(1.0, 0.0, 0.0, 1.0);
        } else {
            gl_FragColor=vec4(0.2, 0.0, 0.0, 1.0);
        }
    } else if(vPosition.z == 6.1 && vPosition.y > -8.0) {//时间为[1,2)黄灯
        if(time >= 1.0 && time < 2.0) {
            gl_FragColor=vec4(1.0, 0.7, 0.0, 1.0);
        } else {
            gl_FragColor=vec4(0.2, 0.1, 0.0, 1.0);
        }
    } else if(vPosition.z == 6.1) {//时间为[2,3)绿灯
        if(time >= 2.0) {
            gl_FragColor=vec4(0.0, 1.0, 0.0, 1.0);
        } else {
            gl_FragColor=vec4(0.0, 0.2, 0.0, 1.0);
        }
    } else {//其余部分为灰色
        gl_FragColor=vec4(0.2, 0.2, 0.2, 1.0);
    }
}

这里我们使用顶点着色器传过来的向量vPosition和uniform中的time值做一些判断,实现对每个点颜色进行控制(根据颜色插值从而实现颜色面的控制),里面使用了一些方法,例如mod,请参见上一篇文章。

虽然这个小案例很简单,但是我相信大家肯定有了很好的想法,这几篇都是比较基础的,后面还有很多好看的案例,喜欢就点个赞吧!

转载请注明地址:郭先生的博客

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • three.js 数学方法之Box3

    郭先生今天说一说three.js的Box3方法(Box2是Box3的二维版本,可以参考Box3)。在线案例点击three.js Box3。

    郭先生的博客
  • three.js 对象绕任意轴旋转--模拟门转动

    今天郭先生说说对象如何绕任意轴旋转。说一说其中一种方法,也是比较容易理解的一种,它的原理就是将子对象放到一个盒子中,然后改变子对象相对于父对象的位置(因为子对象...

    郭先生的博客
  • three.js 自制骨骼动画(二)

    上一篇说了一下自制骨骼动画,这一篇郭先生使用帧动画让骨骼动画动起来。帧动画是一套比较完善的动画剪辑方法,详细我的api我们就不多说了,网上有很多例子,自行查找学...

    郭先生的博客
  • Mac下安装ipython

    超蛋lhy
  • Solr与MySQL查询性能对比

          "q": "CollectTime:[2014-12-06T00:00:00.000Z TO 2014-12-10T21:31:55.000Z]",

    凯哥Java
  • 深入理解python面向对象-特殊成员(补)

    定义一个instance类变量,然后重载__new__方法,这样就能确定此类只创建一个实例,但是返回值是一个实例对象,所以__init__每次还是会被调用。__...

    星星在线
  • 为什么别人的工作效率总比你快,是因为他用了三款神器!!!

    周末的时候菜鸟小白分享了七个神奇的网站,文章一发出去之后,在博客平台上引起了大家普遍的好评。那菜鸟小白就趁热打铁再给大家分享一波超级好用的工具吧,相信你...

    菜鸟小白的学习分享
  • 上辈子是运动员?一款人脸识别AI应用检测你与哪个世界杯运动员长得最像

    挪威新闻机构VG团队开发了一款全新的AI工具,使用面部识别技术,来查找与你的长相最为相似的足球运动员。

    AiTechYun
  • Python-geopandas 中国地图绘制

    上一期的地图可视化推文教程R-ggplot2 标准中国地图制作中,我们详细介绍了使用R-ggplot2 包完美绘制中国标准地图,本期推文我们则试着使用Pytho...

    bugsuse
  • 一次诡异的线上数据库的死锁问题排查过程

    前几天,线上发生了一次数据库死锁问题,这一问题前前后后排查了比较久的时间,这个过程中自己也对数据库的锁机制有了更深的理解。本文总结了这次死锁排查的全过程,并分析...

    Java3y

扫码关注云+社区

领取腾讯云代金券