【发布时间】:2020-03-29 08:07:55
【问题描述】:
我有 2 个网格,每个网格都有一个 shaderMaterial,每个网格都有一个不同的片段着色器。当我将两个网格都添加到场景中时,只会出现一个。您可以在下面找到我的 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);
我还是个着色器新手,所以请耐心等待。 :-)
【问题讨论】:
-
一种解决方案是使用单独的场景和/或render targets 来实现这一点。然后,您可以通过渲染目标将遮罩渲染到纹理,然后渲染第二个将带有遮罩的纹理传递到第二个着色器,类似于how the EffectsComposer works
-
@gman 谢谢,我想最简单的选择是创建一个额外的场景还是我错了?另外,如果我有多个场景,性能会更差吗?
-
是的,创建另一个场景(和一个渲染目标,以便您可以从第一个场景生成遮罩纹理)。不,它不会更慢。虽然这取决于你真正想要做什么。如果您想对事物进行硬编码,您可以将两个着色器组合成一个着色器。将掩码中的
main更改为mainMask并让它返回最后一个值,而不是将其分配给gl_FragColor。现在从第二个着色器调用它以获取蒙版。 -
@gman 我为渲染目标添加了代码。由于我使用紫色 blob 进行页面转换,这将出现在每个页面上,因此我想将其用作我的渲染目标。你介意帮助我在我的蒙版着色器中传递纹理吗?