Как нарисовать форму, сгенерированную несколькими функциями в GLSL? - PullRequest
0 голосов
/ 06 декабря 2018

enter image description here

Я пытался нарисовать сложную фигуру с помощью GLSL, которая генерируется 4 функциональными изображениями, они были

  1. x^ 2 + y ^ 2 = 1
  2. y = 0,8 * log (0,63 * x + 0,64) + 0,8
  3. y = 0,5 *log (10 * x-2) + 1
  4. y = -0,1 (x + -0,5) ^ 2 + 1,8

ВотФорма, которую я нарисовал в десмосе: Магатама .

И это то, что я реализовал до сих пор: Шаринган

Я хочу выделить эту частьв моем фрагментном шейдере: enter image description here

Я не знаю, как выбрать. Надеюсь, кто-то может дать некоторые идеи.

THX.

1 Ответ

0 голосов
/ 06 декабря 2018

Язык GLSL предоставляет такие функции, как log(x) или pow для выполнения мощных вычислений.См. GLSL - Язык затенения OpenGL 4.6;Глава 8. Встроенные функции;стр. 152 для полного набора функций.

например,

float y1 = 0.4*log(0.63*x+0.64)+1.8;

Чтобы нарисовать такую ​​фигуру, вы должны нарисовать квад в пространстве экрана, передав нормализованное устройство x и y.координаты фрагмента шейдера.Нижняя левая координата (-1, -1), верхняя правая - (1, 1) и, конечно, центр - 0.0.

Чтобы найти область, которая находится «в» форме, у вас естьпревратить результат расчетов в атомарные утверждения.Используйте функцию step, чтобы сравнить значение с ребром и получить 1,0, если результат равен true, или 0.0, если результат равен false.

например, проверить, находится ли координата в окружности:

float a0 = step(x*x + y*y, 1.0); 

, например, проверить, если y координата, вычисленная как f (x) меньше "под"(меньше) кривая, образованная функцией:

  float y3 = -0.1 * pow(x+-0.5, 2.0)+1.8;
  float a3 = step(y, y3);

Чтобы выяснить, находится ли фрагмент в форме, у вас есть результаты различных вычислений по" логическим "операциям над значениями с плавающей запятой.

например, логическая ИЛИ операция может быть рассчитана с помощью функции max:

float a = max(a0, a1); // a := a0 OR a1

Например, логическая И Операция может быть рассчитана оператором умножения или функцией min:

float a = a0 * a1; // a := a0 AND a1

Используйте конечный результат для установки выходного цвета.Функцию mix можно использовать для интерполяции между 2 цветами.Так как «логический» результат вычислений равен либо 0.0, либо 1.0, функция mix используется для «выбора» одного из 2 цветов:

vec3 col_fill = vec3(1.0, 0.0, 0.0); // red
vec3 col_back = vec3(0.0, 0.0, 0.0); // black

vec4 frag_color = vec4(mix(col_back, col_fill, a), 1.0); 

См. Пример WebGL, в котором используется фрагментшейдер с этой техникой для генерации формы, похожей на вопрос.Формулы немного адаптированы, поскольку формулы вопроса не дают ожидаемого результата.Логические результаты разных частей фигуры представлены разными цветами:

(function loadscene() {

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

function render(deltaMS) {

  gl.viewport( 0, 0, vp_size[0], vp_size[1] );
  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 );
  ShProg.Use( progDraw );
  ShProg.SetF2( progDraw, "resolution", vp_size );
  VertexBuffer.Draw( bufRect );

  requestAnimationFrame(render);
}  

function initScene() {

  canvas = document.getElementById( "texture-canvas");
  gl = canvas.getContext( "experimental-webgl" );
  //gl = canvas.getContext( "webgl2" );
  if ( !gl )
    return;
    
  progDraw = ShProg.Create( 
    [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
      { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
    ] );
  progDraw.inPos = gl.getAttribLocation( progDraw.progObj, "inPos" );
  if ( progDraw.progObj == 0 )
      return;

  bufRect = VertexBuffer.Create(
  [ { data :  [ -1, -1, 1, -1, 1, 1, -1, 1 ], attrSize : 2, attrLoc : progDraw.inPos } ],
    [ 0, 1, 2, 0, 2, 3 ] );

  window.onresize = resize;
  resize();
  requestAnimationFrame(render);
}

function resize() {
  //vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
  vp_size = [window.innerWidth, window.innerHeight]
  vp_size[0] = vp_size[1] = Math.min(vp_size[0], vp_size[1]); 
  //vp_size = [256, 256]
  canvas.width = vp_size[0];
  canvas.height = vp_size[1];
}

var ShProg = {
Create: function (shaderList) {
  var shaderObjs = [];
  for (var i_sh = 0; i_sh < shaderList.length; ++i_sh) {
      var shderObj = this.Compile(shaderList[i_sh].source, shaderList[i_sh].stage);
      if (shderObj) shaderObjs.push(shderObj);
  }
  var prog = {}
  prog.progObj = this.Link(shaderObjs)
  if (prog.progObj) {
      prog.attrInx = {};
      var noOfAttributes = gl.getProgramParameter(prog.progObj, gl.ACTIVE_ATTRIBUTES);
      for (var i_n = 0; i_n < noOfAttributes; ++i_n) {
          var name = gl.getActiveAttrib(prog.progObj, i_n).name;
          prog.attrInx[name] = gl.getAttribLocation(prog.progObj, name);
      }
      prog.uniLoc = {};
      var noOfUniforms = gl.getProgramParameter(prog.progObj, gl.ACTIVE_UNIFORMS);
      for (var i_n = 0; i_n < noOfUniforms; ++i_n) {
          var name = gl.getActiveUniform(prog.progObj, i_n).name;
          prog.uniLoc[name] = gl.getUniformLocation(prog.progObj, name);
      }
  }
  return prog;
},
AttrI: function (prog, name) { return prog.attrInx[name]; },
UniformL: function (prog, name) { return prog.uniLoc[name]; },
Use: function (prog) { gl.useProgram(prog.progObj); },
SetI1: function (prog, name, val) { if (prog.uniLoc[name]) gl.uniform1i(prog.uniLoc[name], val); },
SetF1: function (prog, name, val) { if (prog.uniLoc[name]) gl.uniform1f(prog.uniLoc[name], val); },
SetF2: function (prog, name, arr) { if (prog.uniLoc[name]) gl.uniform2fv(prog.uniLoc[name], arr); },
SetF3: function (prog, name, arr) { if (prog.uniLoc[name]) gl.uniform3fv(prog.uniLoc[name], arr); },
SetF4: function (prog, name, arr) { if (prog.uniLoc[name]) gl.uniform4fv(prog.uniLoc[name], arr); },
SetM33: function (prog, name, mat) { if (prog.uniLoc[name]) gl.uniformMatrix3fv(prog.uniLoc[name], false, mat); },
SetM44: function (prog, name, mat) { if (prog.uniLoc[name]) gl.uniformMatrix4fv(prog.uniLoc[name], false, mat); },
Compile: function (source, shaderStage) {
  var shaderScript = document.getElementById(source);
  if (shaderScript)
      source = shaderScript.text;
  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 : null;
},
Link: 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(gl.getProgramInfoLog(prog));
  return status ? prog : null;
} };

var VertexBuffer = {
Create: function(attribs, indices, type) {
  var buffer = { buf: [], attr: [], inx: gl.createBuffer(), inxLen: indices.length, primitive_type: type ? type : gl.TRIANGLES };
  for (var i=0; i<attribs.length; ++i) {
      buffer.buf.push(gl.createBuffer());
      buffer.attr.push({ size : attribs[i].attrSize, loc : attribs[i].attrLoc, no_of: attribs[i].data.length/attribs[i].attrSize });
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buf[i]);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array( attribs[i].data ), gl.STATIC_DRAW);
  }
  gl.bindBuffer(gl.ARRAY_BUFFER, null);
  if ( buffer.inxLen > 0 ) {
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer.inx);
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW);
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  }
  return buffer;
},
Draw: function(bufObj) {
  for (var i=0; i<bufObj.buf.length; ++i) {
      gl.bindBuffer(gl.ARRAY_BUFFER, bufObj.buf[i]);
      gl.vertexAttribPointer(bufObj.attr[i].loc, bufObj.attr[i].size, gl.FLOAT, false, 0, 0);
      gl.enableVertexAttribArray( bufObj.attr[i].loc);
  }
  if ( bufObj.inxLen > 0 ) {
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufObj.inx);
      gl.drawElements(bufObj.primitive_type, bufObj.inxLen, gl.UNSIGNED_SHORT, 0);
      gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
  }
  else
      gl.drawArrays(bufObj.primitive_type, 0, bufObj.attr[0].no_of );
  for (var i=0; i<bufObj.buf.length; ++i)
      gl.disableVertexAttribArray(bufObj.attr[i].loc);
  gl.bindBuffer( gl.ARRAY_BUFFER, null );
} };

initScene();

})();       
<script id="draw-shader-fs" type="x-shader/x-fragment">
precision mediump float;
  
uniform vec2 resolution;
varying vec2 vpos;

vec3 col_fill = vec3(0.6);
vec3 col_back = vec3(0.0);

float scale = 3.0;

void main( void )
{
    vec2 pos = scale * vpos;
    float x = pos.x;
    float y = pos.y;

    float a0 = step(x*x + y*y, 1.0); 
    
    float y1 = 0.4*log(0.63*x+0.64)+1.8;
    float a1 = step(y, y1);

    float y2 = 0.3*log(10.0*x-2.0)+0.8;
    float a2 = step(y2, y) + step(x,0.2);

    float y3 = -0.1 * pow(x+-0.5, 2.0)+1.8;
    float a3 = step(y, y3);

    float a = max(a0, a1*a2*a3*step(0.0,y));

    vec3 rgb = mix(col_back, col_fill, a) + 0.4 * vec3(a1, a2, a3);
    
    gl_FragColor = vec4(rgb, 1.0);
}
</script>

<script id="draw-shader-vs" type="x-shader/x-vertex">
precision mediump float;

attribute vec2 inPos;
varying vec2 vpos;

void main()
{
    vpos = inPos.xy; 
    gl_Position = vec4( inPos.xy, 0.0, 1.0 );
}
</script>

<canvas id="texture-canvas" style="border: none"></canvas>
...