【Vue2+ThreeJS踩坑记录(二)】fbx蒙皮网格模型挂载ShaderMaterial材质之后,挂载动画无效的解决办法

博客内容讲述了在使用THREE.js加载FBX模型时,由于ShaderMaterial导致模型动画失效的问题。通过分析发现,官方其他材质的shader中包含了实现动画顶点变化的库。为了解决这个问题,作者获取并展示了原生的基本着色器代码,并进行了优化,创建了一个自定义的Lambert漫反射效果,从而恢复了模型的动画功能。最后,给出了修改后的顶点和片段着色器代码,以及修复后的模型展示结果。
摘要由CSDN通过智能技术生成

错误出现情况(描述,代码与截图如下)

  showModel.children[1].material = new THREE.ShaderMaterial();

在这里插入图片描述
代码没问题,使用的是官方api,不存在shader问题和语法问题,但是fbx上挂载的动画失效。但是使用官方提供的其他材质却没用问题(如MeshBasicMaterial)。那是为什么呢?

错误出现原因

因为官方提供的其他材质shader中,引用了其他其他库,以此来实现动画引起的蒙皮模型顶点的变化,要不然的话,就算动画挂载fbx模型上,也不会有任何变化(没想到,你这个shader连这个都要解决)。

错误解决方法

官方能引用其他库实现模型动画顶点变化,自然你可以引入这些库实现这个效果。使用如下代码就可以获取到官方的顶点和片段着色器代码

  //获取原生shader代码
                let fragStr=THREE.ShaderLib["basic"].fragmentShader;
                let VertStr=THREE.ShaderLib["basic"].vertexShader;
                console.log(fragStr);
                console.log(VertStr);
获取的顶点着色器代码如下
#include <common>
#include <uv_pars_vertex>
#include <uv2_pars_vertex>
#include <envmap_pars_vertex>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <morphtarget_pars_vertex>
#include <skinning_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
void main() {
	#include <uv_vertex>
	#include <uv2_vertex>
	#include <color_vertex>
	#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 <morphtarget_vertex>
	#include <skinning_vertex>
	#include <project_vertex>
	#include <logdepthbuf_vertex>
	#include <clipping_planes_vertex>
	#include <worldpos_vertex>
	#include <envmap_vertex>
	#include <fog_vertex>
}
获取的片段着色器代码如下
uniform vec3 diffuse;
uniform float opacity;
#ifndef FLAT_SHADED
	varying vec3 vNormal;
#endif
#include <common>
#include <dithering_pars_fragment>
#include <color_pars_fragment>
#include <uv_pars_fragment>
#include <uv2_pars_fragment>
#include <map_pars_fragment>
#include <alphamap_pars_fragment>
#include <alphatest_pars_fragment>
#include <aomap_pars_fragment>
#include <lightmap_pars_fragment>
#include <envmap_common_pars_fragment>
#include <envmap_pars_fragment>
#include <fog_pars_fragment>
#include <specularmap_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>
void main() {
	#include <clipping_planes_fragment>
	vec4 diffuseColor = vec4( diffuse, opacity );
	#include <logdepthbuf_fragment>
	#include <map_fragment>
	#include <color_fragment>
	#include <alphamap_fragment>
	#include <alphatest_fragment>
	#include <specularmap_fragment>
	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
	#ifdef USE_LIGHTMAP
		vec4 lightMapTexel = texture2D( lightMap, vUv2 );
		reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;
	#else
		reflectedLight.indirectDiffuse += vec3( 1.0 );
	#endif
	#include <aomap_fragment>
	reflectedLight.indirectDiffuse *= diffuseColor.rgb;
	vec3 outgoingLight = reflectedLight.indirectDiffuse;
	#include <envmap_fragment>
	#include <output_fragment>
	#include <tonemapping_fragment>
	#include <encodings_fragment>
	#include <fog_fragment>
	#include <premultiplied_alpha_fragment>
	#include <dithering_fragment>
}

如上所述,代码其实引入很多无用的库,可以去掉进行优化,这里我直接用了我自己的代码,实现一个Lambert漫反射效果(自用的话可以去掉那部分,代码如下)

修改之后的顶点着色器代码如下
#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);
	
}

修正之后的结果为如下图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值