【weblg threejs shader】4.关于函数的补充--引入自定义变量

前言

上一章代码中最后一段代码有一行注释,这里其实是我引用来uniforms中的变量,我想你如果还记得第一章的内容,那你应该知道他是怎么来的,

float x = st.x;
  // ${uFormula};
  y=x;

自定义变量

这里我再次说明一下,threejs创建ShaderMaterial的时候可以创建一个uniforms的对象存储我们更新glsl视图的参数,比如这里的uFormula,他的意思就是公式。我们可以将片源着色器改成一个箭头函数返回glsl字符串,并且在上述位置获取window上的uFormula变量(前提你取消了注释)。

// 片元着色器代码
const getFragment = () => {
  const fragment = `
······
void main() {
  vec2 st = vUv;
  // 扩大坐标系 现在整个uv的 xy在0-10之间来变化来
  st*=10.;
  float y = st.y;
  float x = st.x;
 ······

  // ${uFormula};
  y=x;

  ······
}
    `;

准备好后我们将创建shaderMaterial的代码稍作修改

const _04_lines = new ShaderMaterial({
  uniforms: {
    uTime: { value: 1.0 },
    uFormula: {
      value: 'y=sin(x)', onFinishChange: (e) => {

        window.uFormula = e
        changefrag()
      }
    }
  },
  vertexShader: vertex,
  fragmentShader: getFragment(),
  side: DoubleSide,
  transparent: true,
});

const changefrag = () => {
  console.log(_04_lines);
  _04_lines.fragmentShader = getFragment();
  _04_lines.needsUpdate = true;
}
export default _04_lines

然后在ui框架对应渲染部分 initPannel(该处使用vue3)对gui做一修改

	const initPanel = (uniforms) => {
  const panel = new GUI({ width: 310 });

  for (let k in uniforms) {
    let item = uniforms[k];
    const folder = panel.addFolder(k);
    const contorller = folder.add(item, "value", item.min, item.max);
    contorller.onChange((e) => {
      if (item.onChange) item.onChange(e);
    });
    contorller.onFinishChange((e) => {
      if (item.onFinishChange) item.onFinishChange(e);
    });
  }
};

....
重复代码不做赘述
...
const init = () => {
  const { renderer, camera, scene } = initThree(threeRef.value);

  const geometry = new PlaneGeometry(2, 2, 200, 200);
  const material = shaderMaterials[props.id];

  initAnimate(material);

  let uniforms = material.uniforms;

  if (props.panel == "addpanel") initPanel(uniforms);

  const plane = new Mesh(geometry, material);
  scene.add(plane);
};
onMounted(() => {
  init();
});

s
再次运行代码,你就可以通过这个参数修改函数了,这可以方便你构建想要的图像。

完整的shadermaterial代码

import { DoubleSide, ShaderChunk, ShaderMaterial } from "three";
window.uFormula = 'y=sin(x)'
const vertex = `
${ShaderChunk.logdepthbuf_pars_vertex}
bool isPerspectiveMatrix(mat4) {
    return true;
}

varying vec4 m_pos;
varying vec2 vUv;

void main () {
    vUv = uv;
    // 从贴图中采样颜色值
    vec3 newPosition = normal*vec3(0,0,0)+position;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);

      ${ShaderChunk.logdepthbuf_vertex}
}
    `;

// 片元着色器代码
const fragment = `
${ShaderChunk.logdepthbuf_pars_fragment}
precision mediump float;
varying vec2 vUv;
uniform float uTime;
uniform float uFormula;
float plot(vec2 st, float pct){
  return  smoothstep( pct-0.05, pct, st.y) -
          smoothstep( pct, pct+0.05, st.y);
}


float grid(in vec2 st,in vec2 start,in vec2 end,in float step,in float width){
  float gr = 0.;
  // 
  float sx = start.x;
  float sy = start.y;
  float ex = end.x;
  float ey = end.y;
  // 
  for(float i = sx;i<=ex;i+=step){
    if(i-width<st.x&&i+width>st.x) gr=1.;
  }
  for(float i = sy;i<=ey;i+=step){
    if(i-width<st.y&&i+width>st.y) gr=1.;
  }

  return gr;

}
void main() {
  vec2 st = vUv;
  st-=vec2(.5);
  st*=10.;
  float y = st.y;
  float x = st.x;
 



  ${uFormula};

  float pct = plot(st,y);
  vec4 base = vec4(0.,0.,0.,0.);

  float gr = grid(st,vec2(-10.,-10),vec2(10.,10.),.5,0.005);
  float gr2 = grid(st,vec2(-10.,-10),vec2(10.,10.),2.5,0.01);
  vec4 g = vec4(0.,1.,0.,gr);
  vec4 g2 = vec4(1.,0.,0.,gr2);
  base = mix(base,g,g.a);
  base = mix(base,g2,g2.a);

  vec4 line = vec4(1.,1.,1.,pct) ;


  gl_FragColor =mix(base,line,line.a);
  ${ShaderChunk.logdepthbuf_fragment}
}
    `;
const getFragment = () => {
  const fragment = `
${ShaderChunk.logdepthbuf_pars_fragment}
precision mediump float;
varying vec2 vUv;
uniform float uTime;
uniform float uFormula;
float plot(vec2 st, float pct){
  return  smoothstep( pct-0.05, pct, st.y) -
          smoothstep( pct, pct+0.05, st.y);
}


float grid(in vec2 st,in vec2 start,in vec2 end,in float step,in float width){
  float gr = 0.;
  // 
  float sx = start.x;
  float sy = start.y;
  float ex = end.x;
  float ey = end.y;
  // 
  for(float i = sx;i<=ex;i+=step){
    if(i-width<st.x&&i+width>st.x) gr=1.;
  }
  for(float i = sy;i<=ey;i+=step){
    if(i-width<st.y&&i+width>st.y) gr=1.;
  }

  return gr;

}
void main() {
  vec2 st = vUv;
  st-=vec2(.5);
  st*=10.;
  float y = st.y;
  float x = st.x;
 
  // Smooth interpolation between 0.1 and 0.9


  // float grid = 


  // y = mod(x,0.5); // 返回 x 对 0.5 取模的值
  // y = fract(y); // 仅仅返回数的小数部分
  // y = ceil(x);  // 向正无穷取整
  // y = floor(x); // 向负无穷取整
  // y = sign(x);  // 提取 x 的正负号
  // y = abs(x);   // 返回 x 的绝对值
  // y = clamp(x,0.0,1.0); // 把 x 的值限制在 0.0 到 1.0
  // y = min(0.0,x);   // 返回 x 和 0.0 中的较小值
  // y = max(0.0,x);   // 返回 x 和 0.0 中的较大值  
  // y = 1.0-pow(abs(x),.5);  // 返回 x 和 0.0 中的较大值  
  ${uFormula};

  float pct = plot(st,y);
  vec4 base = vec4(0.,0.,0.,0.);

  float gr = grid(st,vec2(-10.,-10),vec2(10.,10.),.5,0.005);
  float gr2 = grid(st,vec2(-10.,-10),vec2(10.,10.),2.5,0.01);
  vec4 g = vec4(0.,1.,0.,gr);
  vec4 g2 = vec4(1.,0.,0.,gr2);
  base = mix(base,g,g.a);
  base = mix(base,g2,g2.a);

  vec4 line = vec4(1.,1.,1.,pct) ;


  gl_FragColor =mix(base,line,line.a);
  ${ShaderChunk.logdepthbuf_fragment}
}
    `;
  return fragment
}
const uniforms = {
  uTime: { value: 1.0 },
  uFormula: { value: 'y=sin(x)' }
};
const _04_lines = new ShaderMaterial({
  uniforms: {
    uTime: { value: 1.0 },
    uFormula: {
      value: 'y=sin(x)', onFinishChange: (e) => {

        window.uFormula = e
        changefrag()
      }
    }
  },
  vertexShader: vertex,
  fragmentShader: getFragment(),
  side: DoubleSide,
  transparent: true,
});

const changefrag = () => {
  console.log(_04_lines);
  _04_lines.fragmentShader = getFragment();
  _04_lines.needsUpdate = true;
}
export default _04_lines

你可以 尝试不同的代码,改一个试试吧,比如x的三次方?

  // y = mod(x,0.5); // 返回 x 对 0.5 取模的值
  // y = fract(y); // 仅仅返回数的小数部分
  // y = ceil(x);  // 向正无穷取整
  // y = floor(x); // 向负无穷取整
  // y = sign(x);  // 提取 x 的正负号
  // y = abs(x);   // 返回 x 的绝对值
  // y = clamp(x,0.0,1.0); // 把 x 的值限制在 0.0 到 1.0
  // y = min(0.0,x);   // 返回 x 和 0.0 中的较小值
  // y = max(0.0,x);   // 返回 x 和 0.0 中的较大值  
  // y = 1.0-pow(abs(x),.5);  // 返回 x 和 0.0 中的较大值  

在这里插入图片描述
又或者其他什么的floor
在这里插入图片描述
现在我们换回sin函数,做一些有趣的事情y=sin(x*10.)
sin10
从数学角度来说图像只是被沿着x轴压缩了十倍,但我么可以注意到一些小细节,比如x一次倒数最小的时候,线条的变化,变成了dashline,其实这个现象你应该早就发现了,在远处看栅格或者x三次方的曲线,都有这种虚化现象,我们试着压缩更多一些,比如把10变成1000 10000或更大,是不是出现了和我一样的现象
noise
如果出现了不妨和我一样,加入时间参数,就像我们之前对单一颜色所做的,让他随着时间变化而变化gif noise

看起来像电视信号不好,像是···en 宇宙背景辐射??虽然这是卡了个图像处理的bug,不过我们仍然乐意给他一个专业点的名称————噪声(noise),如果你看见他了,并在你的电脑上复现了他,恭喜你!你将开启关于美的无垠之门,而我,也将陪你一路前行!

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Three.js是一个流行的WebGL库,用于创建和显示三维场景。ShaderThree.js中用于自定义物体的渲染效果。下面是一个示例,展示了如何使用Three.js的shader创建一条飞线效果。 首先,我们需要创建一个场景、相机和渲染器: ```javascript var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); ``` 接下来,我们创建一个包含多个顶点的几何体,并使用自定义shader进行渲染: ```javascript var geometry = new THREE.Geometry(); geometry.vertices.push(new THREE.Vector3(-10, 0, 0)); geometry.vertices.push(new THREE.Vector3(0, 10, 0)); geometry.vertices.push(new THREE.Vector3(10, 0, 0)); var material = new THREE.ShaderMaterial({ uniforms: {}, vertexShader: document.getElementById('vertexShader').textContent, fragmentShader: document.getElementById('fragmentShader').textContent }); var line = new THREE.Line(geometry, material); scene.add(line); ``` 在上述代码中,我们创建一个包含三个顶点的几何体,并将其传递给`THREE.Line`构造函数,以创建一条直线。我们还创建了一个`THREE.ShaderMaterial`,将自定义的顶点着色器和片段着色器传递给它。在这个示例中,我们使用了JavaScript模板字符串的方式,将着色器代码嵌入到页面的script标签中。 最后,我们需要实现顶点着色器和片段着色器的代码。顶点着色器负责计算和传递顶点位置,片段着色器负责确定像素的颜色。下面是一个简单的顶点着色器和片段着色器的示例: ```glsl // 顶点着色器 varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } // 片段着色器 varying vec2 vUv; void main() { gl_FragColor = vec4(vUv.x, vUv.y, 0.0, 1.0); } ``` 在这个示例中,顶点着色器将顶点的位置传递给片段着色器,并将纹理坐标保存在`vUv`变量中。片段着色器使用纹理坐标的x和y分量来确定像素的颜色。 最后,我们需要在渲染循环中更新相机和渲染场景: ```javascript function animate() { requestAnimationFrame(animate); line.rotation.x += 0.01; line.rotation.y += 0.01; renderer.render(scene, camera); } animate(); ``` 在渲染循环中,我们更新飞线的旋转角度,并使用`renderer.render`函数将场景渲染到屏幕上。 这就是用Three.js shader创建飞线效果的简单示例。使用更复杂的shader代码,您可以创建更多样化的渲染效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸢_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值