【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),如果你看见他了,并在你的电脑上复现了他,恭喜你!你将开启关于美的无垠之门,而我,也将陪你一路前行!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

鸢_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值