mapbox结合threeJS载入3d模型,并实现点击事件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mapbox结合threeJS载入3d模型,并实现点击事件相关的知识,希望对你有一定的参考价值。
参考技术A 加载地图后调用该函数Vue2+ThreeJS工程无痛搭建指南
工程初始化流程
全局安装vue-cli
npm install -g vue-cli
进入目录-初始化项目
vue init webpack my-project
进入项目
cd my-project
安装工程核心包(Three JS)
npm install three
核心功能实现与避坑
fbx载入功能代码实现
//模型初始化
initModelFbx()
console.log('模型加载');
let loader = new FBXLoader();
loader.load(modelPath, function (object)
var mat = modelMat;
console.log(object);
showModel = object;
showModel.position.set(0, -30, 0);
// geometry.center(); //居中显示
showModel.children[1].material = mat;
//获取原生shader代码
let fragStr=THREE.ShaderLib["basic"].fragmentShader;
let VertStr=THREE.ShaderLib["basic"].vertexShader;
console.log(fragStr);
console.log(VertStr);
// showModel.children[1].material=mat;
//添加骨骼辅助
// let meshHelper = new THREE.SkeletonHelper(showModel);
// scene.add(meshHelper);
scene.add(showModel);
console.log(showModel);
console.log(showModel.children[1]);
);
,
fbx载入可能出现THREE.FBXLoader: Cannot find the version number for the file given错误,解决办法为,移动文件到static目录下,具体操作见文章(【Vue2+ThreeJS踩坑记录(一)】)
本地文件载入功能
//本地文件读取
load(name)
let xhr = new XMLHttpRequest(),
okStatus = document.location.protocol === "file:" ? 0 : 200;
xhr.open('GET', name, false);
xhr.overrideMimeType("text/html;charset=utf-8");//默认为utf-8
xhr.send(null);
return xhr.status === okStatus ? xhr.responseText : null;
,
shader代码
顶点着色器代码
#include <common>
#include <skinning_pars_vertex>
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 objectPos;
void main()
#include <morphcolor_vertex>
#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )
#include <beginnormal_vertex>
#include <morphnormal_vertex>
#include <skinbase_vertex>
#include <skinnormal_vertex>
#include <defaultnormal_vertex>
#endif
#include <begin_vertex>
#include <skinning_vertex>
#include <project_vertex>
#include <worldpos_vertex>
vNormal=normal;
vUv = uv;
objectPos= position;
片段着色器代码
#include <common>
uniform vec3 diffuse;
uniform float opacity;
uniform mat4 modelMatrix;
uniform vec3 color;
uniform vec3 lightPosition;
uniform vec3 _mainColor;
uniform sampler2D _mainTex;
uniform sampler2D _normalTex;
uniform vec2 tilling;
uniform float _roughness;
uniform float _roughnessContrast;
uniform float _roughnessInit;
uniform float _roughnessMin;
uniform float _roughnessMax;
varying vec3 objectPos;
varying vec3 vNormal;
varying vec2 vUv;
vec3 ACETompping(vec3 x)
float a=2.51;
float b=.03;
float c=2.43;
float d=.59;
float e=.14;
return saturate((x*(a*x+b))/(x*(c*x+d)+e));
vec4 lerp(vec4 a,vec4 b,vec4 w)
return a+w*(b-a);
float lerpFloat(float a,float b,float w)
return a+w*(b-a);
mat3 cotangent_frame(vec3 N,vec3 p,vec2 uv)
vec3 dp1=dFdx(p);
vec3 dp2=dFdy(p);
vec2 duv1=dFdx(uv);
vec2 duv2=dFdy(uv);
vec3 dp2perp=cross(dp2,N);
vec3 dp1perp=cross(N,dp1);
vec3 T=dp2perp*duv1.x+dp1perp*duv2.x;
vec3 B=dp2perp*duv1.y+dp1perp*duv2.y;
float invmax=inversesqrt(max(dot(T,T),dot(B,B)));
return mat3(T*invmax,B*invmax,N);
vec3 ComputeNormal(vec3 nornal,vec3 viewDir,vec2 uv,sampler2D normalMap)
vec3 map=texture2D(normalMap,uv).xyz;
map=map*255./127.-128./127.;
mat3 TBN=cotangent_frame(nornal,-viewDir,uv);
return normalize(TBN*map);
return(texture2D(normalMap,vUv).rgb-.5)*2.;
void main()
vec3 worldNormal = normalize( vec3( modelMatrix * vec4( vNormal, 0.0 ) ) );
vec3 worldPosition=(modelMatrix*vec4(objectPos,1.0)).xyz;//获取世界坐标
vec3 vDir=normalize(cameraPosition-worldPosition);
vec3 nDir=ComputeNormal(worldNormal,vDir,vUv*tilling,_normalTex);
vec3 lDir = normalize( lightPosition - worldPosition );
//向量操作
vec3 rvDir=reflect(-vDir,nDir);
float NdotV=dot(nDir,vDir);
float NdotL=dot(nDir,lDir);
//贴图操作
vec3 mainTex=texture2D(_mainTex,vUv).xyz;
vec3 roughnessTex=vec3(1.0,1.0,1.0);
vec3 _roughnessContrasts=vec3(_roughnessContrast,_roughnessContrast,_roughnessContrast);
//粗糙度
float finalRoughness=saturate(pow(roughnessTex,_roughnessContrasts)*_roughnessInit).x;
finalRoughness=lerpFloat(_roughnessMin,_roughnessMax,finalRoughness);
finalRoughness=finalRoughness*(1.7-.7*finalRoughness);
finalRoughness=finalRoughness*6.;
//漫反射模型(兰伯特)
vec3 lambert=vec3(max(0.0,NdotL),max(0.0,NdotL),max(0.0,NdotL));
//最终颜色
vec3 finalColor=(lambert.xyz*_mainColor);
vec3 finalColor_liner=pow(finalColor,vec3(2.2,2.2,2.2));
finalColor=ACETompping(finalColor_liner);
vec3 finalColor_gamma=pow(finalColor,vec3(1./2.2,1./2.2,1./2.2));
gl_FragColor=vec4(finalColor_gamma,1);
这里注意一下,如果不使用#inlcude引用库,可能会导致fbx模型动画无效。具体情况见此文章链接(【Vue2+ThreeJS踩坑记录(二)】fbx蒙皮网格模型挂载ShaderMaterial材质之后,挂载动画无效的解决办法】)
材质初始化
initMat()
fragShaderStr = this.load(shaderPath + `.frag`);
vertexShaderStr = this.load(shaderPath + `.vert`);
modelMat = new THREE.ShaderMaterial(
uniforms:
_mainColor: value: new THREE.Vector3(1.0, 1.0, 1.0) ,
lightPosition: value: new THREE.Vector3(0, -10, 0) ,
tilling: value: new THREE.Vector2(1, 1) ,
_normalTex: value: new THREE.TextureLoader().load("static/texture/Naria/Naria_N.tga") ,
_roughness: value: 1.0 ,
_roughnessContrast: value: 1.06 ,
_roughnessInit: value: 1.92 ,
_roughnessMin: value: 0.0 ,
_roughnessMax: value: 0.7
,
//236,65,65
vertexShader: vertexShaderStr,
fragmentShader: fragShaderStr,
);
,
载入并播放fbx动画
//载入模型动画
initModelAnim()
console.log('动画加载');
let loader = new FBXLoader();
loader.load(animationPath, function (object)
//创建动画混合器,并指定模型,混合器会自动根据指定模型寻找骨骼,并绑定
let mixer = new THREE.AnimationMixer(showModel);
//添加至动画混合器数组
animationMixers.push(mixer);
//挂载动画
showModel.animations.push(object.animations[0]);
//获取动画片
let action = mixer.clipAction(showModel.animations[0]);
//播放动画片
action.play();
);
,
更新动画混合器
if (animationMixers.length > 0)
//遍历并更新所有动画混合器
animationMixers[0].update(clock.getDelta());
工程打包
工程打包之前建议按这篇文章配置(【Vue2+ThreeJS踩坑记录(三)】Vue2打包项目之后,运行本地项目为空白页解决办法)
配置完之后使用如下命名打包
npm run build
案例代码链接
工程链接
DEMO链接(大小为8mb,用的是GitHubPage,可能加载要几分钟)
最终效果图
以上是关于mapbox结合threeJS载入3d模型,并实现点击事件的主要内容,如果未能解决你的问题,请参考以下文章
vite+vue3+threejs实现一个3D模型的展示案例
Web 3D智慧变电站三维工程进度系统-WebGL/Threejs实战开发