Линейный и радиальный градиентный шейдер

Я пытаюсь создать шейдер с радиальным градиентом, чтобы он выглядел как на картинке ниже.

Фоновый линейный градиент работает хорошо, но когда я пытаюсь смешать его с радиальным градиентом, я получаю пузырь внизу. Красный фон, кажется, скользит дальше вниз по оси Y.

Как можно наложить 2 градиента, чтобы радиальная форма не влияла на фон?

Кроме того, фон HTML-страницы (синий) кажется видимым через холст. Как я могу это остановить?

Ниже приведен скриншот результата и фрагмент кода.

var ShaderProgram = {};
ShaderProgram.Create = function(shaderList) {
  var shaderObjs = [];
  for (var i_sh = 0; i_sh < shaderList.length; ++i_sh) {
    var shderObj = this.CompileShader(shaderList[i_sh].source, shaderList[i_sh].stage);
    if (shderObj == 0)
      return 0;
    shaderObjs.push(shderObj);
  }
  var progObj = this.LinkProgram(shaderObjs)
  if (progObj != 0) {
    progObj.attribIndex = {};
    var noOfAttributes = gl.getProgramParameter(progObj, gl.ACTIVE_ATTRIBUTES);
    for (var i_n = 0; i_n < noOfAttributes; ++i_n) {
      var name = gl.getActiveAttrib(progObj, i_n).name;
      progObj.attribIndex[name] = gl.getAttribLocation(progObj, name);
    }
    progObj.unifomLocation = {};
    var noOfUniforms = gl.getProgramParameter(progObj, gl.ACTIVE_UNIFORMS);
    for (var i_n = 0; i_n < noOfUniforms; ++i_n) {
      var name = gl.getActiveUniform(progObj, i_n).name;
      progObj.unifomLocation[name] = gl.getUniformLocation(progObj, name);
    }
  }
  return progObj;
}
ShaderProgram.AttributeIndex = function(progObj, name) {
  return progObj.attribIndex[name];
}
ShaderProgram.UniformLocation = function(progObj, name) {
  return progObj.unifomLocation[name];
}
ShaderProgram.Use = function(progObj) {
  gl.useProgram(progObj);
}
ShaderProgram.SetUniformI1 = function(progObj, name, val) {
  if (progObj.unifomLocation[name]) gl.uniform1i(progObj.unifomLocation[name], val);
}
ShaderProgram.SetUniformF1 = function(progObj, name, val) {
  if (progObj.unifomLocation[name]) gl.uniform1f(progObj.unifomLocation[name], val);
}
ShaderProgram.SetUniformF2 = function(progObj, name, arr) {
  if (progObj.unifomLocation[name]) gl.uniform2fv(progObj.unifomLocation[name], arr);
}
ShaderProgram.SetUniformF3 = function(progObj, name, arr) {
  if (progObj.unifomLocation[name]) gl.uniform3fv(progObj.unifomLocation[name], arr);
}
ShaderProgram.SetUniformF4 = function(progObj, name, arr) {
  if (progObj.unifomLocation[name]) gl.uniform4fv(progObj.unifomLocation[name], arr);
}
ShaderProgram.SetUniformM33 = function(progObj, name, mat) {
  if (progObj.unifomLocation[name]) gl.uniformMatrix3fv(progObj.unifomLocation[name], false, mat);
}
ShaderProgram.SetUniformM44 = function(progObj, name, mat) {
  if (progObj.unifomLocation[name]) gl.uniformMatrix4fv(progObj.unifomLocation[name], false, mat);
}
ShaderProgram.CompileShader = function(source, shaderStage) {
  var shaderScript = document.getElementById(source);
  if (shaderScript) {
    source = "";
    var node = shaderScript.firstChild;
    while (node) {
      if (node.nodeType == 3) source += node.textContent;
      node = node.nextSibling;
    }
  }
  var shaderObj = gl.createShader(shaderStage);
  gl.shaderSource(shaderObj, source);
  gl.compileShader(shaderObj);
  var status = gl.getShaderParameter(shaderObj, gl.COMPILE_STATUS);
  if (!status) alert(gl.getShaderInfoLog(shaderObj));
  return status ? shaderObj : 0;
}
ShaderProgram.LinkProgram = function(shaderObjs) {
  var prog = gl.createProgram();
  for (var i_sh = 0; i_sh < shaderObjs.length; ++i_sh)
    gl.attachShader(prog, shaderObjs[i_sh]);
  gl.linkProgram(prog);
  status = gl.getProgramParameter(prog, gl.LINK_STATUS);
  if (!status) alert("Could not initialise shaders");
  gl.useProgram(null);
  return status ? prog : 0;
}

function drawScene() {

  var canvas = document.getElementById("ogl-canvas");
  var vp = [canvas.width, canvas.height];

  gl.viewport(0, 0, canvas.width, canvas.height);
  gl.enable(gl.DEPTH_TEST);
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  ShaderProgram.Use(progDraw);
  ShaderProgram.SetUniformF2(progDraw, "resolution", [512.0, 512.0])
  gl.enableVertexAttribArray(progDraw.inPos);
  gl.bindBuffer(gl.ARRAY_BUFFER, bufObj.pos);
  gl.vertexAttribPointer(progDraw.inPos, 2, gl.FLOAT, false, 0, 0);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufObj.inx);
  gl.drawElements(gl.TRIANGLES, bufObj.inx.len, gl.UNSIGNED_SHORT, 0);
  gl.disableVertexAttribArray(progDraw.pos);
}

var gl;
var prog;
var bufObj = {};

function sceneStart() {

  var canvas = document.getElementById("ogl-canvas");
  gl = canvas.getContext("experimental-webgl");
  if (!gl)
    return;

  progDraw = ShaderProgram.Create(
    [{
        source: "draw-shader-vs",
        stage: gl.VERTEX_SHADER
      },
      {
        source: "draw-shader-fs",
        stage: gl.FRAGMENT_SHADER
      }
    ]);
  progDraw.inPos = gl.getAttribLocation(progDraw, "inPos");
  if (prog == 0)
    return;

  var pos = [-1, -1, 1, -1, 1, 1, -1, 1];
  var inx = [0, 1, 2, 0, 2, 3];
  bufObj.pos = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, bufObj.pos);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pos), gl.STATIC_DRAW);
  bufObj.inx = gl.createBuffer();
  bufObj.inx.len = inx.length;
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufObj.inx);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(inx), gl.STATIC_DRAW);

  setInterval(drawScene, 50);
}
<script id="draw-shader-vs" type="x-shader/x-vertex">
  precision mediump float;
  
  attribute vec2 inPos;
  
  varying vec2 vertPos;
  
  void main()
  {
      vertPos = inPos;
      gl_Position = vec4( inPos.xy, 0.0, 1.0 );
  }
  </script>
  
  <script id="draw-shader-fs" type="x-shader/x-fragment">
  precision mediump float;
  
  varying vec2 vertPos;
  uniform vec2 resolution;


    void main()
    {
      float y = gl_FragCoord.y / resolution.y;

    vec4 color0= vec4(0.0, 0.0,0.0, 1.0);
    vec4 color1= vec4(0.15, 0.0,0.0, 1.0);
    vec4 color2= vec4(0.7, 0.0,0.0, 1.0);
    vec4 color3= vec4(1, 0.0,0.0, 1.0);
    vec4 color4= vec4(1, 0.0,0.0, 1.0);
    float step0 = 0.0;
    float step1 = 0.15;
    float step2 = 0.75;
    float step3 = 0.95;
    float step4 = 1.0;
   vec4 bg_color = mix(color0, color1, smoothstep(step0, step1, y));
   bg_color = mix(bg_color, color2, smoothstep(step1, step2, y));
   bg_color = mix(bg_color, color3, smoothstep(step2, step3, y));
   bg_color = mix(bg_color, color4, smoothstep(step3, step4, y));

    float d = distance(resolution.xy*0.5,gl_FragCoord.xy)*0.005;
    vec4 r_color0= vec4(1.0, 1.0,1.0, 1.0);
    vec4 r_color1= vec4(1.0, 1.0,1.0, 0.2);
    vec4 r_color2= vec4(1.0, 1.0,1.0, 1.0);
    vec4 r_color3= vec4(1.0, 1.0,1.0, 0.1);
    vec4 r_color4= vec4(1.0, 1.0,1.0, 1.0);
    float r_step0 = 1.0;
    float r_step1 = 0.9;
    float r_step2 = 0.85;
    float r_step3 = 0.05;
    float r_step4 = 0.0;

    vec4 r_color = mix(r_color0, r_color1, smoothstep(r_step0, r_step1, d));
    r_color = mix(r_color, r_color2, smoothstep(r_step1, r_step2, d));
    r_color = mix(r_color, r_color3, smoothstep(r_step2, r_step3, d));
    r_color = mix(r_color, r_color4, smoothstep(r_step3, r_step4, d));

    bg_color.a = 1.0;


      gl_FragColor = mix(r_color, bg_color, d);
    }
  </script>
  <style>
  body{
    background:blue;
  }
  </style>
  <body onload="sceneStart();">
      <canvas id="ogl-canvas" style="border: none;" width="512" height="512"></canvas>
  </body>

0 ответов

Другие вопросы по тегам