Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用2个网格+;在一个场景(three.js)中使用每个不同片段着色器的着色器材质_Three.js_Shader - Fatal编程技术网

使用2个网格+;在一个场景(three.js)中使用每个不同片段着色器的着色器材质

使用2个网格+;在一个场景(three.js)中使用每个不同片段着色器的着色器材质,three.js,shader,Three.js,Shader,我有两个网格,每个网格都有一个着色器材质,每个网格都有一个不同的片段着色器。将两个网格添加到场景中时,将只显示一个网格。下面您可以找到我的2个片段着色器(请查看这两个图像以查看它们的外观)。他们基本上是一样的 我想要实现的是:使用mesh1作为遮罩,并将另一个mesh2(紫色斑点)放在遮罩顶部 紫色斑点: // three.js code const geometry1 = new THREE.PlaneBufferGeometry(1, 1, 1, 1); const material1 =

我有两个网格,每个网格都有一个着色器材质,每个网格都有一个不同的片段着色器。将两个网格添加到场景中时,将只显示一个网格。下面您可以找到我的2个片段着色器(请查看这两个图像以查看它们的外观)。他们基本上是一样的

我想要实现的是:使用
mesh1
作为遮罩,并将另一个
mesh2
(紫色斑点)放在遮罩顶部

紫色斑点:

// three.js code
const geometry1 = new THREE.PlaneBufferGeometry(1, 1, 1, 1);
const material1 = new THREE.ShaderMaterial({
  uniforms: this.uniforms,
  vertexShader,
  fragmentShader,
  defines: {
    PR: window.devicePixelRatio.toFixed(1)
  }
});

const mesh1 = new THREE.Mesh(geometry1, material1);
this.scene.add(mesh1);


// fragment shader
void main() {
  vec2 res = u_res * PR;
  vec2 st = gl_FragCoord.xy / res.xy - 0.5;

  st.y *= u_res.y / u_res.x * 0.8;

  vec2 circlePos = st;
  float c = circle(circlePos, 0.2 + 0. * 0.1, 1.) * 2.5;

  float offx = v_uv.x + sin(v_uv.y + u_time * .1);
  float offy = v_uv.y * .1 - u_time * 0.005 - cos(u_time * .001) * .01;
  float n = snoise3(vec3(offx, offy, .9) * 2.5) - 2.1;

  float finalMask = smoothstep(1., 0.99, n + pow(c, 1.5));

  vec4 bg = vec4(0.12, 0.07, 0.28, 1.0);
  vec4 bg2 = vec4(0., 0., 0., 0.);

  gl_FragColor = mix(bg, bg2, finalMask);
}
蓝色面具

// three.js code
const geometry2 = new THREE.PlaneBufferGeometry(1, 1, 1, 1);
const material2 = new THREE.ShaderMaterial({
  uniforms,
  vertexShader,
  fragmentShader,
  defines: {
    PR: window.devicePixelRatio.toFixed(1)
  }
});

const mesh2 = new THREE.Mesh(geometry2, material2);
this.scene.add(mesh2);

// fragment shader
void main() {
  vec2 res = u_res * PR;
  vec2 st = gl_FragCoord.xy / res.xy - 0.5;

  st.y *= u_res.y / u_res.x * 0.8;

  vec2 circlePos = st;
  float c = circle(circlePos, 0.2 + 0. * 0.1, 1.) * 2.5;

  float offx = v_uv.x + sin(v_uv.y + u_time * .1);
  float offy = v_uv.y * .1 - u_time * 0.005 - cos(u_time * .001) * .01;
  float n = snoise3(vec3(offx, offy, .9) * 2.5) - 2.1;

  float finalMask = smoothstep(1., 0.99, n + pow(c, 1.5));

  vec4 bg = vec4(0.12, 0.07, 0.28, 1.0);
  vec4 bg2 = vec4(0., 0., 0., 0.);

  gl_FragColor = mix(bg, bg2, finalMask);
}
呈现目标代码

this.rtWidth = window.innerWidth;
this.rtHeight = window.innerHeight;
this.renderTarget = new THREE.WebGLRenderTarget(this.rtWidth, this.rtHeight);

this.rtCamera = new THREE.PerspectiveCamera(
  this.camera.settings.fov,
  this.camera.settings.aspect,
  this.camera.settings.near,
  this.camera.settings.far
);
this.rtCamera.position.set(0, 0, this.camera.settings.perspective);

this.rtScene = new THREE.Scene();
this.rtScene.add(this.purpleBlob);

const geometry = new THREE.PlaneGeometry(window.innerWidth, window.innerHeight, 1);
const material = new THREE.MeshPhongMaterial({
  map: this.renderTarget.texture,
});

this.mesh = new THREE.Mesh(geometry, material);

this.scene.add(this.mesh);
我还是个新手,所以请耐心点。:-)


在three.js中,可能有无限种屏蔽方式。这里有一些

  • 使用模具缓冲区

    模具缓冲区类似于深度缓冲区,因为画布或渲染目标中的每个像素都有一个对应的模具像素。您需要告诉three.js您想要一个模具缓冲区,然后在渲染时告诉它在绘制东西时如何使用模具缓冲区

    您可以在上选择模具设置

    你告诉three.js

    • 如果正在绘制的像素未通过模具测试,该怎么办
    • 如果图形中的像素未通过深度测试,该怎么办
    • 如果正在绘制的像素通过深度测试,该怎么办。

    对于这些条件中的每一个,您可以告诉它执行以下操作:keep(不执行任何操作)、increment、decrement、increment wrapparound、decrement wrapparound,设置为特定值

    您还可以通过设置来指定模具测试的内容

    例如,您可以将模具缓冲区清除为0(默认值?),将模具测试设置为始终通过,并设置条件,以便在深度测试通过时将模具设置为1。然后你画一堆东西。无论在何处绘制,现在都会有一个1英寸的模具缓冲区

    现在更改模具测试,使其仅在等于1(或0)时通过,然后绘制更多内容,现在仅在模具等于您设置的值时绘制内容

  • 用阿尔法遮罩遮罩

    在这种情况下,您需要2个颜色纹理和一个alpha纹理。你如何得到这些取决于你。例如,您可以从图像中加载所有3个。或者可以使用3个渲染目标生成所有3个渲染目标。最后,将所有3个对象传递给一个着色器,该着色器将它们混合在一起,如中所示

    gl_FragColor = mix(colorFromTexture1, colorFromTexture2, valueFromAlphaTexture);
    

    请注意,如果两种颜色的纹理之一具有alpha通道,则可以仅使用两种纹理。你只需要传递一个颜色纹理作为你的面具

    当然,您也可以根据一幅图像或另一幅图像或两者中的颜色计算遮罩。比如说

    // assume you have function that converts from rgb to hue,saturation,value
    vec3 hsv = rgb2hsv(colorFromTexture1.rgb);
    float hue = hsv.x;
    // pick one or the other if color1 is close to green
    float mixAmount = step(abs(hue - 0.33), 0.05); 
    gl_FragColor = mix(colorFromTexture1, colorFromTexture2, mixAmount);
    
    这里的重点不是精确的代码,而是你可以根据你想要的任何东西,颜色,位置,随机数学,基于时间的正弦波,一些生成斑点的公式,等等,为面具制作任何你想要的公式。最常见的是一些代码,它只是从纹理中查找mixAmount,这就是上面链接的示例所做的

  • 沙德托风格

    上面的代码似乎是一个shadertoy样式的着色器,它正在绘制一个全屏四边形。您可以在同一着色器中绘制它们,而不是绘制两个单独的对象

    vec4 computeBlueBlob() {
      ...
      return blueBlobColor;
    }
    
    vec4 computeWhiteBlob() {
      ...
      return whtieBlobColor;
    }
    
    vec4 main() {
      vec4 color1 = computeBlueBlob();
      vec4 color2 = computeWhiteBlob();
      float mixAmount = color.a;  // note: color2.a could be any
                                  // formula to decide which colors
                                  // to draw
      gl_FragColor = mix(color1, color2, mixAmount);
    }
    
    请注意,正如上面所述,如何计算mixAmount取决于您。基于任何东西,color1.r,color2.r,一些公式,一些色调,一些其他blob生成函数,等等


  • 一种解决方案是使用单独的场景和/或实现这一点。然后,您可以通过渲染目标将遮罩渲染为纹理,然后渲染第二个遮罩,并将包含遮罩的纹理传递到第二个类似于@gman的着色器。谢谢,我想最简单的方法是创建一个额外的场景,还是我错了?另外,如果我有多个场景,性能会更差吗?是的,创建另一个场景(和渲染目标,以便可以从第一个场景生成遮罩纹理)。不,不会再慢了。尽管这取决于你真正想做什么。如果要硬编码,可以将两个着色器组合到一个着色器中。将掩码中的
    main
    更改为
    mainMask
    ,并使其返回最后一个值,而不是将其分配给
    gl\u FragColor
    。现在从第二个着色器调用它以获得蒙版。@gman我为渲染目标添加了代码。由于我将紫色斑点用于页面转换,这将出现在每个页面上,因此我想将其用作渲染目标。你介意帮我在我的遮罩着色器中传递纹理吗?在a中发布可运行代码。您可以看到很多类似runnable three.js的示例。