【问题标题】:Shader with threejs material not working in aframe具有threejs材料的着色器在框架中不起作用
【发布时间】:2019-03-14 11:27:57
【问题描述】:

我正在尝试通过自定义着色器为在组件内创建的实体添加波浪,但添加着色器后场景立即消失。如果我移除着色器,实体将显示为静态实体。

控制台不会抛出任何错误,所以我不确定出了什么问题

这是一个代码笔:codepen

如果您删除材料属性,实体将被显示。

    <script>
  AFRAME.registerComponent('waves', {
  init: function() {
    var texture = new THREE.TextureLoader().load( "https://cinemont.com/tutorials/zelda/water.png" );
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.set(5, 5);
  this.geometry = new THREE.PlaneBufferGeometry( 4000, 2000, 128, 64 ); 
  this.material = new THREE.MeshPhongMaterial({
   map:texture,
   color: 0xffffff,
   opacity: 1,
   blending: THREE.NoBlending,
   side: THREE.DoubleSide,
   transparent: false,
   depthTest: false,
   wireframe: false 
  });
    var plane = new THREE.Mesh(this.geometry, this.material);
    plane.position.set(0, -400, -300);
    plane.rotation.set(Math.PI / 2, 0, 0);
    var el = this.el;
    el.setObject3D('mesh', plane);
  }
});
</script>
<script>
AFRAME.registerShader('makewaves', {
  schema: {
    color: {type: 'color', is: 'uniform', default: '#0051da'},
    timeMsec: {type: 'time', is: 'uniform'}
  },

  vertexShader: `
#define SCALE 10.0

varying vec2 vUv;

uniform float timeMsec;  

float calculateSurface(float x, float z) {
    float uTime = timeMsec / 1000.0;
    float y = 0.0;
    y += (sin(x * 1.0 / SCALE + uTime * 1.0) + sin(x * 2.3 / SCALE + uTime * 1.5) + sin(x * 3.3 / SCALE + uTime * 0.4)) / 3.0;
    y += (sin(z * 0.2 / SCALE + uTime * 1.8) + sin(z * 1.8 / SCALE + uTime * 1.8) + sin(z * 2.8 / SCALE + uTime * 0.8)) / 3.0;
    return y;
}

void main() {
    float uTime = timeMsec / 1000.0;
    vUv = uv;
    vec3 pos = position;    
    float strength = 1.0;
    pos.y += strength * calculateSurface(pos.x, pos.z);
    pos.y -= strength * calculateSurface(0.0, 0.0);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}  
`,
  fragmentShader: `
varying vec2 vUv;

uniform sampler2D uMap;

uniform vec3 color;

uniform float timeMsec; 

void main() {
    float uTime = timeMsec / 1000.0;     
    vec2 uv = vUv * 10.0 + vec2(uTime * -0.05);

    uv.y += 0.01 * (sin(uv.x * 3.5 + uTime * 0.35) + sin(uv.x * 4.8 + uTime * 1.05) + sin(uv.x * 7.3 + uTime * 0.45)) / 3.0;
    uv.x += 0.12 * (sin(uv.y * 4.0 + uTime * 0.5) + sin(uv.y * 6.8 + uTime * 0.75) + sin(uv.y * 11.3 + uTime * 0.2)) / 3.0;
    uv.y += 0.12 * (sin(uv.x * 4.2 + uTime * 0.64) + sin(uv.x * 6.3 + uTime * 1.65) + sin(uv.x * 8.2 + uTime * 0.45)) / 3.0;

    vec4 tex1 = texture2D(uMap, uv * 1.0);
    vec4 tex2 = texture2D(uMap, uv * 1.0 + vec2(0.2));

    vec3 blue = color;

    gl_FragColor = vec4(blue + vec3(tex1.a * 0.9 - tex2.a * 0.02), 1.0);

}`
});
</script>
<a-scene>
        <a-camera postion="0 1.2 0"></a-camera>     
  <a-entity material="shader:makewaves;" 
            waves></a-entity>
  <a-entity light="type: directional; color: #ffffff; intensity: 2.8; castShadow:true;" position="0 2 -10"></a-entity>
  <a-light type="point" color="blue" position="0 5 0"></a-light>
    <a-light type="directional" color="blue" intensity="1.8" position="0 5 0"></a-light> 
</a-scene>

【问题讨论】:

    标签: three.js shader aframe


    【解决方案1】:

    这里的问题是应用材质中的着色器没有提供贴图统一/纹理值。

    另一方面,您尝试创建两次材质:

    1) 首先使用a-frames material 组件创建材质
    2) 然后您在waves 组件中创建一个新几何图形 + 一种新材料(具有不正确的三种材料类型)。 您需要让a-frame 处理大部分内容,或者完全在 THREE.js 中创建网格(几何 + 材质)。

    AFRAME
    这里就不多说了。您的着色器没有为纹理公开任何统一,因此您需要在 registerShader 内将其添加到架构中:

    AFRAME.registerShader('makewaves', {
      schema: {
         ......,
        uMap: {
          type: 'map',
          is: 'uniform'
        }
      }, .....
    

    并像这样使用你的着色器:

    <a-plane postion="1 1.2 2" width="5" height="5" rotation="-90 0 90" material="shader:makewaves; 
    uMap: https://cinemont.com/tutorials/zelda/water.png;"></a-plane>
    

    然后a-frame 将使用您的vertexShader 和fragmentShader 创建一个新的着色器。 示例here


    此外,根据@ngoKevin 的回答,向默认平面添加更多段将允许更多顶点随着“波浪”运动而移动。
    segments-height="20" segments-width="20"
    

    小提琴here.

    三个

    要使用自定义着色器,您需要使用THREE.ShaderMaterial

    THREE.ShaderMaterial({
         fragmentShader: this.fragmentShader, // custom fragment shader
         vertexShader: this.vertexShader, // custom vertex shader
         ......
    

    这是一种专为与自定义着色器一起使用而设计的三种材质。

    查看here

    【讨论】:

    • 我认为材料应用得当。材质组件将覆盖waves 中定义的组件。如果存在网格,它将写入材质。否则它将等待网格然后写入材料。
    • 是的,我认为解决方案是提供地图统一/纹理值,否则只会显示白色。没有材质颜色。
    • @ngokevin 我认为“后者”组件(波浪)将覆盖材质和几何组件。此外,不应该使用任何一种解决方案:1)更正着色器,或 2)在波浪组件上正确设置材质吗?除了两者同时还有什么? :)
    • 只需要修正shader即可。顺序无关紧要,材料组件将适用于任何一种方式。
    • @ngokevin 我已经更新了我的 anwser,如果它更准确,请告诉我。
    【解决方案2】:

    您还需要在您的a-plane 中添加segments-height="20" segments-width="20" 来为其提供要置换的顶点。默认平面只有拐角处有顶点,所以不会出现波浪。

    https://codepen.io/anon/pen/MPoBKz?editors=1000

    【讨论】:

      猜你喜欢
      • 2015-08-16
      • 1970-01-01
      • 1970-01-01
      • 2014-09-26
      • 2018-10-09
      • 1970-01-01
      • 2018-11-14
      • 2019-05-14
      • 1970-01-01
      相关资源
      最近更新 更多