Mathematical parabola and straight line equation used by cocos shader

One: the characteristics of the parabola

In the parabola y^2=2px, the focus is (p/2, 0), the equation of the directrix is ​​x= -p/2, the eccentricity e=1, and the range: x≥0.

In the parabola y^2= -2px, the focus is (-p/2, 0), the equation of the directrix is ​​x=p/2, the eccentricity e=1, and the range: x≤0.

In the parabola x^2=2py, the focus is (0, p/2), the equation of the directrix is ​​y= -p/2, the eccentricity e=1, and the range: y≥0.

In the parabola x^2= -2py, the focus is (0, -p/2), the equation of the directrix is ​​y=p/2, the eccentricity e=1, and the range: y≤0.

Eccentricity is the ratio of the distance of a point on a conic section from the focus to the distance from the directrix

An eccentricity less than one is an ellipse

Equal to one is a parabola

Greater than one is hyperbolic

When it is equal to zero, it is a circle

It shows that when the cone is cut, it is cut continuously.

Deformation:

// 当uv.x - uv.y * 0.5 * uv.y + t = 0的时候表示改像素点在这条线段上,否则不在
float d = uv.x - uv.y * 0.5 * uv.y + t;

// 这里讨论d 是大于零还是小于零
// d > 0 像素点在曲线的右方
// d < 0 像素点在曲线的左方

 Works with almost any curve, with some exceptions

1: For a closed curve < 0 is inside the closed curve, greater than zero is outside the curve.

2: Applicable for one x value corresponds to one y value

3: For an unclosed curve with an x ​​value corresponding to two y values, when the opening is to the right, < 0 is on the right side of the curve, > 0 is on the left side of the curve, and the point of the curve opening to the left < 0 is on the left side of the curve , the points >0 are on the right side of the curve

The following uses these principles to achieve the effect of a piece of paper on fire:

Two: cocos creator implementation

// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.

CCEffect %{
  techniques:
  - passes:
    - vert: vs
      frag: fs
      blendState:
        targets:
        - blend: true
      rasterizerState:
        cullMode: none
      properties:
        texture: { value: white }
        noiseTexture: {value: white}
        alphaThreshold: { value: 0.5 }
}%


CCProgram vs %{
  precision highp float;

  #include <cc-global>
  #include <cc-local>

  in vec3 a_position;
  in vec4 a_color;
  out vec4 v_color;

  #if USE_TEXTURE
  in vec2 a_uv0;
  out vec2 v_uv0;
  #endif

  void main () {
    vec4 pos = vec4(a_position, 1);

    #if CC_USE_MODEL
    pos = cc_matViewProj * cc_matWorld * pos;
    #else
    pos = cc_matViewProj * pos;
    #endif

    #if USE_TEXTURE
    v_uv0 = a_uv0;
    #endif

    v_color = a_color;

    gl_Position = pos;
  }
}%


CCProgram fs %{
  precision highp float;

  #include <alpha-test>
  #include <texture>
  #include <cc-global>

  in vec4 v_color;

  #if USE_TEXTURE
  in vec2 v_uv0;
  uniform sampler2D texture;
  uniform sampler2D noiseTexture;
  #endif

  vec4 textureSource(vec2 uv) {
    return texture2D(texture,uv).rgba;
  }

  vec4 textureTarget(vec2 uv) {
    return texture2D(noiseTexture,uv).rgba;
  }

  float hash(vec2 p) {
    vec3 p2 = vec3(p.xy,1.);
    return fract(sin(dot(p2,vec3(37.1,61.7,12.4))) * 3758.54);
  }

  float noise(vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);

    f *= f * (3. - 2. *f);

    return mix(mix(hash(i + vec2(0.,0.)), hash(i + vec2(1.,0.)),f.x),
		mix(hash(i + vec2(0.,1.)), hash(i + vec2(1.,1.)),f.x),
		f.y);
  }

  float fbm(vec2 p) {
    float v = 0.0;
    v += noise(p*1.)*.5;
    v += noise(p*2.)*.25;
    v += noise(p*4.)*.125;
    return v;
  }

  vec4 mainImage(vec2 uv) {
    vec4 src = textureSource(uv);
    vec4 tgt = textureTarget(uv);

    vec4 col = src;
    uv.x -= 1.5;
    // 控制火焰的燃烧时间
    float t = 2.;
    // [0 ~ 2.5)
    float ctime = mod(cc_time.x * .5,t);

    // d = x + 0.25 * y * y 抛物线方程 y * y = -x; 开口向左  曲线上的点到抛物线焦点的距离 y * y = 4 - 4x  焦点坐标(-1,0)形状就是抛物线
    // 0.5 * fbm(uv * 15.1) 造型函数
    // 所有的像素点到曲线的距离(非垂直距离而是直线距离)
    float d = uv.x - uv.y * 0.5 * uv.y + 0.5 * fbm(uv * 15.2) + ctime * 1.3;

    // d > 0 表示像素点在曲线的右边 d < 0 表示像素点在曲线的左边 d = 0 表示像素点在曲线上

    // 约束 col的值的三个分量在【0,0.4】范围内颜色会变暗
    if(d > 0.4) col = clamp(col - (d - 0.4) * 10.,0.0,1.0);
    
    if(d > 0.47) {
      // 控制火焰颜色
      vec4 fireColor = vec4(1.5,0.5,0.,1.);
      // 火焰最红的厚度
      float fireWeight = 0.4;
      // 距离在 0.47 ~ 0.5的时候直接显示火焰的颜色
      if(d < 0.5) col += (d - fireWeight) * 33.0 * 0.5 * (0.0 + noise(100. * uv + vec2(-ctime * 2.,0.))) * fireColor;
      // 如果距离大于0.5的时候直接显示黑色
      else col += vec4(0.,0.,0.,0.);
    }
    return col;

  }

  void main () {
    vec4 o = vec4(1, 1, 1, 1);

    #if USE_TEXTURE 
      CCTexture(texture, v_uv0, o);
    #endif

    o *= v_color;

    ALPHA_TEST(o);

    // mainImage(o);
    vec2 uv = v_uv0;
    uv.y = 1. - uv.y;

    o.rgba = mainImage(uv);

    #if USE_BGRA
      gl_FragColor = o.bgra;
    #else
      gl_FragColor = o.rgba;
    #endif
  }
}%

 

Guess you like

Origin blog.csdn.net/lck8989/article/details/127306116