基于threejs的商品VR展示平台的设计与实现思路

简介: 本设计针对目前互联网销售传统展示的现状,考虑当前市场形式,利用虚拟现实技术理论,结合计算机网络、交互设计实现一个以普通终端浏览器为载体的适用于用户或消费者需求的VR展示平台系统,打造一种全新的商品展示方式,拉近用户或者消费者于商品的距离,提供商品全面的信息,提高商品的可信度,降低交易失败的风险,带来一次愉快完美的购物体验。

基于threejs的商品VR展示平台的设计与实现思路

前言

     本设计针对目前互联网销售传统展示的现状,考虑当前市场形式,利用虚拟现实技术理论,结合计算机网络、交互设计实现一个以普通终端浏览器为载体的适用于用户或消费者需求的VR展示平台系统,打造一种全新的商品展示方式,拉近用户或者消费者于商品的距离,提供商品全面的信息,提高商品的可信度,降低交易失败的风险,带来一次愉快完美的购物体验。

本文仅仅展示部分核心内容点击资源下载 查看更多

整个VR商品展示平台系统的最核心的部分是VR引擎部分,是虚拟现实系统的最核心的地方。在浏览器和Threejs以及云数据库做储存的支持下处理和产生三维立体的虚拟空间环境,使得浏览者有了身临其境的“沉浸感”和人机交互的能力。

vr模型制作演示

总体开发方案设计

      根据当前互联网销售行业的现状的展示方面的不足和局限,从新生一代的消费群体的消费观念以及需求进行了设计,设计出一种全新的设计思路,其扩展性、适用性和交互性得到了充分的体现。总体设开发设计思维导图如下图所示:

网络异常,图片无法展示
|

总体开发设计思维导图

  • 对于企业用户,该平台实现如下的功能:可以加载产品模型,可以将制作的三维模型添加到特定的虚拟环境中,前提是符合系统平台支持的文件格式的三维模型文件;可以构建3D模型组件信息库,即企业或商家将商品的3D模型导入到该平台中,平台将该模型中各个组件模型的关联信息与构成信息,封装存储在云存储中,以便日后组合使用;设定模型组件之间的关系,即企业或者商家可以通过一些简单的便捷的操作的方式建立组件间的关系,形成树状结构;可以设定组件运动行为参数,即企业或者商家可以设定模型的分解状态;设定组件的文字说明信息,即企业或者商家可以对组件添加商品文字信息说明,或者重新命名,或者添加一些参数,设定和编辑顾客用户自定义的信息,即企业或商家可以设定顾客用户自定义的权限;方便快捷的在线编辑功能,即提供一个在线编辑器功能,可以供商家实时修改,实时预览,简单操作即可完成商品模型的制作,商品模型的运动分解参数,商品信息的添加等。
  • 对于顾客用户来说,该平台如下的功能:任意调整观察点,即顾客用户在可以随意角度浏览该VR商品展示平台上的商品;获取模型组件的信息,即顾客用户以鼠标点击或者手指触摸的方式,触发查看商品模型的某个组件模型,同时可以获得该组件模型的名称、尺寸、组成成分等参数;分解展示,即顾客用户以鼠标点击或者手指触摸的方式,决定让商品模型进行分解运动,使该商品模型的内部结构关系展现出来;搭配商品,即顾客用户可以选择商品的一些规格参数,比如口味,尺寸大小等;个性化定制,即顾客用户可以对商品模型进行自定义设置。

平台整体架构核心

  平台整体架构核心如下图所示,其核心主要有四个部分组成,分别是模型制作模块后台管理模块数据存储模块前端展示模块

网络异常,图片无法展示
|

模型制作模块

     模型制作模块,主要又分为模型导入和模型编辑,让企业或商家块可以进行商品模型和材质的导入、商品模型的重命名、商品模型组件的分解运动的设定、商品信息的录入修、商品模型和材质的关联设定等。

前端展示模块

      前端展示模块,主要面向顾客,给顾客展示商品的信息,商家动态,商品购买的方式等,在VR商品展示中能够任意的改变观察的角度,视点的距离,将商品模型进行分解展示,更好地了解和认识想要了解的商品信息和特征,并且可以对商品模型进行一定的修改,满足不同顾客的不同个性化需求。主要分为商品展示、模型交互展示和模型自定义。

存储模块

存储模块,所有的商品数据,商品模型数据,商品材质纹理,顾客自定义的信息,商品交易等都将存放到存储模块中。

后端管理模块

     后端管理模块的功能主要是供给企业对商品的增删改查,前端展示网站的设置,活动的设定,商品售后处理管理,订单管理,商品数据的统计分析以及模型的管理和信息的设置等。

根据预期实现目标和制定的总体开发方案,以太泗蒂艺术蛋糕为实例,分别实现了后台管理、商品模型制作、数据存储和前端展示。

后台管理实现

      后台管理主要用到了Vue框架和Element UI组件实现包括主界面登录界面商品管理商品列表订单管理网站管理数据管理等,便于商家用户管理商品,管理订单和管理商品模型。★ 主界面:一进入后台管理,就将给商家关心的订单数据,访问数据,营销统计图表等展示出来。便于商家快速直观获得,平台运营概况以及待办事项。后台管理的首页界面效果图如下图所示:

网络异常,图片无法展示
|

★ 商品列表:当企业或者商家点击商品列表,那么后台管理系统将会把当前所有的商品信息以表格形式展示出来,便于企业或者商家快捷的对自家的商品集中查看,批量处理。同时也可以点击操作栏对单个商品进行编辑或删除,同时支持多关键字筛选功能,可以输入商品名称、商品的分类,或者商品的唯一ID作为关键字,快速查找想要处理的商品。商品列表效果图如下图所示:

★ 订单管理:点击订单管理,可以及时获取最新的订单,用户自定义商品信息,维权信息等(页面效果与商品列表相似,就不再展示)。★ 数据分析:点击数据分析,可以获取近段时间的商品或者历史信息相关的分析统计信息,收益统计,客户端访问情况等。★ 网站管理:点击网站管理,可以对网站的一些展示模块信息模块进行管理(例如:首页banner、新品展示等),可以发通知公告,管理留言信息,制定商品的营销方式,管理买家秀等。

网络异常,图片无法展示
|

商品模型制作

在制作商品模型制作主要分为前期准备环境搭建组件制作模型合成等步骤,如下图所示。

网络异常,图片无法展示
|

商品模型前期准备

      在制作商品模型前,当然是需要做一点准备工作,需要了解商品模型的原型(以太泗蒂艺术蛋糕的一款蛋糕为例,如下图所示 上图为商品实物,下图为模型),并了解原型的真实结构(如:单层或是双层,是否含有夹层等)、组成成分(如:胚子为慕斯还是传统蛋糕胚子;夹层为布丁或水果)、商品属性(包括颜色、形状、口味、口感、尺寸)、适宜人群、适合场景等,收集原料信息等相关参数,分析产品建模方式,根据预计效果针对性的去采集该商品的局部细节图或纹理,用于制作商品模型的局部UV贴图等,更好的将商品模型制作出来。

网络异常,图片无法展示
|
网络异常,图片无法展示
|

商品模型展示环境搭建

      商品模型的虚拟展示环境主要色调为冷色调的黑色,与实例太泗蒂艺术蛋糕的主营商品:慕斯蛋糕属于一种奶冻式的甜点,口感冰凉细腻相符合。虚拟展示环境的视点相机设置Perspective Camera ,即透视投影照相机,投影方式为远景投影,为人眼看世界的模式;将相机的视点位置设置在整个渲染场景略高处,目的是达到人眼俯视效果。虚拟环境中设置一个圆形镜面,与蛋糕制作的工作台相似,再在上面搭建一个长方形半透明托盘,用于放置蛋糕的3D模型。然后在圆形镜面的周围设置4个颜色不相同的PointLight(点光源),作为虚拟环境中商品模型的展射灯,分别位于东西南北四个方位。最后给创建好的三维虚拟环境绑定一个OrbitControls(场景控制器)。设置一个监听器去实时监听,虚拟环境中发生变化,及时更新渲染虚拟环境,这里调用浏览器自带的API,requestAnimationFrame函数,由浏览器内核去决定该函数的回调函数的执行时机,有60Hz的刷新频率,那么每次刷新的间隔中会执行一次回调函数,不会引起丢帧,不会卡顿,它与曾经使用频率很高的setTimeout函数相比而言,更节约CPU性能,更加流畅。场景搭建完成效果如下图所示。

网络异常,图片无法展示
|

商品模型组件制作

      根据蛋糕商品的原型以及相关信息,开始制作蛋糕的3D模型。对于常用的基础模型Threejs已经集成封装好了,但是稍微特殊一点的模型就需要单独去制作。一个3D模型,本质上由无数的点组成,点可以组成线,而三个不在一条直线上的点,就可以组成一个三角形的面,无数的三角形的面就可以通过一定的组合和排列组成各种各样丰富的网络结构或者说网络模型,我们一般称它为Mesh模型。给Mesh模型贴上纹理,就变成了3D模型。以制作空心圆柱体为例,以原点为中心,固定Y轴在ZOX平面通过Math.sin函数画圆,就会形成一圈点,然后再沿着Y轴一层一层叠加,就会构成一个圆柱面,然后减小画圆的半径,形成另一个圆柱面,此时一个空心圆柱的内外壁面就完成了。当然现在还是一圈一圈的散点,然后根据一定规则将每三个点构成一个一个的小三角形,每个小三角形环环相扣,就完成了Mesh模型的创建,然后将内外壁面的边缘的点按照一定的规则链接起来,最后利用片元着色器将三角形填充或者填充上纹理。至此,一个空心圆柱模型就制作完成了。添加到虚拟环境中进行渲染。就能看见一个空心圆柱体。如图下图所示:

网络异常,图片无法展示
|

//制作空心圆柱源码varHollowBufferCylinder=function (radiusTop, radiusBottom, radiusStep, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength, phiSegments) {
BufferGeometry.call(this);
this.type='HollowBufferCylinder';
this.parameters= {
radiusTop: radiusTop,
radiusBottom: radiusBottom,
radiusStep: radiusStep,
height: height,
radialSegments: radialSegments,
heightSegments: heightSegments,
openEnded: openEnded,
thetaStart: thetaStart,
phiSegments: phiSegments,
thetaLength: thetaLength  };
varscope=this;
radiusTop=radiusTop!==undefined?radiusTop : 10;
radiusBottom=radiusBottom!==undefined?radiusBottom : 10;
height=height||10;
radiusStep=radiusStep||2radialSegments=Math.floor(radialSegments) ||8;
heightSegments=Math.floor(heightSegments) ||1;
phiSegments=Math.floor(phiSegments) ||8;
openEnded=openEnded!==undefined?openEnded : false;
thetaStart=thetaStart!==undefined?thetaStart : 0.0;
thetaLength=thetaLength!==undefined?thetaLength : Math.PI*2;
varindices= [];
varvertices= [];
varnormals= [];
varuvs= [];
vararr= [];
varindex=0;
varhalfHeight=height/2;
vargroupStart=0;
generateTorso(true);//InsidegenerateTorso(false);//Outsideif (radiusTop>0) generateCap(true);
if (radiusBottom>0) generateCap(false);
generateTorsoSide(true);
generateTorsoSide(false);
this.setIndex(indices);
this.setAttribute('position', newFloat32BufferAttribute(vertices, 3));
this.setAttribute('normal', newFloat32BufferAttribute(normals, 3));
this.setAttribute('uv', newFloat32BufferAttribute(uvs, 2));
functiongenerateTorso(inside) {
varx, y;
varnormal=newVector3();
varvertex=newVector3();
varindexArray= [];
vargroupCount=0;
varslope= (radiusBottom-radiusTop) /height;
for (y=0; y<=heightSegments; y++) {
varindexRow= [];
varv=y/heightSegments;
varradius=inside?v* (radiusBottom-radiusTop) +radiusTop-radiusStep : v* (radiusBottom-radiusTop) +radiusTop;
for (x=0; x<=radialSegments; x++) {
varu=x/radialSegments;
vartheta=u*thetaLength+thetaStart;
varsinTheta=Math.sin(theta);
varcosTheta=Math.cos(theta);
vertex.x=radius*sinTheta;
vertex.y=-v*height+halfHeight;
vertex.z=radius*cosTheta;
vertices.push(vertex.x, vertex.y, vertex.z);
normal.set(sinTheta, slope, cosTheta).normalize();
normals.push(normal.x, normal.y, (inside?1 : -1) *normal.z);
uvs.push(u, 1-v);
indexRow.push(index++);
      }
indexArray.push(indexRow);
    }
for (x=0; x<radialSegments; x++) {
for (y=0; y<heightSegments; y++) {
vara=indexArray[y][x];
varb=indexArray[y+1][x];
varc=indexArray[y+1][x+1];
vard=indexArray[y][x+1];
indices.push(a, b, d);
indices.push(b, c, d);
groupCount+=6;
      }
    }
scope.addGroup(groupStart, groupCount, inside===true?0 : 1);
groupStart+=groupCount;
  }
functiongenerateTorsoSide(sideLeft) {
vargroupCount=0;
vartheta=sideLeft==true?thetaLength+thetaStart : thetaStart;
vertices.push(radiusTop*Math.sin(theta), halfHeight, radiusTop*Math.cos(theta));
normals.push(Math.sin(theta), (sideLeft?1 : -1) *-1, Math.cos(theta));
uvs.push(0, 0);
vertices.push((radiusTop-radiusStep) *Math.sin(theta), halfHeight, (radiusTop-radiusStep) *Math.cos(theta));
normals.push(Math.sin(theta), (sideLeft?1 : -1) *-1, Math.cos(theta));
uvs.push(0, 1);
vertices.push(radiusBottom*Math.sin(theta), -halfHeight, radiusBottom*Math.cos(theta));
normals.push(Math.sin(theta), (sideLeft?1 : -1) *1, Math.cos(theta));
uvs.push(1, 0);
vertices.push((radiusBottom-radiusStep) *Math.sin(theta), -halfHeight, (radiusBottom-radiusStep) *Math.cos(theta));
normals.push(Math.sin(theta), (sideLeft?1 : -1) *1, Math.cos(theta));
uvs.push(1, 1);
vara=index++;
varb=index++;
varc=index++;
vard=index++;
if (sideLeft) {
indices.push(d, c, b);
indices.push(b, a, c);
    } else {
indices.push(a, b, c);
indices.push(c, d, b);
    }
groupCount+=6;
scope.addGroup(groupStart, groupCount, sideLeft===true?4 : 5);
groupStart+=groupCount;
  }
functiongenerateCap(top) {
varx, centerIndexStart, centerIndexEnd;
varuv=newVector2();
varvertex=newVector3();
vargroupCount=0;
varouterRadius= (top===true) ?radiusTop : radiusBottom;
varsign= (top===true) ?1 : -1;
varsegment;
varradius=outerRadius-radiusStep;
varj, i;
centerIndexStart=index;
for (j=0; j<=phiSegments; j++) {
for (i=0; i<=radialSegments; i++) {
egment=thetaStart+i/radialSegments*thetaLength;
vertex.x=radius*Math.sin(segment);
vertex.y=halfHeight*sign;
vertex.z=radius*Math.cos(segment);
vertices.push(vertex.x, vertex.y, vertex.z);
normals.push(0, sign, 0);
uv.x= (vertex.x/outerRadius+1) /2;
uv.z= (vertex.z/outerRadius+1) /2;
uvs.push(uv.x, uv.z);
index++;
      }
radius+=radiusStep/phiSegments;
    }
for (j=0; j<phiSegments; j++) {
varradialSegmentLevel=j* (radialSegments+1);
for (i=0; i<radialSegments; i++) {
segment=i+radialSegmentLevel;
vara=centerIndexStart+segment;
varb=centerIndexStart+segment+radialSegments+1;
varc=centerIndexStart+segment+radialSegments+2;
vard=centerIndexStart+segment+1;
indices.push(a, b, d);
indices.push(b, c, d);
groupCount+=6;
      }
    }
scope.addGroup(groupStart, groupCount, top===true?2 : 3);
groupStart+=groupCount;
  }
}

模型在线编辑功能实现

     为便于管理者制作和修改商品模型,所以需要一个在线编辑功能,即在线编辑器,可以供商家实时修改,实时预览,通过简单的鼠标点击拖动和键盘输入等操作即可完成对商品模型的编辑制作、分解运动参数的设置、模型各部分详细信息的添加编辑和设置顾客用户可自定义的组件(如下图所示),无需专业的建模师就能对商品模型进行制作,极大节约了企业的建模成本。该在线编辑器主要分四个模块,分别为 实时预览模块功能模块树形结构展示模块模型编辑模块

网络异常,图片无法展示
|

模型轮廓高亮实现

      为了给用户带来更加友好,愉快的浏览体验,以及对商品的组成成分(模型组件)的直观了解,采用广度优先搜索算法与并查集算法,获取同类别组成成分(同编号模型组件),加入选定对象数组(selectedObjects),实时进行高亮渲染选定数组中的模型组件对象。

网络异常,图片无法展示
|

模型分解运动的实现

     为了给用户对商品的内部构成(模型组件)的直观详细的了解,实现一个模型分解功能,将商品模型内部无法观察的部分展示出来,用户点击分解按钮,商品模型开始按照每个模型的分解运动参数(下表所示)进行分解运动。分解运动参数保存在每一个模型组件的userData对象中,其中属性id的值决定该模型组件是否分解运动模型,id值两位数以下,为分解运动模型,三位数以上则为随动分解运动模型或不分解运动模型;sO(speed Orientation)代表运动方向,采用三位二进制表示,对应坐标轴的XYZ,例如4(100)代表沿着X正向运动,-2(-010)代表沿着-Y轴运动。sV(speed Velocity)代表运动的速度(范围1-100)。值越大,该模型组件的分解运动速度越快。sI(speed Increment)代表运动增量,决定分解运动的最终增加的距离,及原位置的相对位移大小。当用户点击合成按钮时,通过反向运动得以复原。

网络异常,图片无法展示
|

//解析函数源码 functionComponent(_Group, modelsConfig) {  // 解析器函数for (leti=0; i<modelsConfig.length; i++) {
if (modelsConfig[i].Nid) continue;
var_M=modelsConfig[i].ChildrenModel&&modelsConfig[i].Type=="Group"?buildGroup(modelsConfig[i]) : buildModel(modelsConfig[i]);
_MinstanceofArray?addArray(_Group, _M) : _Group.add(_M);
  }
}
functionbuildGroup(GConfig) {
/*创模型组*/var_G=newTHREE.Group();
/*模组名称*/_G.name=GConfig.Name;
/*模组数据*/GConfig.UserData?_G.userData=GConfig.UserData : "";
/*模组位置*/GConfig.Position?_G.position.set(GConfig.Position[0], GConfig.Position[1], GConfig.Position[2]) : "";
/*模组方向*/GConfig.Rotate?_G.rotation.set(GConfig.Rotate[0] /180*Math.PI, GConfig.Rotate[1] /180*Math.PI, GConfig.Rotate[2] /180*Math.PI) : '';
/*模组缩放*/GConfig.Scale?_G.scale.set(GConfig.Scale[0], GConfig.Scale[1], GConfig.Scale[2]) : "";
/*模组组件*/for (leti=0; i<GConfig.ChildrenModel.length; i++) {
if (GConfig.ChildrenModel[i].Nid) continue;
var_M=GConfig.ChildrenModel[i].ChildrenModel&&GConfig.ChildrenModel[i].ChildrenModel.Type=="Group"?buildGroup(GConfig.ChildrenModel[i]) : buildModel(GConfig.ChildrenModel[i]);
_MinstanceofArray?addArray(_G, _M) : _G.add(_M);
  }
/*组件克隆*/if (GConfig.CloneList) {
varcloneList= [_G];
for (leti=0; i<GConfig.CloneList.length; i++) {
cloneList.push(cloneModel(_G, GConfig.CloneList[i]));
    }
returncloneList;
  }
return_G}
functionbuildModel(MConfig) {
/*材料*/var_Material=MConfig.Material.Color.indexOf(".") !=-1?newTHREE['MeshBasicMaterial']({ map: newTHREE.ImageUtils.loadTexture(MConfig.Material.Color) }) : newTHREE['MeshBasicMaterial']({ color: MConfig.Material.Color }); MConfig.Side?_Material.side=THREE.DoubleSide : '';
/*两面都显示*/MConfig.Material.Others?setOthers(_Material, MConfig.Material.Others) : "";
/*几何*/var_Geometry=newTHREE[MConfig.Type](MConfig.Paramete[0], MConfig.Paramete[1], MConfig.Paramete[2], MConfig.Paramete[3], MConfig.Paramete[4], MConfig.Paramete[5], MConfig.Paramete[6], MConfig.Paramete[7], MConfig.Paramete[8], MConfig.Paramete[9]);
/*模型*/var_M=newTHREE.Mesh(_Geometry, _Material);
/*名称*/_M.name=MConfig.Name;
/*位置*/MConfig.Position?_M.position.set(MConfig.Position[0], MConfig.Position[1], MConfig.Position[2]) : "";
/*方向*/MConfig.Rotate?_M.rotation.set(MConfig.Rotate[0] /180*Math.PI, MConfig.Rotate[1] /180*Math.PI, MConfig.Rotate[2] /180*Math.PI) : '';
/*缩放*/MConfig.Scale?_M.scale.set(MConfig.Scale[0], MConfig.Scale[1], MConfig.Scale[2]) : "";
/*数据*/MConfig.UserData?_M.userData=MConfig.UserData : "";
/*其他*/MConfig.Others?setOthers(_M, MConfig.Others) : "";
if (MConfig.ChildrenModel) {
for (leti=0; i<MConfig.ChildrenModel.length; i++) {
if (MConfig.ChildrenModel[i].Cid) continue;
var_CM=MConfig.ChildrenModel[i].ChildrenModel&&MConfig.ChildrenModel[i].ChildrenModel.Type=="Group"?buildGroup(MConfig.ChildrenModel[i]) : buildModel(MConfig.ChildrenModel[i]); _CMinstanceofArray?addArray(_M, _CM) : _M.add(_CM);
    }
  }
if (MConfig.CloneList) {
varcloneList= [_M];
for (leti=0; i<MConfig.CloneList.length; i++) {
cloneList.push(cloneModel(_M, MConfig.CloneList[i]));
    }
returncloneList;
  }
return_M;
}
functioncloneModel(M, CConfig) {
/*克隆母体*/var_C=M.clone();
/*重置位置*/CConfig.Position?_C.position.set(CConfig.Position[0], CConfig.Position[1], CConfig.Position[2]) : "";
/*重置方向*/CConfig.Rotate?_C.rotation.set(CConfig.Rotate[0] /180*Math.PI, CConfig.Rotate[1] /180*Math.PI, CConfig.Rotate[2] /180*Math.PI) : '';
/*重置缩放*/CConfig.Scale?_C.scale.set(CConfig.Scale[0], CConfig.Scale[1], CConfig.Scale[2]) : "";
/*重置数据*/CConfig.UserData?_C.userData=CConfig.UserData : '';
return_C;
}
functionsetOthers(G, M) {
for (varkeyinM) {
G[key] =M[key];
  }
}
functionaddArray(G, M) {
M.forEach(ele=> {
G.add(ele);
  });
}
目录
相关文章
|
数据可视化 物联网 vr&ar
THREE.JS 实现看房自由(VR 看房)
目前随着元宇宙概念的爆火,THREE技术已经深入到了物联网、VR、游戏、数据可视化等多个平台,今天我们主要基于THREE实现一个三维的VR看房小项目
2204 4
|
4月前
|
编解码 网络协议 vr&ar
Android平台下VR头显如何低延迟播放4K以上超高分辨率RTSP|RTMP流
这段内容讲述了VR头显中实现高分辨率视频播放的技术背景与实现方法,并强调了其重要性。高分辨率对于提升VR体验至关重要,它能提供更清晰的画面、增强沉浸感、补偿透镜放大效应,并维持宽广视场角下的图像质量。文中提到的大牛直播SDK具备极低的延迟(200-400ms),支持多种协议与格式,并具有丰富的功能特性,如多实例播放、事件回调、视频及音频格式支持等。此外,提供了基于Unity的播放器示例代码,展示了如何配置播放参数并开始播放。最后,作者指出此类技术在远程控制、虚拟仿真等应用场景中的重要意义。
|
数据采集 编解码 vr&ar
Android平台实现VR头显Unity下音视频数据RTMP推送
随着技术发展的日新月异,虚拟现实产业已经从过去的探索期,自2020年起,慢慢过渡到高速发展期,随着5G时代的到来,大带宽高可靠低延迟网络环境,为虚拟现实产业提供了很好的网络保障,虚拟现实在越来越多的场景下有了应用价值,典型场景如工业互联网、虚拟仿真、文旅文博、智慧交通、智慧能源、智慧医疗、智慧校园、智慧农业等。同事,行业也对清晰度、流畅性和交互感也提出了更高的要求。本文从Android平台的采集推送为例,介绍下基于头显或类似终端的低延迟解决方案。
|
vr&ar 开发工具
一起来云赏月把!three.js实现vr赏月!
一起来云赏月把!three.js实现vr赏月!
235 0
一起来云赏月把!three.js实现vr赏月!
|
传感器 前端开发 vr&ar
三种前端实现VR全景看房的方案!说不定哪天就用得上!(上)
事情是这样的,前几天我接到一个外包工头的新需求,某品牌要搭建一个在线VR展厅,用户可以在手机上通过陀螺仪或者拖动来360度全景参观展厅,这个VR展厅里会有一些信息点,点击之后可以呈现更多信息(视频,图文等)... 我第一反应是用3D引擎,因为我不久前刚用three.js做过一个BMW的在线展厅,基本把three.js摸熟了。
560 0
三种前端实现VR全景看房的方案!说不定哪天就用得上!(上)
|
传感器 移动开发 数据可视化
三种前端实现VR全景看房的方案!说不定哪天就用得上! (下)
事情是这样的,前几天我接到一个外包工头的新需求,某品牌要搭建一个在线VR展厅,用户可以在手机上通过陀螺仪或者拖动来360度全景参观展厅,这个VR展厅里会有一些信息点,点击之后可以呈现更多信息(视频,图文等)... 我第一反应是用3D引擎,因为我不久前刚用three.js做过一个BMW的在线展厅,基本把three.js摸熟了。
1064 0
三种前端实现VR全景看房的方案!说不定哪天就用得上! (下)
|
编解码 自然语言处理 vr&ar
不只是买买买,阿里巴巴还要做最大的 VR 内容平台?|VR站
2016年全球VR生态大会于5月27日在深圳举办,其中有一件值得关注的事情是,会上阿里巴巴VR产品技术负责人杜武平表示,阿里数娱与优酷业务快速融合,双方将在VR项目方面统一布局和统筹规划打造最大VR内容平台。
250 0
不只是买买买,阿里巴巴还要做最大的 VR 内容平台?|VR站
|
编解码 自然语言处理 数据可视化
从行业盘点到未来技术,VR 计算平台的革命正在发生
4月9日(下周六),由 APEC Y星人社区 举办的 全球创新者大会(GIC) 虚拟现实峰会 将在北京举行,演讲嘉宾和参会公司覆盖了 VR 的全产业链(点击「阅读原文」查看会议详细信息及报名),机器之心作为「首席科技媒体」将为大家带来全程报道和深度专访。在这之前,机器之心对 VR 领域进行了详细分析和梳理。
238 0
从行业盘点到未来技术,VR 计算平台的革命正在发生