我最近正在尝试学习webgl和着色器,因为我正在尝试为网站背景制作动画。我能够将简单的示例从shadertoy移植到three.js中进行操作。现在,我试图更好地理解更高级的示例,并且正在努力解决这个特殊的示例:
https://www.shadertoy.com/view/4sfBWj
我知道要将着色器程序移植到three.js,您需要:
new THREE.PlaneGeometry()
创建three.js基本设置iTime
和iResolution
创建制服gl_FragColor
和gl_FragCoord
void main(void)
如果在一个或多个通道中使用了某些纹理,则
new THREE.TextureLoader()
加载纹理,并为iChannel0
创建制服上面有一些基本的例子。但是我链接的那个有:
这两个都还包括着色器程序和运行它们的主要功能,如何处理它才能将其移植到three.js?
我当前的进度:
var container;
var camera, scene0, scene1, scene2, renderer;
var uniforms0, uniforms1, uniforms2;
var startTime;
var renderTarget0, renderTarget1;
var clock = new THREE.Clock();
init();
animate();
function init() {
container = document.getElementById( 'container' );
startTime = Date.now();
camera = new THREE.Camera();
camera.position.z = 1;
scene0 = new THREE.Scene();
scene1 = new THREE.Scene();
scene2 = new THREE.Scene();
renderTarget0 = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
renderTarget1 = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
/* scene0 */
var geometry0 = new THREE.PlaneGeometry(700, 394, 1, 1);
uniforms0 = {
iTime: { type: "f", value: 1.0 },
iResolution: { type: "v1", value: new THREE.Vector2(), }
};
var material0 = new THREE.ShaderMaterial( {
uniforms: uniforms0,
vertexShader: document.getElementById( 'vs0' ).textContent,
fragmentShader: document.getElementById( 'fs0' ).textContent
});
/* scene0 */
var mesh0 = new THREE.Mesh( geometry0, material0 );
/* scene1 */
var geometry1 = new THREE.PlaneGeometry(700, 394, 1, 1);
uniforms1 = {
iTime: { type: "f", value: 1.0 },
iResolution: { type: "v1", value: new THREE.Vector2(), }
};
var material1 = new THREE.ShaderMaterial( {
uniforms: uniforms1,
vertexShader: document.getElementById( 'vs1' ).textContent,
fragmentShader: document.getElementById( 'fs1' ).textContent,
iChannel0: {type: 't', value: renderTarget0 }
});
var mesh1 = new THREE.Mesh( geometry1, material1 );
/* scene1 */
/* scene2 */
var geometry2 = new THREE.PlaneGeometry(700, 394, 1, 1);
uniforms2 = {
iTime: { type: "f", value: 1.0 },
iResolution: { type: "v1", value: new THREE.Vector2(), }
};
var material2 = new THREE.ShaderMaterial( {
uniforms: uniforms1,
vertexShader: document.getElementById( 'vs2' ).textContent,
fragmentShader: document.getElementById( 'fs2' ).textContent,
iChannel0: {type: 't', value: renderTarget0 },
iChannel1: {type: 't', value: renderTarget1 }
});
var mesh2 = new THREE.Mesh( geometry2, material2 );
/* scene2 */
scene0.add( mesh0 );
scene1.add( mesh1 );
scene2.add( mesh2 );
renderer = new THREE.WebGLRenderer();
container.appendChild( renderer.domElement );
onWindowResize();
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize( event ) {
uniforms0.iResolution.value.x = window.innerWidth;
uniforms0.iResolution.value.y = window.innerHeight;
uniforms1.iResolution.value.x = window.innerWidth;
uniforms1.iResolution.value.y = window.innerHeight;
uniforms2.iResolution.value.x = window.innerWidth;
uniforms2.iResolution.value.y = window.innerHeight;
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
//renderer.render(scene0, camera, renderTarget0);
//renderer.render(scene1, camera, renderTarget1);
uniforms1.iChannel0.value = rendertarget0.texture;
uniforms2.iChannel0.value = rendertarget0.texture;
uniforms2.iChannel1.value = rendertarget1.texture;
uniforms0.iTime.value += clock.getDelta();
uniforms1.iTime.value += clock.getDelta();
uniforms2.iTime.value += clock.getDelta();
//renderer.render( scene2, camera );
}
body {
margin:0;
padding:0;
overflow:hidden;
}
<script src="//threejs.org/build/three.min.js"></script>
<div id="container"></div>
<!-- BREAK --->
<script id="vs0" type="x-shader/x-vertex">
void main() {
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script id="fs0" type="x-shader/x-fragment">
uniform vec2 iResolution;
uniform float iTime;
const mat2 m = mat2( 0.8, 0.6, -0.6, 0.8 );
const mat3 m3 = mat3( 0.8, 0.6, 0.0, -0.6, 0.80, 0.0, 0.0, 0.0, 1.0) *
mat3( 1.0, 0.0, 0.0, 0.0, -0.60, 0.80, 0.0, 0.8, 0.6) *
mat3( 0.8, 0.6, 0.0, -0.6, 0.80, 0.0, 0.0, 0.0, 1.0) *
mat3( 1.0, 0.0, 0.0, 0.0, -0.60, 0.80, 0.0, 0.8, 0.6);
float time;
float n1f0(float p) {
return fract(sin(p * 1.7227636) * 8.03e2);
}
float n1f1(float p) {
return fract(sin(p * 1.42736 + 1.12) * 5.1e2);
}
float n1f2(float p) {
return fract(sin(p * 1.22712 + 12.161) * 5.2e2);
}
float n3f(vec3 p) {
return fract(n1f0(p.x) + n1f1(p.y) + n1f2(p.z) + n1f0(p.x * 1.613) + n1f1(p.y * 3.112) + n1f2(p.z * 4.112));
}
float n3(vec3 p) {
vec3 b = floor(p);
vec3 e = b + vec3(1.0);
vec3 f = smoothstep(vec3(0.0), vec3(1.0), fract(p));
float c000 = n3f(b);
float c001 = n3f(vec3(b.x, b.y, e.z));
float c010 = n3f(vec3(b.x, e.y, b.z));
float c011 = n3f(vec3(b.x, e.y, e.z));
float c100 = n3f(vec3(e.x, b.y, b.z));
float c101 = n3f(vec3(e.x, b.y, e.z));
float c110 = n3f(vec3(e.x, e.y, b.z));
float c111 = n3f(e);
vec4 z = mix(vec4(c000, c100, c010, c110), vec4(c001, c101, c011, c111), f.z);
vec2 yz = mix(z.xy, z.zw, f.y);
return mix(yz.x, yz.y, f.x);
}
float fbm4( vec3 p )
{
float f = 0.0;
p = m3 * p;
f += 0.5000*n3( p ); p = m3*p*2.02;
f += 0.2500*n3( p ); p = m3*p*2.03;
f += 0.1250*n3( p ); p = m3*p*2.01;
f += 0.0625*n3( p );
return f/0.9375;
}
float fbm4( vec2 p )
{
return fbm4(vec3(p, time));
}
float fbm6( vec3 p )
{
float f = 0.0;
p = m3 * p;
f += 0.500000*n3( p ); p = m3*p*2.02;
f += 0.250000*n3( p ); p = m3*p*2.03;
f += 0.125000*n3( p ); p = m3*p*2.01;
f += 0.062500*n3( p ); p = m3*p*2.04;
f += 0.031250*n3( p ); p = m3*p*2.01;
f += 0.015625*n3( p );
return f/0.984375;
}
float fbm6( vec2 p )
{
return fbm6(vec3(p, time));
}
float grid(vec2 p) {
p = sin(p * 3.1415);
return smoothstep(-0.01, 0.01, p.x * p.y);
}
void main(void) {
time = iTime * 0.7;
vec2 q = gl_FragCoord.xy / iResolution.xy;
vec2 p = -1.0 + 2.0 * q;
p.x *= iResolution.x/iResolution.y;
p.y *= 0.3;
p.y -= time * 1.5;
float tc = time * 1.2;
float tw1 = time * 2.5;
float tw2 = time * 0.6;
vec3 vw1 = vec3(p, tw1);
vw1.y *= 2.8;
vec2 ofs1 = vec2(fbm4(vw1), fbm4(vw1 + vec3(10.0, 20.0, 50.0)));
ofs1.y *= 0.3;
ofs1.x *= 1.3;
vec3 vw2 = vec3(p, tw2);
vw2.y *= 0.8;
vec2 ofs2 = vec2(fbm4(vw2), fbm4(vw2 + vec3(10.0, 20.0, 50.0)));
ofs2.y *= 0.3;
ofs2.x *= 1.3;
vec2 vs = (p + ofs1 * 0.5 + ofs2 * 0.9) * 4.0;
vec3 vc = vec3(vs, tc);
float l;
l = fbm6(vc);
l = smoothstep(0.0, 1.0, l);
l = max(0.0, (l - pow(q.y * 0.8, 0.6)) * 1.8);
float r = pow(l , 1.5);
float g = pow(l , 3.0);
float b = pow(l , 6.0);
//r = grid(vs);
gl_FragColor = vec4( r, g, b, 1.0 );
}
</script>
<!-- BREAK --->
<script id="vs1" type="x-shader/x-vertex">
void main() {
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script id="fs1" type="x-shader/x-fragment">
uniform vec2 iResolution;
uniform float iTime;
uniform sampler2D iChannel0;
#ifdef GL_ES
precision mediump float;
#endif
#define SIGMA 5.0
float normpdf(in float x, in float sigma)
{
return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma;
}
void main(void) {
vec3 c = texture2D(iChannel0, gl_FragCoord.xy / iResolution.xy).rgb;
//declare stuff
const int mSize = int(SIGMA * 11.0/7.0);
const int kSize = (mSize-1)/2;
float kernel[mSize];
vec3 finalColor = vec3(0.0);
//create the 1-D kernel
float sigma = SIGMA;
float Z = 0.0;
for (int j = 0; j <= kSize; ++j)
{
kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j), sigma);
}
//get the normalization factor (as the gaussian has been clamped)
for (int j = 0; j < mSize; ++j)
{
Z += kernel[j];
}
//read out the texels
for (int i=-kSize; i <= kSize; ++i)
{
for (int j=-kSize; j <= kSize; ++j)
{
finalColor += kernel[kSize+j]*kernel[kSize+i]*texture2D(iChannel0, (gl_FragCoord.xy+vec2(float(i),float(j))) / iResolution.xy).rgb;
}
}
finalColor /= Z*Z;
//finalColor = c + finalColor * 0.3;
gl_FragColor = vec4(finalColor, 1.0);
}
</script>
<!-- BREAK --->
<script id="vs2" type="x-shader/x-vertex">
void main() {
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script id="fs2" type="x-shader/x-fragment">
uniform vec2 iResolution;
uniform float iTime;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
#ifdef GL_ES
precision mediump float;
#endif
#define SIGMA 5.0
float normpdf(in float x, in float sigma)
{
return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma;
}
void main(void) {
vec3 c = texture2D(iChannel0, gl_FragCoord.xy / iResolution.xy).rgb;
//gl_FragColor = vec4(c, 1.0);
//return;
//declare stuff
const int mSize = int(SIGMA * 11.0/7.0);
const int kSize = (mSize-1)/2;
float kernel[mSize];
vec3 finalColor = vec3(0.0);
//create the 1-D kernel
float sigma = SIGMA;
float Z = 0.0;
for (int j = 0; j <= kSize; ++j)
{
kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j), sigma);
}
//get the normalization factor (as the gaussian has been clamped)
for (int j = 0; j < mSize; ++j)
{
Z += kernel[j];
}
//read out the texels
for (int i=-kSize; i <= kSize; ++i)
{
for (int j=-kSize; j <= kSize; ++j)
{
finalColor += kernel[kSize+j]*kernel[kSize+i]*texture2D(iChannel1, (gl_FragCoord.xy+vec2(float(i),float(j))) / iResolution.xy).rgb;
}
}
finalColor /= Z*Z;
finalColor = c + pow(finalColor, vec3(0.5)) * 0.5;
gl_FragColor = vec4(finalColor, 1.0);
}
</script>
答案 0 :(得分:2)
此示例每帧使用多个渲染。它是这样的:
要在Three.js中复制此内容,您需要使用WebGLRenderTarget
作为中介,以将一个渲染的输出作为纹理传递到下一个着色器。这是只有2个渲染器的伪代码,如果需要更多,则需要扩展它:
var renderer = new WebGLRenderer(w, h, ...);
var scene0 = new Scene();
var scene1 = new Scene();
var plane0 = new THREE.PlaneBufferGeometry(1, 1);
var plane1 = new THREE.PlaneBufferGeometry(1, 1);
// ... continue building materials, shaders, etc
// Add plane mesh to its corresponding scene
scene0.add(planeMesh0);
scene1.add(planeMesh1);
// You should only need one camera if they're both in the same position.
var cam = new Camera();
// renderTarget will store the first buffer
var renderTarget = new WebGLRenderTarget(w, h);
update() {
// This pass will render the first shader
// Its output will be drawn on the rendertarget's texture
renderer.render(scene0, cam, renderTarget);
// We assign the output of the first render pass to the second plane
plane1.uniforms.texture.value = rendertarget.texture;
// Now we render the second shader to the canvas
renderer.render(scene1, cam);
}
请记住,必须在每个遍次中渲染单独的场景,以避免递归问题,因此,您必须将每个平面添加到单独的场景中。要了解有关WebGLRenderTarget
you can read about it in the docs