用Three.js搞个3D金字塔

简介: 来来来,进来就看用Three.js搞个简单的3D金字塔!祝福大家都能成为金字塔顶端的大佬!嘛哩嘛哩哄!祈祷成功!

1.金字塔

金字塔组成:顶部一个四棱锥体,下面是上窄下宽依次递增的四棱台。

那么需要计算一下依次下来的每个面大小,上面的形状底部作为下面形状的顶面,这样就每层都能看起来连续。

js

let top = idx * width;//顶面正方形宽度            let bottom = (idx + 1) * width;//底面正方形宽度            let geometry = newTHREE.CylinderGeometry(              isDown ? bottom : top,              isDown ? top : bottom,              height,              4,//四棱台              4            );                                   //对应形状的需要放置的高度            //this.intervalH = 0.3 形状与形状之间的间隔距离   let y =              (isDown ? idx + 1 : list.length - idx) * height -              (isDown ? -idx : idx) * height * this.intervalH;          

当顶面宽度为0时即为四灵锥。

当顶面宽底面窄时,即可形成倒金字塔

2.金字塔立体化

可以看到,单纯的一种颜色,让金字塔看起来不太立体,这时候需要给每个面设置同色系的相近颜色,通过每个面的颜色差来达到这种效果。

四棱台有六个面,四棱椎有五个面,那么就取五颜色值,侧面的四个面分别一个颜色,顶面和底面一个颜色。

js

/** * 获取暗色向渐变颜色 * @param {string} color 基础颜色 * @param {number} step  数量 * @returns {array} list 颜色数组 */exportfunctiongetShadowColor(color, step) {  let c = getColor(color);  let { red, blue, green } = c;  console.log('%ccolor', `background:${color}`);  const s = 0.8;  const r = parseInt(red * s),    g = parseInt(green * s),    b = parseInt(blue * s);  console.log('%cshadow', `background:rgb(${r},${g}, ${b})`);  const rr = (r - red) / step,    gg = (g - green) / step,    bb = (b - blue) / step;  let list = [];  for (let i = 0; i < step; i++) {    list.push(      `rgb(${parseInt(red + i * rr)},${parseInt(green + i * gg)},${parseInt(blue + i * bb)})`    );  }  return list;}//获取颜色系exportfunctiongetDrawColors(cs, cLen) {  let list = [];  for (let i = 0; i < cs.length; i++) {    list.push(getShadowColor(cs[i], cLen));  }  return list;}this.cLen=5;this.colors = getDrawColors(that.colors, this.cLen);

给每个面的三角形设置对应材质索引materialIndex,注意,四棱椎与四棱台的面数是不同的,但画面的顺序是相同的,先画侧面,再画顶面和底面

js

if (idx == 0) {//四棱椎              geometry.faces.forEach((f, fIdx) => {                if (fIdx < 28) {                  geometry.faces[fIdx].materialIndex = parseInt(fIdx / 7);                } else {                  geometry.faces[fIdx].materialIndex = 3;                }              });            } else {            //四棱台              geometry.faces.forEach((f, fIdx) => {                if (fIdx < 32) {                  geometry.faces[fIdx].materialIndex = parseInt(fIdx / 8);                } else {                  geometry.faces[fIdx].materialIndex = 4;                }              });            }                         let cs = this.colors[idx % this.colors.length];            let ms = [];            for (let k = 0; k < cs.length; k++) {              ms.push(getBasicMaterial(THREE, cs[k]));            }            let mesh = newTHREE.Mesh(geometry, ms);

四棱椎每个侧面有7个三角形组成,前28个三角形都是侧面。

四棱台每个侧面有8个三角形组成,前32个三角形是侧面

这样看起来终于有了3D的效果了。

3.加上精灵文本

js

/** * 生成文本canvas * @param {array} textList [{text:文本,color:文本颜色}] * @param {number} fontSize 字体大小 * @returns */exportfunctiongetCanvasTextArray(textList, fontSize) {  const canvas = document.createElement('canvas');  const ctx = canvas.getContext('2d');  ctx.font = fontSize + 'px Arial';  let textLen = 0;  textList.forEach((item) => {    let w = ctx.measureText(item.text + '').width;    if (w > textLen) {      textLen = w;    }  });  canvas.width = textLen;  canvas.height = fontSize * 1.2 * textList.length;  ctx.clearRect(0, 0, canvas.width, canvas.height);  ctx.font = fontSize + 'px Arial';  textList.forEach((item, idx) => {    ctx.fillStyle = item.color;    ctx.fillText(item.text, 0, fontSize * 1.2 * idx + fontSize);  });  return canvas;}/** *生成多行文本精灵材质 * @param {THREE.js} THREE * @param {array} textlist 文本颜色数组 * @param {number} fontSize 字体大小 * @returns */exportfunctiongetTextArraySprite(THREE, textlist, fontSize) {  //生成五倍大小的canvas贴图,避免大小问题出现显示模糊  const canvas = getCanvasTextArray(textlist, fontSize * 5);  return { ...getCanvaMat(THREE, canvas, 0.1), canvas };}let textList = [              { text: item.name, color: fontColor },              { text: item.value + '', color: fontColor }            ];            const { mesh: textMesh } = getTextArraySprite(THREE, textList, height * 0.5);            textMesh.material.depthTest = false;            textMesh.name = 'f' + idx;            textMesh.position.z = idx == 0 ? width : (idx + 0.5) * width;            textMesh.position.y = y;            textMesh.position.x = 0;            this.objGroup.add(textMesh);

canvas文本贴图一定要放大倍数,否则会出现近看模糊

4.使用

js

var myPyramid = newMyPyramid();      window.myPyramid = myPyramid;      myPyramid.initThree(document.getElementById('canvas'));      myPyramid.createChart({        //颜色        colors: ['#fcc02a', '#f16b91', '#187bac'],        //数据        data: [          { name: '小学', value: 100 },          { name: '中学', value: 200 },          { name: '大学', value: 300 }        ],        //是否倒金字塔        isDown: false,        //每层高度        pHeight: 40,        //递增宽度        pWidth: 20,        //字体颜色        fontColor: 'rgb(255,255,255)',        //相机位置        cameraPos: {          x: 178.92931795958233,          y: 210.63511436762354,          z: 357.5498605603872        },        //控制器位置        controlsPos: {          x: -4.895320674125236,          y: 27.139140036227758,          z: 1.5576536521931232        }      });

5.渐变3D金字塔

可能上面的效果有点不够设计感,那么就来点好看的渐变色吧!

获取一个比当前颜色浅的亮色

js

getLightColor(color) {          let c = getColor(color);          let { red, blue, green } = c;          console.log('%ccolor', `background:${color}`);          const l = 0.5;          const r = red + parseInt((255 - red) * l),            g = green + parseInt((255 - green) * l),            b = blue + parseInt((255 - blue) * l);          console.log('%clight', `background:rgb(${r},${g}, ${b})`);          return`rgb(${r},${g}, ${b})`;        }

渐变shader

c++

uniform vec3 topColor; //顶面颜色  uniform vec3 bottomColor;//底面颜色      varying vec2 vUv;        varying vec3 vNormal;  voidmain() {         if(vNormal.y==1.0){//顶面          gl_FragColor = vec4(topColor, 1.0 );        }elseif(vNormal.y==-1.0){//底面          gl_FragColor = vec4(bottomColor, 1.0 );        }else{//根据uv的y坐标混合两种颜色,形成渐变          gl_FragColor = vec4(mix(bottomColor,topColor,vUv.y), 1.0 );        } 	}

获取渐变ShaderMaterial

js

exportfunctiongetGradientShaderMaterial(THREE, topColor, bottomColor) {  const uniforms = {    topColor: { value: newTHREE.Color(getRgbColor(topColor)) },    bottomColor: { value: newTHREE.Color(getRgbColor(bottomColor)) }  };  returnnewTHREE.ShaderMaterial({    uniforms: uniforms,    vertexShader: vertexShader,    fragmentShader: barShader,    side: THREE.DoubleSide  });}

将材质换成渐变材质

js

let cs = that.colors[idx % that.colors.length];            let ms = getGradientShaderMaterial(THREE, this.getLightColor(cs), cs);            let mesh = newTHREE.Mesh(geometry, ms);

Github地址

https://github.com/xiaolidan00/my-three

相关文章
|
5月前
|
JavaScript
js实现图片3D轮播效果(收藏)
js实现图片3D轮播效果(收藏)
62 0
|
5月前
three.js的3D模型渲染主要构成
three.js的3D模型渲染主要构成
98 0
|
JavaScript 前端开发 索引
用Three.js搞个炫酷3D地球
地球人怎么可以不会画地球!从canvas画地球贴图开始,用Three.js手把手教你实现一个炫酷的3D地球!
用Three.js搞个炫酷3D地球
基于three.js的牛逼轰轰的3D编辑器nunuStudio!
这是一款基于Three.js的3D编辑器,我之前一直喊错,叫人家"牛牛",因为我觉得它真的好牛,其实人家正确拼音喊“努努”! 可以发布web的运行包,直接可以网页端二次开发,真的不要太方便了!
基于three.js的牛逼轰轰的3D编辑器nunuStudio!
|
JavaScript 定位技术
原生 js 实现类 3d 地图大屏展示自动高亮轮播、显示悬浮提示 tootip 的方案:svg + popper.js 定位引擎
原生 js 实现类 3d 地图大屏展示自动高亮轮播、显示悬浮提示 tootip 的方案:svg + popper.js 定位引擎
321 0
原生 js 实现类 3d 地图大屏展示自动高亮轮播、显示悬浮提示 tootip 的方案:svg + popper.js 定位引擎
|
2月前
|
编解码 缓存 算法
Three.js如何降低3D模型的大小以便更快加载
为加快600MB的3D模型在Three.js中的加载速度,可采用多种压缩方法:1) 减少顶点数,使用简化工具或LOD技术;2) 压缩纹理,降低分辨率或转为KTX2等格式;3) 采用高效文件格式如glTF 2.0及draco压缩;4) 合并材质减少数量;5) 利用Three.js内置优化如BufferGeometry;6) 按需分批加载模型;7) Web Workers后台处理;8) 多模型合并减少绘制;9) 使用Texture Atlas及专业优化工具。示例代码展示了使用GLTFLoader加载优化后的模型。
310 12
|
2月前
|
存储 JavaScript 前端开发
小白实战!用JS实现一个3D翻书效果,附上代码
小白实战!用JS实现一个3D翻书效果,附上代码
|
2月前
|
存储 JavaScript 前端开发
使用JS创造一个3D粒子化星空,十分酷炫,大家快进来看看吧
使用JS创造一个3D粒子化星空,十分酷炫,大家快进来看看吧
|
5月前
|
JavaScript 开发工具 git
Three.js第1篇,Three.js新手教学,如何在项目中使用Three.js(three.js使用流程详细,three.js的使用方式,three.js创建3d物体)
Three.js封装了WebGL的底层细节,是一款运行在浏览器中的 3D 引擎,可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象,目前在Git上已经拥有90k+的star。
118 0
Three.js第1篇,Three.js新手教学,如何在项目中使用Three.js(three.js使用流程详细,three.js的使用方式,three.js创建3d物体)
|
JavaScript 前端开发 CDN
JavaScript 实现 3D 模型
JavaScript 实现 3D 模型
137 0