web 3d场景构建+three.js+室内围墙,仓库,楼梯,货架模型等,第一人称进入场景案例

这篇具有很好参考价值的文章主要介绍了web 3d场景构建+three.js+室内围墙,仓库,楼梯,货架模型等,第一人称进入场景案例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

web 3d场景构建+three.js+室内围墙,仓库,楼梯,货架模型等,第一人称进入场景案例,THREE.JS,web3d,javascript,前端,THREE,3Dweb 3d场景构建+three.js+室内围墙,仓库,楼梯,货架模型等,第一人称进入场景案例,THREE.JS,web3d,javascript,前端,THREE,3D

 

翻到了之前的一个案例,基于three.js做的仓库布局模拟,地图元素除了大模型外,其他都是通过JSON数据解析动态生成的,例如墙体,柱子门口,地标等,集成了第一人称的插件可以第一人称进入场景有需要的可以下载看看,对想入门的朋友应该有一些参考价值。

/**

   *创建自定义几何体

   *输入参数几何体底面逆时针坐标组、几何体高度

   * 目前只支持凸多边形 逆时针则连线,顺时针不连线

   */

function createCustomBufferGeometry(planeArr, height, color) {

    let planes = planeArr;

    let planes2 = [];

    //组装顶面坐标

    for (let i = 0; i < planes.length; i++) {

        planes2.push(new THREE.Vector3(planes[i].x, planes[i].y + height, planes[i].z));

    }

    planes = planes.concat(planes2);

    let arr = [];

    //循环组成三角面

    for (let i = 0; i < planes.length; i++) {

        let j = i + 1, k2 = j + planes2.length;

        let xLength = planes2.length;

        if (j >= planes2.length && i < planes2.length) {

            j = 0; k2 = j + planes2.length;

        }

        if (i >= planes2.length) {

            if (j >= planes.length) {

                j = planes2.length;

            }

            k2 = i - planes2.length;

            xLength = planes.length;

        }

        for (let x = i + 2; x < xLength; x++) {

            arr = arr.concat([planes[i].x, planes[i].y, planes[i].z]);

            arr = arr.concat([planes[j].x, planes[j].y, planes[j].z]);

            arr = arr.concat([planes[x].x, planes[x].y, planes[x].z]);

            // if (((planes[j].x - planes[i].x) * (planes[x].z - planes[i].z) - (planes[x].x - planes[i].x) * ( planes[j].z - planes[i].z)) < 0) {

            //     arr = arr.concat([planes[i].x, planes[i].y, planes[i].z]);

            //     arr = arr.concat([planes[j].x, planes[j].y, planes[j].z]);

            //     arr = arr.concat([planes[x].x, planes[x].y, planes[x].z]);

            // }

        }

        arr = arr.concat([planes[i].x, planes[i].y, planes[i].z]);

        if (i < planes2.length) {

            arr = arr.concat([planes[j].x, planes[j].y, planes[j].z]);

            arr = arr.concat([planes[k2].x, planes[k2].y, planes[k2].z]);

        } else {

            arr = arr.concat([planes[k2].x, planes[k2].y, planes[k2].z]);

            arr = arr.concat([planes[j].x, planes[j].y, planes[j].z]);

        }

    }

    let bufferGeometry = new THREE.BufferGeometry();

    let vertices = new Float32Array(arr);

    // itemSize = 3 因为每个顶点都是一个三元组。

    bufferGeometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));

    bufferGeometry.computeFaceNormals();//计算法向量,会对光照产生影响

    bufferGeometry.computeVertexNormals();//自动设置法向量

    let material = new THREE.MeshLambertMaterial({ color: color });

    let mesh = new THREE.Mesh(bufferGeometry, material);

    _bufferGeometry = bufferGeometry;

    //worldScene.add(mesh);

    return mesh;

}

var _bufferGeometry;

/**

    *地图数据坐标是左上角为原点开始的二维坐标系x,y,绘制以左上角开始

    * web 3d坐标原点是屏幕中心点,绘制的时候也是以中心为相对位置

    * MapXLength:地图最长距离,MapZLength 地图最宽距离

    * 转换规则 3d.position.x =  2d.width/2 -  maxWidth/2 +2d.position.x

    * 3d.position.z = 2d.height/2 - maxHeight/2 +2d.position.z;

    * 3d.position.y y轴高度 2D地图无需设置,默认为0,如果有高度, 3d.position.y =  2d.高度.y/2+2d.高度位置+MapYLength/2

    */

function handCoordinate(data) {

    data.x = data.x / 10;

    data.y = data.y / 10;

    data.z = data.z / 10;

    if (data.positionY)

        data.positionY = data.positionY / 10;

    else

        data.positionY = 0;

    data.width = data.width / 10;

    data.height = data.height / 10;

    data.x = data.width / 2 - MapXLength / 2 + data.x;

    data.z = data.height / 2 - MapZLength / 2 + data.z;

    if (data.groupOption) {

        data.groupOption.offSetX = data.groupOption.offSetX / 10;

        data.groupOption.offSetY = data.groupOption.offSetY / 10;

        data.groupOption.offSetZ = data.groupOption.offSetZ / 10;

    }

}

var _baseBox;

var  _floorType;

//最底层的box

function createBaseBox(data,floorType) {

    data.width = data.width / 10;

    data.height = data.height / 10;

    MapXLength = data.width;

    MapZLength = data.height;

    sizeRatio = MapXLength / MapXLength;

    if(data.floorType){

        _floorType = data.floorType;

        if(!floorModels[floorType])

        {

            floorModels[floorType] = [];

        }

    }

    var geometry = new THREE.BoxBufferGeometry(data.width, 1, data.height);

    var material = new THREE.MeshLambertMaterial({ color: data.color });

    var cube = new THREE.Mesh(geometry, material);

    cube.position.set(0, 0, 0);

    //cube.castShadow = true;//开启投影

    cube.receiveShadow = true;//接收阴影

    cube.geometry.computeBoundingBox();

    _baseBox = cube.geometry.boundingBox;

    clickObjects.push(cube);//加入点击对象组

    worldScene.add(cube);

    floorModels[floorType].push(cube);

    //console.log(cube);

    //地图标注

    //  worldScene.add(createTextTextureBySprite(data))

}

//创建几何体

function createBox(data,_floorType) {

   

    handCoordinate(data);

    var geometry = new THREE.BoxGeometry(data.width, data.y, data.height);

    var material = new THREE.MeshLambertMaterial({ color: data.color, vertexColors: THREE.FaceColors });

    var cube = new THREE.Mesh(geometry, material);

    cube.castShadow = true;//开启投影

    //cube.receiveShadow = true;//接收阴影

    cube.position.set(data.x, 0.55 + data.positionY / 2 + data.y / 2, data.z);

    var newMesh;

    //几何体组合处理

    if (data.bspMesh) {

        newMesh = cube;

        data.bspMesh.forEach(x => {

            handCoordinate(x);

            let tempMesh;

            if (x.geometryType == 'box') {

                tempGeometry = new THREE.BoxGeometry(x.width, x.y, x.height);

                tempMesh = new THREE.Mesh(tempGeometry, new THREE.MeshLambertMaterial({ color: x.color }));

            }

            tempMesh.position.set(x.x, 0.55 + x.positionY / 2 + x.y / 2, x.z);

            newMesh = bspMesh(x.type, newMesh, tempMesh);

        })


 文章来源地址https://www.toymoban.com/news/detail-695790.html

    } else {

    }

    let finalMesh;

    if (newMesh) {

        newMesh.castShadow = true;//开启投影

        // worldScene.add(newMesh);

        finalMesh = newMesh;

    } else {

        finalMesh = cube;

        // worldScene.add(cube);

    }

    //多个相同模型组合

    if (data.type && data.type == 'group') {

        for (let i = 0; i < data.groupOption.total; i++) {

            let tempMesh = finalMesh.clone();

            if (data.groupOption.offSetX != 0) {

                tempMesh.position.x = finalMesh.position.x + (data.width + data.groupOption.offSetX) * i;

            }

            if (data.groupOption.offSetY != 0) {

                tempMesh.position.y = finalMesh.position.y + (data.y + data.groupOption.offSety) * i;

            }

            if (data.groupOption.offSetZ != 0) {

                tempMesh.position.z = finalMesh.position.z + (data.height + data.groupOption.offSetZ) * i;

            }

            // tempMesh.position.set(

            //    ( data.width+tempMesh.position.x+data.groupOption.offSetX)*i,

            //    ( data.y+tempMesh.position.y+data.groupOption.offSetY)*i,

            //     (data.height+tempMesh.position.z+data.groupOption.offSetZ)*i);

            worldScene.add(tempMesh);

            floorModels[_floorType].push(tempMesh);

        }

    } else {

        worldScene.add(finalMesh);

        floorModels[_floorType].push(finalMesh);

    }

    //地图标注

    let sprite = createTextureBySprite(data);

    if (sprite != null)

    worldScene.add(sprite);

}




 

//创建圆柱体

function createCylinder(data) {

    handCoordinate(data);

    var geometry = new THREE.CylinderGeometry(data.width / 2, data.width / 2, data.y, 32);

    var material = new THREE.MeshLambertMaterial({ color: data.color, vertexColors: THREE.FaceColors });

    var cylinder = new THREE.Mesh(geometry, material);

    cylinder.position.set(data.x, 0.55 + data.positionY / 2 + data.y / 2, data.z);

    for (let i = 0; i < 64; i++) {

        geometry.faces[i].color = new THREE.Color('#004892');

    }

    worldScene.add(cylinder);

}

/**

 * 创建网格

 * @param {几何体对象} geometry

 */

function createMesh(geometry, color) {

    if (!color) {

        color = '#4685C6';

    }

    return new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ color: color }));

}

/**

 * A,B模型type:'intersect' 交集  'union' 并集  subtract 差集

 * @param {A模型} geometryA

 * @param {B模型} geometryB

 */

function bspGeometry(type, geometryA, geometryB) {

    //生成ThreeBSP对象

    var a = new ThreeBSP(geometryA);

    var b = new ThreeBSP(geometryB);

    //进行算

    var resultBSP;

    if (type == 'intersect')

        resultBSP = a.intersect(b);

    else if (type == 'union')

        resultBSP = a.union(b);

    else

        resultBSP = a.subtract(b);

    //从BSP对象内获取到处理完后的mesh模型数据

    var result = resultBSP.toGeometry();

    //更新模型的面和顶点的数据

    result.computeFaceNormals();

    result.computeVertexNormals();

    return cresult;

}

/**

 * A,B模型type:'intersect' 交集  'union' 并集  subtract 差集

 * @param {A模型} meshA

 * @param {B模型} meshB

 */

function bspMesh(type, meshA, meshB) {

    //生成ThreeBSP对象

    var a = new ThreeBSP(meshA);

    var b = new ThreeBSP(meshB);

    //进行算

    var resultBSP;

    if (type == 'intersect')

        resultBSP = a.intersect(b);

    else if (type == 'union')

        resultBSP = a.union(b);

    else

        resultBSP = a.subtract(b);

    //从BSP对象内获取到处理完后的mesh模型数据

    var result = resultBSP.toMesh();

    result.material = meshA.material;

    //更新模型的面和顶点的数据

    result.geometry.computeFaceNormals();

    result.geometry.computeVertexNormals();

    testResult = result

    return result;

}

var testResult;



 

/**

 *创建地图标注

 *canvas地图标注的内容很小需要放大,放大会失真,后期调整其缩放大小,或者不采用canvas渲染

 */

function createTextureBySprite(data) {

    if ((data.title == '' && data.imageurl == '') || (!data.title && !data.imageurl)) {

        return null;

    }

    let canvas = document.createElement('canvas');

    canvas.width=3000;

    canvas.height=2000;

   

    let ctx = canvas.getContext('2d');

   

    ctx.lineWidth = 1;

    ctx.textAlign = "center";

    ctx.textBaseline = "middle";

    ctx.textAlign = 'center';

    if (data.font) {

        ctx.font = data.font;

    } else {

        ctx.font = "Normal 180px Arial"

    }

    if (data.textcolor) {

        ctx.fillStyle = data.textcolor;

    }

    //ctx.lineWidth = 4;

    if (data.imageurl) {

        let img = new Image();

        img.src = data.imageurl;

        img.onload = function () {

            ctx.drawImage(img, 30, 90);

            texture.needsUpdate = true;

        }

    }

    /*

    把整个 canvas 作为纹理,所以字尽量大一些,撑满整个 canvas 画布。

    但也要小心文字溢出画布。

    */

    ctx.fillText(data.title, 400, 200);

    let texture = new THREE.CanvasTexture(canvas);

    let material = new THREE.SpriteMaterial({

        map: texture,

        transparent: true, // 避免遮挡其他图形

       // sizeAttenuation:false

    });

    let textMesh = new THREE.Sprite(material);

    /*

    精灵很小,要放大

    */

   textMesh.scale.set(10, 10, 10);

    /*

    WebGL 3D 世界中的位置

    */

    textMesh.position.set(data.x,data.y + 1.5, data.z);//data.y + 3

    return textMesh;

}


 

到了这里,关于web 3d场景构建+three.js+室内围墙,仓库,楼梯,货架模型等,第一人称进入场景案例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • web3d-three.js场景设计器-mesh网格添加多模型-模型描述随动

    给场景中的模型加上广告牌描述,可以在模型的MESH里添加Sprite,配上相应的文字, 描述Sprite的位置则是在mesh中的相对位置,比如模型高10,那么我们可以给一个y等于10 来进行适配,这样在移动模型mesh网格时可以整体移动。 function createBox(data) {   const geometry = new THREE.BoxGeom

    2024年02月21日
    浏览(35)
  • Three.js之创建3D场景

    【G】Three.js官方文档:https://threejs.org/docs/ Three.js是一个流行的WebGL库,官方文档提供了详细的API参考和示例,适合学习和参考。 【G】Three.js GitHub链接:https://github.com/mrdoob/three.js 这是一个流行的基于WebGL的3D图形库,提供了丰富的功能和工具,用于创建交互式的3D场景和应用。

    2024年02月14日
    浏览(30)
  • Three.js教程:第一个3D场景

    推荐:将 NSDT场景编辑器加入你3D工具链 其他工具系列: NSDT简石数字孪生 下面的代码完整展示了通过three.js引擎创建的一个三维场景,在场景中绘制并渲染了一个立方体的效果,为了大家更好的宏观了解three.js引擎, 尽量使用了一段短小但完整的代码实现一个实际的三维效果

    2023年04月12日
    浏览(31)
  • 和我一起学 Three.js【初级篇】:1. 搭建 3D 场景

    💡 本篇文章共 5572 字,最近更新于 2023 年 04 月 19 日。 本系列第 6,7,8 章节支持在我的个人公众号「前端乱步」内付费观看,将在全平台文章「点赞数」+「评论数」 = 500(第 6 章), 1000(第 7,8 章) 时分别解锁发布。 《和我一起学 Three.js【初级篇】:0. 总论》 📍 您当

    2023年04月10日
    浏览(27)
  • 【Three.js基础入门】:创建你的第一个3D场景

    Three.js是一种强大的JavaScript库,用于在Web浏览器中创建交互式的3D图形和动画。无需熟练的图形编程经验,你也可以通过Three.js轻松地构建令人惊叹的3D场景。 本文将带你逐步学习如何入门Three.js,从创建一个简单的3D场景开始。 我们将介绍如何使用Three.js创建你的第一个3D场景

    2024年02月16日
    浏览(38)
  • Vue中如何进行3D场景展示与交互(如Three.js)

    随着WebGL技术的发展,越来越多的网站开始使用3D场景来展示产品、游戏等内容。在Vue中,我们可以使用第三方库Three.js来实现3D场景的展示与交互。本文将介绍如何在Vue中使用Three.js来创建3D场景,并实现交互功能。 Three.js是一个用于创建3D图形的JavaScript库。它基于WebGL技术,

    2024年02月09日
    浏览(39)
  • WEB 3D技术 three.js 点光源

    本文的话 我们来设置一下点光源 点光源其实最直观的就是可以做萤火虫 也可以做星光 点点的效果 我们可以直接在官网中搜索 Pointlight 大家可以在官网这里看一下 其实 SpotLight 聚关灯中的属性 Pointlight 点光源也有的 我们先编写代码如下 PointLight 创建一个点光源 这里我们给了

    2024年01月19日
    浏览(31)
  • WEB 3D技术 three.js 阴影属性

    上文 WEB 3D技术 three.js 光照与阴影 我们说了阴影 那么 我们继续将阴影的属性 目前 我们的代码 目前阴影效果是这样的 我们可以设置它的一个模糊度 我们官网搜索 LightShadow 下面找到 radius 模糊度的一个属性 这里 我们可以 设置 20 的一个模糊度 运行代码 然后看我们的模糊度

    2024年01月22日
    浏览(36)
  • WEB 3D技术 three.js 聚光灯

    本文 我们来说说 点光源和聚光灯 点光源 就像一个电灯泡一样 想四周发散光 而聚光灯就像手电筒一样 像一个方向射过去 距离越远范围越大 光越弱 我们先来看一个聚光灯的效果 我们可以编写代码如下 SpotLight 聚光灯 然后通过 position 设置一下光的位置 运行代码如下 目前看

    2024年01月21日
    浏览(32)
  • WEB 3D技术 three.js 3D贺卡(1) 搭建基本项目环境

    好 今天 我也是在网上学的 带着大家一起来做个3D贺卡 首先 我们要创建一个vue3的项目、 先创建一个文件夹 装我们的项目 终端执行 vue create 项目名称 例如 我的名字想叫 greetingCards 就是 因为这个名录 里面是全部都小写的 然后 下面选择 vue3 然后按下回车 等待项目创建完成

    2024年01月19日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包