使用2个网格+;在一个场景(three.js)中使用每个不同片段着色器的着色器材质
我有两个网格,每个网格都有一个着色器材质,每个网格都有一个不同的片段着色器。将两个网格添加到场景中时,将只显示一个网格。下面您可以找到我的2个片段着色器(请查看这两个图像以查看它们的外观)。他们基本上是一样的 我想要实现的是:使用使用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 =
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中,可能有无限种屏蔽方式。这里有一些
- 如果正在绘制的像素未通过模具测试,该怎么办
- 如果图形中的像素未通过深度测试,该怎么办
- 如果正在绘制的像素通过深度测试,该怎么办。
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,这就是上面链接的示例所做的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的示例。