在使用片段着色器应用波浪效果时,防止在WebGL中出现纹理边界扭曲

图加亚克

我在项目中通过Three.js使用GLSL。

我有这样的标志纹理:

当我应用“片段着色器”(Fragment Shader)使其具有波浪效果时,纹理的边界似乎会拉伸。但是,我不想要那个。我希望看到背景颜色(在这种情况下为透明),以便看起来就像挥舞的旗帜。您可以在CodePen看到问题在这里

供参考(如果CodePen由于某种原因将来无法使用),下面是代码:

顶点着色器

varying vec2 vUv;

void main() {
  vUv = uv;

  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

片段着色器

uniform vec2 u_resolution;
uniform float u_time;
uniform sampler2D image;

uniform vec2 strength;
uniform float speed;

varying vec2 vUv;

vec2 sineWave( vec2 p ) {
  float x = strength.x * sin(-1.0 * p.y + 50.0 * p.x + u_time * speed);
  float y = strength.y * sin(p.y + 10.0 * p.x + u_time * speed);
  return vec2(p.x, p.y + y);
}

void main() {
  vec4 color = texture2D(image, sineWave(vUv));
  gl_FragColor = color;
}

Three.js代码

const CANVAS_WIDTH = 250;
const CANVAS_HEIGHT = 250;

const imageDataUri = 'data:image/png;base64,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';

const vertexShader = () => {
  return `
    varying vec2 vUv;

    void main() {
      vUv = uv;

      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `
};

const fragmentShader = () => {
  return `
    uniform vec2 u_resolution;
    uniform float u_time;
    uniform sampler2D image;

    uniform vec2 strength;
    uniform float speed;

    varying vec2 vUv;

    vec2 sineWave( vec2 p ) {
      float x = strength.x * sin(-1.0 * p.y + 50.0 * p.x + u_time * speed);
      float y = strength.y * sin(p.y + 10.0 * p.x + u_time * speed);
      return vec2(p.x, p.y + y);
    }

    void main() {
      vec4 color = texture2D(image, sineWave(vUv));
      gl_FragColor = color;
    }
  `
};

function init() {
    let loader = new THREE.TextureLoader();

    loader.load(
      imageDataUri,
      (texture) => {
        let scene = new THREE.Scene();
        let camera =
          new THREE.PerspectiveCamera(75, CANVAS_WIDTH / CANVAS_HEIGHT, 0.1, 1000);
        let renderer = new THREE.WebGLRenderer({ alpha: true });
        renderer.setClearColor(0x000000, 0);

        renderer.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);

				document.body.appendChild(renderer.domElement);
        
        let uniforms = {
          u_time: { type: 'f', value: 0.1 },
          u_resolution: { type: 'v2', value: new THREE.Vector2() },
          image: { type: 't', value: texture },
          strength: { type: 'v2', value: new THREE.Vector2(0.01, 0.025) },
          speed: { type: 'f', value: 8.0 }
        };
        let material = new THREE.ShaderMaterial({
          uniforms,
          vertexShader: vertexShader(),
          fragmentShader: fragmentShader()
        });
let triangleMesh = new THREE.Mesh(new THREE.PlaneGeometry(CANVAS_WIDTH, CANVAS_HEIGHT, 1, 1), material);

        scene.add(triangleMesh);
        camera.position.z = 250;

        let clock = new THREE.Clock();
        let animate = () => {
          requestAnimationFrame(animate);

          triangleMesh.material.uniforms.u_time.value += clock.getDelta();

          renderer.render(scene, camera);
        };

        animate();
      },
      undefined,
      (err) => { console.error('Could not load texture', err) }
    );

}

init();
body {background: orange;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>

拉比德76

您可以做的是根据纹理v坐标缩放波浪效果如果按比例缩放,1.0-p.y则波效果在顶部边界处为零,在底部处具有最大值。

float y = strength.y * sin(p.y + 10.0 * p.x + u_time * speed) * (1.0-p.y*p.y);

为了在标志的顶部区域产生较小的波动影响,请按v坐标((1.0-p.y*p.y)的平方进行缩放

float y = strength.y * sin(p.y + 10.0 * p.x + u_time * speed) * (1.0-p.y*p.y);

const CANVAS_WIDTH = 250;
const CANVAS_HEIGHT = 250;

const imageDataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6CAYAAACI7Fo9AAAQOElEQVR4nO2dTWtcyRWGT2v0QSwUZqVh0EbeBbQek0A2Yf5AdlkNjLchf6LzC2YgOEtlK6+8SJYhmwEbeaFJwJCdjbE3zlK0pWmBOlS729Nu9e2+VfdU3apTzwMemK/X95br1aPbfVQ9+ONvfv1SRI4FAKzyaltEhoP9vdPP//qNDPb37tznT//6r4z+8k/Z/9PXsve7XwWtg2bGL//8e9k+Oer9OrgXMkrImDHcevT02d8mo59eXf/jP0XcuKViUHIyYmZsHR64v33lOr41+3fD67//Wyajn/gDIIMMAxn3Hv5WJqOx+0dD95dp0ZetzkYgg4yyMybvx07cU5vLvOgzplZ3v9gIZJBRbsbug/vTHs9t7hgs/sfzV+DZCGSQUW7G1ePncnV27mx+f/7fbC39P+4V+OlXBEs3TgYZtWS419mWbS7LRV/3CnzNi0cGGaVkuO4uPpvPWTa6rHoFvuQbJ4OMWjKabC6riu5rdf4AyCAjj4wmm0uD0aWt1dkIZJCRR8Y6m0tT0dtYnY1ABhn5ZKyzuawxuqyzOhuBDDLyydhkc1lX9CarsxHIICOvjE02lw1Gl2WrsxHIICOvjDY2d3y27l8+f/Pmx6+++PLbwe7257fvLtkIZJCRWcb1kwu5uXjtbP5wXdZ2i8t2Vj91XznYCGSQkU9GW5tLi2/dPz6ru9+MjUAGGflktHk2n7Ox6DOG4/OXXtNyvhdNBhlktM/wsbm0LXroDDx/iGSQESfDx+biYXTxnYFnI5BBRpwMX5uLT9F9rM5GIIOMeBm+NhdPo0sbq7MRyCAjXkaIzcW36JuszkYgg4y4GSE2lwCjS5PV2QhkkBE3I9TmElL0VVZnI5BBRvyMUJtLoNFl0epsBDLIiJ/RxeayfAqsD+7E2J2To+ObF2/ZCGSQETlj1cmuPoQa3TF0JXefCMFGIIOMeBldbS5dij57TnjlPhEiBDYTGWS0o8uz+ZwuRpeQE2OFjUAGGa3RsLl0LXrIDDwbgQwy2qNhc1EwuvhYnY1ABhnt0bK5aBS9rdXZCGSQ4YeWzUXJ6LLJ6mwEMsjwX5Ors3PRsLlsOjOuLYtny+2cHN25YDYCGWT4r4l7V2vTWXBt0TK6rLI6G4EMMsLWZIaKzUXL6LLC6mwEMsgIW5OtwwOZjMZqNhdlo8vc6u4XG4EMMvzXxE2aTkbTITQ1m0uXWfcm3Ay8iByzEcggw39Nbv932WmmvQltozuGg/092X0Qdp1sJjJqyVheE9cZrffNl1EveuiJscJGIKOijFVrovm++TIxjC4hM/BsBDJqyVi1JppTcKuIUnRfq7MRyKglo2lNYtpcIhpd2lqdjUBGLRlNaxLb5hKz6G2szkYgo5aMdWsS2+YS2eiyzupsBDJqyVi3JilsLrGL3mR1NgIZtWRsWpMUNpcERpdlq7MRyKglY9OapLK5aM66N7E4A3/77pKNQEYVGW3W5PrJhdxcvFadaW9iO/ZvMMNZ/dR9BWMjkGE9o82apLS5JPrW/eOzurthNgIZljParkmqZ/M5SYo+Yzg+f+l9YqywmcgoJKPt/aS2uaQseugMPMUgo4QMn/tJbXNJbHTxnYGnGGSUkOFzP33YXFIX3cfqFIOMEjJ876cPm0sPRpc2VqcYZJSQ4Xs/fdlc+ij6JqtTDDJKyAi5n75sLj0ZXZqsTjHIKCEj5H76tLn0VfRVVqcYZJSQEXo/fdpcejS6LFqdYpBRQkbo/fRtc4lxCqwP7sTYnZOj45sXbykGGVlndLmfq8fPo5zs6kOfRnd870ruzrKmGGTkmtHlfnKwufRd9EdPn33nPl9q8n4c9P9TLjJiZ3S9lr6fzef0bXQJOTFWKAYZCTK6XksuNpccih4yA08xyIidoXEtudhcMjG6+FidYpARO0PjWnKyueRS9LZWpxhkxM7QupacbC4ZGV02WZ1ikBE7Q+tacrO55FT0dVanGGTEztC6FsnQ5pKZ0WWV1SkGGbEztK5lnnN1di452VxSnALrw+KJsTsnRxSDjOgZWteymONmQ1Kc7OpDqlNgfZieGDu4tyvvT3+gGGREy9C6Fvm05JKbzaXvWfcm3Ay8iBxTDDJiZWhdy2LO1uGB3L677HWmvYncntHnDAf7e7L7IGy9KBcZKdZkMcf9vMZkNB3lzs7mkmvRQ0+MFYpBRqI1Wc5xP6+R2yvti+RqdAmZgacYZKRYk+Uc951nbu+bL5Nt0X2tTjHISLEmq3JyfN98mZyNLm2tTjHISLEmq3JynIJbRdZFb2N1ikFGijVpyinB5lKA0WWd1SkGGSnWpCmnFJtLCUVvsjrFICPFmqzLKcXmUojRZdnqFIOMFGuyLqckm0tus+5NLM7A3767pBhkRF+TTTnXTy7k5uJ1djPtTeQ4697EdAbefSWlGGTEXJNNOaXZXAr61v3js7pbdIpBRqw1aZNT0rP5nGKKPmM4Pn/pfWKsUAzTGVpr0ianRJtLaUUPnYGnGHYztNakbU6JNpcCjS6+M/AUw26G1pq0zSnV5lJi0X2sTjHsZmitiU9OqTaXQo0ubaxOMexmaK2JT07JNpdSi77J6hTDbobWmvjmlGxzKdjo0mR1imE3Q2tNfHNKt7mUXPRVVqcYdjO01iQkp3SbS+FGl0WrUwy7GVprEpJjweaS6ymwPrgTY3dOjo5vXrylGAYztNYkNOfq8XP3gQxZnuzqQ+lGdwxdyd0pnBTDVobW/YTmWLG5WCj67LnplTuFMwTKlWeG1v10ybHwbD7HgtEl5MRYoVzZZmjdT5ccSzYXK0UPmYGnXHlmaN1P1xxLNhdDRhcfq1OuPDO07qdrjjWbi6Wit7U65cozQ+t+NHKs2VyMGV02WZ1y5ZmhdT8aORZtLtaKvs7qlCvPDK370cqxaHMxaHRZZXXKlWeG1v1o5Vi1uVgs+rLVKVeeGVr3o5lj1eZS2CmwPkxPjB3c25X3pz9QrswytO5HO+fq7Fws2lwszLo34WbgReSYcuWVoXU/MXLchGXpM+1NWHxGnzMc7O9NP7s6BAqqn6F1LTFyZpi0uZTySS0hLH66y87JkVcCBdXP0LqWGDlbhwcyGY2L+dSVECwbXUJm4CmofobWtcTIcT/1OBlNfyDKrM3FetF9Z+ApqH6G1rXEynE/9Wj1lfZFrBtd2lqdgupnaF1LrBz3+o3V982XMV/0NlanoPoZWtcSM8fy++bL1GB0WWd1CqqfoXUtMXMsT8GtooqiN1mdgupnaF1L7JyabC4VGV2WrU5B9TO0riV2Tm02F8vvoy+z+L767btLCqqcoXUtKXKun1zIzcVr0++bL2N11r2J6Qy8+4pOQfUytK4lRU6NNpfKvnX/+Kzu/uApaH0llwqfzedUVfQZw/H5S+8TY4WSF59Tq82lxqKHnBgrlNxETq02l0qNLr4z8JS8/JyabS61Ft3H6pTcRk7NNpeKjS5trE7JbeTUbnOpueibrE7J7eTUbnOp3OjSZHVKbicHm3+g6qKvsjolt5WDzT9Qu9Fl0eqU3FYONv8Zs6fA+uBOjN05OTq+efGWkhvKuXr83B3hbPZkVx8w+geGruTu/DBKbiMHm38KRZ89q7szvd35YSFQ8vxyeDb/FIr+M94nxgolzzIHm9+Fos8ImYGn5HnmYPO7UPRPaW11Sp5nDjZfDUVfoK3VKXm+Odh8NRT9LmutTsnzzcHmzVD0JdZZnZLnnYPNm6Hoq7ljdUqedw42Xw9FX8Gy1Sl5/jnYfD21nQLrw/TE2MG9XXl/+gMlzzgHm2+GWfc1uBl4ETmm5HnnMNO+Gb51X89wsL83/dTNECh5mpyrs3PB5uup5pNaQlj8dJedkyOvBEqeLsf9nEJNn7oSAkbfjPcMPCVPlzMDm28Ao2/A1+qUPF3O1uGBTEZjbN4CjN6OVlan5Oly3NkBk9H0x4qxeQsoegvazMBT8rQ57uwA3jdvD0VvT6PVKXnaHPcuCO+b+0HRW9JkdUqePocpOH8ouh+fWJ2Sp89hCi4MXnX3YPEV+Nt3l5S8h5zrJxdyc/GaV9o9Ydbdn+kMvDMLJU+bg83D4Vt3T+bP6m7zUfK0OTybh0PRwxiOz196nxgrlDw4B5t3g6IHEHJirFDyTjnYvBsUPRyvGXhKHp6DzbtD0QPxsTol75aDzbtD0bux0eqUvFsONteBondgk9UpefccbK4DRe/OSqtT8u452FwPit6RVVan5Do52FwPiq7DR6vXXk6tHGyuC6fAKuFOjN05OTq+efGWkivkcLKrLhhdj6EruTv5hJJ3y8Hm+lB0JWbPka/cySehUPIP8GyuD0XXxfvE2DmU/APYPA4UXRFm4LvnYPM4UHR9mIEPzMHm8aDoyjADH56DzeNB0ePADLxnDjaPC0WPADPw/jnYPC4UPR7MwLcEm8eHokeCGfj2YPP4UPS4MAO/AWyeBmbdI8MM/HqYaU8DRo8PM/ANYPN0UPTIMAPfDM/m6aDoaWAGfkXO1dm5YPM08NlrCVj8zLadk6PWv6H1F/Dcdzp8hloaMHo6mIH/tOSCzdOB0RPhY3XrJd86PJDJaIzNE4LR01L9DLx792Eymr4wic0TQtETwgz81+LefeCV9vRQ9PRUOwO/++A+75v3BEVPTM0z8Lxv3h8UvR+qm4FnCq5fmHXvidpm4Jlp7xeM3h/f1zIDj837h6L3xKOnz76rZQaeZ/P+oej9Yn4GHpvnAUXvkRrOgcfmeUDR+8fsDDw2zweK3jOWz4HH5vlA0fPA3Aw8Ns8Lip4BFmfgsXleUPR8MDMDj83zg6JngqUZeGyeHxQ9L4qfgcfmecKse2aUPgPPTHueYPT8KHYGHpvnC0XPjJJn4Hk2zxeKnifFzcBj87yh6BlS4gw8Ns8bip4vxczAY/P8oeiZUtIMPDbPH4qeN9nPwGPzMqDoGVPCDDw2LwOKnj/ZzsBj83Kg6JmT8ww8Ni8Hil4G2c3AY/OyYNa9EHKbgWemvSwwejkMc5mBx+blQdELYfYcnMUMPM/m5UHRyyKLGfirs3PB5mXxWe0LUBLP37z58asvvvx2sLv9+c7JUesr134Bz31n8ejps4emFtc4GL08ep2Bn4HNCwOjF4aP1bVLvnV4IJPRGJsXCEYvk+Qz8O7V/slo+kIgNi8Qil4gfczAu1f7eaW9XCh6uSSbgd99cJ/3zQuHohdKyhl43jcvH4peNtFn4JmCswGz7oUTewaemXYbYPTyiTYDj83tQNELJ+YMPM/mdqDoNlCfgcfmtqDoBohxDjw2twVFt4PaDDw2twdFN4LmOfDY3B4U3RadZ+CxuU0ouiE0ZuCxuU0ouj2CZ+CxuV0oujG6zMBjc7tQdJt4z8Bjc9sw624U3xl4Ztptg9Ht0noGHpvbh6IbxWcGnmdz+1B022x8Xx2b1wFFN0ybaTlsXgcU3T6NVsfm9UDRjbPO6ti8Hih6HdyxOjavC4peAausjs3rgqLXw0erY/P6YDKuIty03C/+8ODY3TFTcHWxXfsCVIaz+unslrE5gFWc1d0v/oDrAqPXByavDRH5P5j6oOB59pHPAAAAAElFTkSuQmCC';

const vertexShader = () => {
  return `
    varying vec2 vUv;

    void main() {
      vUv = uv;

      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `
};

const fragmentShader = () => {
  return `
    uniform vec2 u_resolution;
    uniform float u_time;
    uniform sampler2D image;

    uniform vec2 strength;
    uniform float speed;

    varying vec2 vUv;

    vec2 sineWave( vec2 p ) {
      float x = strength.x * sin(-1.0 * p.y + 50.0 * p.x + u_time * speed);
      float y = strength.y * sin(p.y + 10.0 * p.x + u_time * speed) * (1.0-p.y*p.y);
      return vec2(p.x, p.y + y);
    }

    void main() {
      vec4 color = texture2D(image, sineWave(vUv));
      gl_FragColor = color;
    }
  `
};

function init() {
    let loader = new THREE.TextureLoader();

    loader.load(
      imageDataUri,
      (texture) => {
        let scene = new THREE.Scene();
        let camera =
          new THREE.PerspectiveCamera(75, CANVAS_WIDTH / CANVAS_HEIGHT, 0.1, 1000);
        let renderer = new THREE.WebGLRenderer({ alpha: true });
        renderer.setClearColor(0x000000, 0);

        renderer.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);

				document.body.appendChild(renderer.domElement);
        
        let uniforms = {
          u_time: { type: 'f', value: 0.1 },
          u_resolution: { type: 'v2', value: new THREE.Vector2() },
          image: { type: 't', value: texture },
          strength: { type: 'v2', value: new THREE.Vector2(0.01, 0.025) },
          speed: { type: 'f', value: 8.0 }
        };
        let material = new THREE.ShaderMaterial({
          uniforms,
          vertexShader: vertexShader(),
          fragmentShader: fragmentShader()
        });
let triangleMesh = new THREE.Mesh(new THREE.PlaneGeometry(CANVAS_WIDTH, CANVAS_HEIGHT, 1, 1), material);

        scene.add(triangleMesh);
        camera.position.z = 250;

        let clock = new THREE.Clock();
        let animate = () => {
          requestAnimationFrame(animate);

          triangleMesh.material.uniforms.u_time.value += clock.getDelta();

          renderer.render(scene, camera);
        };

        animate();
      },
      undefined,
      (err) => { console.error('Could not load texture', err) }
    );

}

init();
body {background: orange;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用Vulkan在片段着色器中缓慢获取纹理

来自分类Dev

使用着色器在画布上镜像效果(WebGL)

来自分类Dev

片段着色器忽略纹理坐标

来自分类Dev

片段着色器中的纹理读取

来自分类Dev

在片段着色器中的OpenGL中更改纹理的颜色效果不佳

来自分类Dev

WebGL / three.js片段着色器-用alpha透明色覆盖alpha透明纹理

来自分类Dev

WebGL / three.js片段着色器-用alpha透明色覆盖alpha透明纹理

来自分类Dev

使用着色器时纹理无法渲染?

来自分类Dev

如何在着色器中制作波形扭曲效果?

来自分类Dev

鱼眼扭曲鼠标位置-片段着色器

来自分类Dev

GLSL着色器可提供纹理“烟熏”效果

来自分类Dev

GLSL着色器可提供纹理“烟熏”效果

来自分类Dev

webgl:与其他程序/着色器共享纹理

来自分类Dev

GLSL片段着色器可智能地平铺纹理

来自分类Dev

glsl片段着色器计算纹理位置

来自分类Dev

OpenGL片段着色器返回纹理的固定颜色

来自分类Dev

片段着色器中的OpenGL纹理为黑色

来自分类Dev

在GLSL着色器中使用多个纹理时,纹理被覆盖

来自分类Dev

为什么用片段着色器进行纹理映射时会在纹理坐标跳跃时生成线条?

来自分类Dev

为什么在使用着色器时出现黑屏?

来自分类Dev

将WebGL片段着色器转换为GLES

来自分类Dev

WebGL-丢弃顶点着色器标记的片段

来自分类Dev

在WebGL片段着色器中绘制网格

来自分类Dev

WebGL片段着色器可用于多个光源?

来自分类Dev

WebGL片段着色器不透明度

来自分类Dev

在WebGL片段着色器中绘制网格

来自分类Dev

WebGL片段着色器可用于多个光源吗?

来自分类Dev

webgl使用帧缓冲对象在图像上的多个片段着色器产生黑色输出

来自分类Dev

使用变化的Webgl将属性传递给片段着色器

Related 相关文章

  1. 1

    使用Vulkan在片段着色器中缓慢获取纹理

  2. 2

    使用着色器在画布上镜像效果(WebGL)

  3. 3

    片段着色器忽略纹理坐标

  4. 4

    片段着色器中的纹理读取

  5. 5

    在片段着色器中的OpenGL中更改纹理的颜色效果不佳

  6. 6

    WebGL / three.js片段着色器-用alpha透明色覆盖alpha透明纹理

  7. 7

    WebGL / three.js片段着色器-用alpha透明色覆盖alpha透明纹理

  8. 8

    使用着色器时纹理无法渲染?

  9. 9

    如何在着色器中制作波形扭曲效果?

  10. 10

    鱼眼扭曲鼠标位置-片段着色器

  11. 11

    GLSL着色器可提供纹理“烟熏”效果

  12. 12

    GLSL着色器可提供纹理“烟熏”效果

  13. 13

    webgl:与其他程序/着色器共享纹理

  14. 14

    GLSL片段着色器可智能地平铺纹理

  15. 15

    glsl片段着色器计算纹理位置

  16. 16

    OpenGL片段着色器返回纹理的固定颜色

  17. 17

    片段着色器中的OpenGL纹理为黑色

  18. 18

    在GLSL着色器中使用多个纹理时,纹理被覆盖

  19. 19

    为什么用片段着色器进行纹理映射时会在纹理坐标跳跃时生成线条?

  20. 20

    为什么在使用着色器时出现黑屏?

  21. 21

    将WebGL片段着色器转换为GLES

  22. 22

    WebGL-丢弃顶点着色器标记的片段

  23. 23

    在WebGL片段着色器中绘制网格

  24. 24

    WebGL片段着色器可用于多个光源?

  25. 25

    WebGL片段着色器不透明度

  26. 26

    在WebGL片段着色器中绘制网格

  27. 27

    WebGL片段着色器可用于多个光源吗?

  28. 28

    webgl使用帧缓冲对象在图像上的多个片段着色器产生黑色输出

  29. 29

    使用变化的Webgl将属性传递给片段着色器

热门标签

归档