Three.js 如何将不透明度贴图添加到着色器材质

Three.js 如何将不透明度贴图添加到着色器材质,three.js,Three.js,我已将ShaderMaterial应用于具有不透明度贴图的glb模型(该模型是人体,不透明度贴图用于创建头发和睫毛),模型材质的参考如下所示- 如你所见-材质是某种辉光效果,所以我设法找到了我所需要的-问题是我不知道如何应用模型不透明度贴图-如果你仔细观察我的结果之间的差异(左图)在右图中-您将看到头发看起来不像它应该的样子-因为不透明度贴图没有应用。。。我想知道ShaderMaterial是否适合这种外观,还是应该使用其他类型的着色器 这是我的物料代码- let m = new THR

我已将ShaderMaterial应用于具有不透明度贴图的glb模型(该模型是人体,不透明度贴图用于创建头发和睫毛),模型材质的参考如下所示-

如你所见-材质是某种辉光效果,所以我设法找到了我所需要的-问题是我不知道如何应用模型不透明度贴图-如果你仔细观察我的结果之间的差异(左图)在右图中-您将看到头发看起来不像它应该的样子-因为不透明度贴图没有应用。。。我想知道ShaderMaterial是否适合这种外观,还是应该使用其他类型的着色器

这是我的物料代码-

  let m = new THREE.MeshStandardMaterial({
  roughness: 0.25,
  metalness: 0.75,
  opacity: 0.3,

  map: new THREE.TextureLoader().load(
    "/maps/opacity.jpg",
    (tex) => {
      tex.wrapS = THREE.RepeatWrapping;
      tex.wrapT = THREE.RepeatWrapping;
      tex.repeat.set(16, 1);
    }
  ),
  onBeforeCompile: (shader) => {
    
    shader.uniforms.s = uniforms.s;
    shader.uniforms.b = uniforms.b;
    shader.uniforms.p = uniforms.p;

    shader.uniforms.glowColor = uniforms.glowColor;
    shader.vertexShader = document.getElementById("vertexShader").textContent;
    shader.fragmentShader = document.getElementById(
      "fragmentShader"
    ).textContent;
    shader.side = THREE.FrontSide;
    shader.transparent = true;
  //  shader.uniforms['alphaMap'].value.needsUpdate = true;

    console.log(shader.vertexShader);
    console.log(shader.fragmentShader);
  },
});
着色器设置:

      <script id="vertexShader" type="x-shader/x-vertex">
    varying vec3 vNormal;
    varying vec3 vPositionNormal;
    void main() 
    {
      vNormal = normalize( normalMatrix * normal ); // 转换到视图空间
      vPositionNormal = normalize(( modelViewMatrix * vec4(position, 1.0) ).xyz);
      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }
  </script>
  <!-- fragment shader a.k.a. pixel shader -->
  <script id="fragmentShader" type="x-shader/x-vertex"> 
    uniform vec3 glowColor;
    uniform float b;
    uniform float p;
    uniform float s;
    varying vec3 vNormal;
    varying vec3 vPositionNormal;
    void main() 
    {
      float a = pow( b + s * abs(dot(vNormal, vPositionNormal)), p );
      gl_FragColor = vec4( mix(vec3(0), glowColor, a), 1. );
    }
  </script>

可变vec3 vNormal;
可变vec3位置正常;
void main()
{
vNormal=规格化(normalMatrix*normal);//转换到视图空间
vPositionNormal=规格化((modelViewMatrix*vec4(位置,1.0)).xyz);
gl_位置=projectionMatrix*modelViewMatrix*vec4(位置,1.0);
}
颜色均匀;
均匀浮动b;
均匀浮动p;
均匀浮球;
可变vec3 vNormal;
可变vec3位置正常;
void main()
{
浮动a=功率(b+s*abs(点(V正常,V位置正常)),p);
gl_FragColor=vec4(混合(vec3(0),glowColor,a),1.);
}

您正在创建一个
MeshStandardMaterial
,但是当您指定新的顶点和片段着色器时,您将覆盖其所有着色器代码,从而使标准材质无效。您应该像链接的演示一样坚持使用
ShaderMaterial
。这将使您的代码更干净:

//获取着色器代码
让vertShader=document.getElementById(“vertexShader”).textContent;
让fragmshader=document.getElementById(“fragmentShader”).textContent;
//构建纹理
让alphaTex=new THREE.TextureLoader().load(“/maps/opacity.jpg”);
alphaTex.wrapps=3.repeat wrapping;
alphaTex.wrapT=3.0;
//字母重复集(16,1);
均匀浮球;
均匀浮动b;
均匀浮动p;
颜色均匀;
均匀vec2重复;
//如果我们要用alphaMap制服,就申报它
二维字母地图;
//别忘了声明UV坐标
可变vec2 vUv;
可变vec3 vNormal;
可变vec3位置正常;
void main()
{
浮动a=功率(b+s*abs(点(V正常,V位置正常)),p);
//带有UV坐标的样本地图。乘以均匀得到重复
浮点a2=纹理2D(字母映射,vUv*重复).r;
//合并两个字母
浮动不透明度=a*a2;
gl_FragColor=vec4(混合(vec3(0),发光颜色,不透明度),1);
}

Marquizzo-感谢您提供的详细解决方案-不幸的是,我无法实现它-我已经将您的更改添加到了-正如您所看到的-我收到了控制台错误-我无法真正调试(自定义材质的新手…)-thanks@RoyBarOn我的错误是,片段着色器应该读取
texture2D().r
,而不仅仅是
texture2D()
。我已经在我的答案中添加了一个工作演示的更新。Marquizzo-谢谢!!!-我想知道如何应用更多的贴图,如凹凸贴图、彩色贴图等。(我会在赏金可用时更新它)@RoyBarOn Colormap与我们做的方式非常相似,
alphaMap
只需再采样一个
vec3 color=texture2D().rgb
来替换
glowColor
。凹凸贴图会更难,因为您必须沿法线置换顶点位置,所以它需要相当多的数学知识。我建议您花一些时间熟悉着色器、它们的语法和一些术语。