¿Qué tipo de desenfoques se pueden implementar en los sombreadores de píxeles?

Gaussiano, cuadro, radial, direccional, desenfoque de movimiento, desenfoque de zoom, etc.

Leí que el desenfoque gaussiano se puede dividir en pases que podrían implementarse en sombreadores de píxeles, pero no pude encontrar ninguna muestra.

¿Es correcto suponer que cualquier efecto relacionado con píxeles que no sean ellos mismos no se puede implementar en sombreadores de píxeles?

preguntado el 01 de julio de 12 a las 14:07

4 Respuestas

Puede implementar todo, siempre que pueda pasar información al sombreador.

El truco, en estos casos, es realizar un renderizado de varias pasadas. El sombreador final tomará una cierta cantidad de muestras, que son las fuentes no borrosas, que se utilizan para calcular los valores borrosos.

Por ejemplo, es posible usar múltiples texturas para emular efectos basados ​​en el búfer de acumulación.


para implementar un desenfoque gaussiano, renderice la escena en un objeto frambuffer, con una textura adjunta en el archivo adjunto de color. Este es el primer pase.

Como segundo paso, renderice un quad texturizado, donde la textura es la generada en el primer paso. Las coordenadas de las texturas se pasan de la etapa de vértice a la etapa de fragmento, interpoladas a lo largo del cuádruple. De hecho, tiene coordenadas de textura para cada fragmento; aplique un desplazamiento para cada coordenada para obtener textos alrededor del subyacente y realice el desenfoque gaussiano.

Respondido 01 Jul 12, 15:07

Gracias, ¿qué tipo de entradas puedo pasar para estos desenfoques? Pensé que solo obtenía un píxel y sus colores, etc., no sus coordenadas ni nada más. Además, ¿sabe cómo podría implementar un desenfoque gaussiano o de cuadro como un sombreador de píxeles? - joan venganza

'tubería' general para efectos de posprocesamiento

setRenderTarget(myRenderTarget); // or FBO in GL
drawAwsomeScene();

setdefaultRenderTarget();   // draw to screen...

blurShader.use();
// shader needs to know what is the size of one pixel on the screen
blurShader.uniform2f("texelSize", 1/screenW, 1/screenH);

// set the texture with scene rendered...
setRenderTargetTexture();

drawFullScreenQuad();

// other effects...

ejemplos útiles/tutorial para desenfoque: http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/

Respondido 03 Jul 12, 12:07

Implementé un sombreador de fragmentos de convolución genérico (sombreador de píxeles)

#version 120

uniform sampler2D texUnit;
uniform float[9] conMatrix;
uniform float conWeight;
uniform vec2 conPixel;

void main(void)
{
    vec4 color = vec4(0.0);
    vec2 texCoord = gl_TexCoord[0].st;
    vec2 offset = conPixel * 1.5;
    vec2 start = texCoord - offset;
    vec2 current = start;

    for (int i = 0; i < 9; i++)
    {
        color += texture2D( texUnit, current ) * conMatrix[i]; 

        current.x += conPixel.x;
        if (i == 2 || i == 5) {
            current.x = start.x;
            current.y += conPixel.y; 
        }
    }

    gl_FragColor = color * conWeight;
}

Para un desenfoque:

where conPixel is {1/screen width, 1/screen height}
where conMatrix is {1.0, 1.0, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0, 1.0}
where conWeight is 1.0 / 9.0
where texUnit is 0

Respondido 08 ago 12, 15:08

Una implementación que se ve a menudo para lograr un efecto de desenfoque de una escena es la Desenfoque gaussiano, implementado por un post-procesamiento de 2 pases.
Esta es una aproximación que primero se difumina a lo largo del eje X en el primer paso y a lo largo del eje Y en el segundo paso (o viceversa). Esto da como resultado un mejor rendimiento para un fuerte desenfoque.
El sombreador de desenfoque utiliza un distribución normal (o gaussiana). Para las 2 pasadas se usa el mismo programa de sombreado, con configuraciones de dirección individuales para las 2 pasadas, almacenadas en el uniforme vec2 u_dir. La fuerza del efecto de desenfoque se puede variar con la variable uniforme float u_sigma en el rango [0.0, 1.0].
La escena se escribe en el búfer de fotogramas con una textura vinculada al plano de color. Un pase de espacio de pantalla usa la textura como entrada para desenfocar la salida a lo largo del eje X. El pase de desenfoque del eje X escribe en otro búfer de cuadro, con una textura vinculada a su plano de color. Esta textura se utiliza como entrada para el proceso de desenfoque final a lo largo del eje Y.
Puede encontrar una descripción detallada del algoritmo de desenfoque en la respuesta a la pregunta OpenGL es 2.0 desenfoque gaussiano en triángulo or LeranOpenGL - Desenfoque gaussiano.

mancha Sombreador de vértices

#version 330

in  vec2 inPos;
out vec2 pos;

void main()
{
    pos = inPos;
    gl_Position = vec4( inPos, 0.0, 1.0 );
}

mancha Sombreador de fragmentos

#version 330

in vec2 pos;

uniform sampler2D u_texture;
uniform vec2      u_textureSize;
uniform float     u_sigma;
uniform vec2      u_dir;

float CalcGauss( float x, float sigma )
{
    if ( sigma <= 0.0 )
        return 0.0;
  return exp( -(x*x) / (2.0 * sigma) ) / (2.0 * 3.14157 * sigma);
}

void main()
{
    vec2 texC     = pos.st * 0.5 + 0.5;
    vec4 texCol   = texture2D( u_texture, texC );
    vec4 gaussCol = vec4( texCol.rgb, 1.0 );
    vec2 step     = u_dir / u_textureSize;
    for ( int i = 1; i <= 32; ++ i )
    {
        float weight = CalcGauss( float(i) / 32.0, u_sigma * 0.5 );
        if ( weight < 1.0/255.0 )
            break;
        texCol    = texture2D( u_texture, texC + step * float(i) );
        gaussCol += vec4( texCol.rgb * weight, weight );
        texCol    = texture2D( u_texture, texC - step * float(i) );
        gaussCol += vec4( texCol.rgb * weight, weight );
    }
    gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
    gl_FragColor = vec4( gaussCol.rgb, 1.0 );
}

Vea también las respuestas a la siguiente pregunta:

Vea un ejemplo de WebGL:

var readInput = true;
function changeEventHandler(event){
readInput = true;
}

(function loadscene() {

var resize, gl, progDraw, progBlur, vp_size, blurFB;
var canvas;
var camera;
var bufCube = {};
var bufQuad = {};
var shininess = 10.0;
var glow = 10.0;
var sigma = 0.8;
var radius = 1.0;

function render(deltaMS){

    if ( readInput ) {
        //readInput = false;
        var sliderScale = 100;
        sigma     = document.getElementById( "sigma" ).value / sliderScale;
        radius    = document.getElementById( "radius" ).value / sliderScale;
    }

    vp_size = [canvas.width, canvas.height];
    camera.Update( vp_size );
        
    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 );

    // set up framebuffer
    gl.bindFramebuffer( gl.FRAMEBUFFER, blurFB[0] );
    gl.viewport( 0, 0, blurFB[0].width, blurFB[0].height );
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );

    // setup view projection and model
    var prjMat = camera.Perspective();
    var viewMat = camera.Orbit();
    var modelMat = IdentM44();
    modelMat = camera.AutoModelMatrix();
    
    // set up draw shader
    ShProg.Use( progDraw.prog );
    ShProg.SetM44( progDraw.prog, "u_projectionMat44", prjMat );
    ShProg.SetM44( progDraw.prog, "u_modelViewMat44", Multiply(viewMat, modelMat) );
    ShProg.SetF1( progDraw.prog, "u_shininess", shininess );
    
    // draw scene
    VertexBuffer.Draw( bufCube );

    // set blur-X framebuffer and bind frambuffer texture
    gl.bindFramebuffer( gl.FRAMEBUFFER, blurFB[1] );
    gl.viewport( 0, 0, blurFB[1].width, blurFB[1].height );
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
    var texUnit = 1;
    gl.activeTexture( gl.TEXTURE0 + texUnit );
    gl.bindTexture( gl.TEXTURE_2D, blurFB[0].color0_texture );

    // set up blur-X shader
    ShProg.Use( progBlur.prog );
    ShProg.SetI1( progBlur.prog, "u_texture", texUnit )
    ShProg.SetF2( progBlur.prog, "u_textureSize", vp_size );
    ShProg.SetF1( progBlur.prog, "u_sigma", sigma )
    ShProg.SetF1( progBlur.prog, "u_radius", radius )
    ShProg.SetF2( progBlur.prog, "u_dir", [1.0, 0.0] )

    // draw full screen space
    gl.enableVertexAttribArray( progBlur.inPos );
    gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
    gl.vertexAttribPointer( progBlur.inPos, 2, gl.FLOAT, false, 0, 0 ); 
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
    gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
    gl.disableVertexAttribArray( progBlur.inPos );

    // reset framebuffer and bind frambuffer texture
    gl.bindFramebuffer( gl.FRAMEBUFFER, null );
    gl.viewport( 0, 0, vp_size[0], vp_size[1] );
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
    texUnit = 2;
    gl.activeTexture( gl.TEXTURE0 + texUnit );
    gl.bindTexture( gl.TEXTURE_2D, blurFB[1].color0_texture );

    // set up pst process shader
    ShProg.SetI1( progBlur.prog, "u_texture", texUnit )
    ShProg.SetF1( progBlur.prog, "u_radius", radius )
    ShProg.SetF2( progBlur.prog, "u_dir", [0.0, 1.0] )

    // draw full screen space
    gl.enableVertexAttribArray( progBlur.inPos );
    gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
    gl.vertexAttribPointer( progBlur.inPos, 2, gl.FLOAT, false, 0, 0 ); 
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
    gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
    gl.disableVertexAttribArray( progBlur.inPos );

    requestAnimationFrame(render);
}

function initScene() {

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

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

    progBlur = {}
    progBlur.prog = ShProg.Create( 
    [ { source : "post-shader-vs", stage : gl.VERTEX_SHADER },
        { source : "blur-shader-fs", stage : gl.FRAGMENT_SHADER }
    ] );
    progBlur.inPos = gl.getAttribLocation( progBlur.prog, "inPos" );
    if ( !progBlur.prog )
        return;    
    
    // create cube
    var cubePos = [
    -1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  1.0,  1.0,  1.0, -1.0,  1.0,  1.0,
    -1.0, -1.0, -1.0,  1.0, -1.0, -1.0,  1.0,  1.0, -1.0, -1.0,  1.0, -1.0 ];
    var cubeCol = [ 1.0, 0.0, 0.0, 1.0, 0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ];
    var cubeHlpInx = [ 0, 1, 2, 3, 1, 5, 6, 2, 5, 4, 7, 6, 4, 0, 3, 7, 3, 2, 6, 7, 1, 0, 4, 5 ];  
    var cubePosData = [];
    for ( var i = 0; i < cubeHlpInx.length; ++ i ) {
    cubePosData.push( cubePos[cubeHlpInx[i]*3], cubePos[cubeHlpInx[i]*3+1], cubePos[cubeHlpInx[i]*3+2] );
    }
    var cubeNVData = [];
    for ( var i1 = 0; i1 < cubeHlpInx.length; i1 += 4 ) {
    var nv = [0, 0, 0];
    for ( i2 = 0; i2 < 4; ++ i2 ) {
        var i = i1 + i2;
        nv[0] += cubePosData[i*3]; nv[1] += cubePosData[i*3+1]; nv[2] += cubePosData[i*3+2];
    }
    for ( i2 = 0; i2 < 4; ++ i2 )
    cubeNVData.push( nv[0], nv[1], nv[2] );
    }
    var cubeColData = [];
    for ( var is = 0; is < 6; ++ is ) {
    for ( var ip = 0; ip < 4; ++ ip ) {
        cubeColData.push( cubeCol[is*3], cubeCol[is*3+1], cubeCol[is*3+2] ); 
    }
    }
    var cubeInxData = [];
    for ( var i = 0; i < cubeHlpInx.length; i += 4 ) {
    cubeInxData.push( i, i+1, i+2, i, i+2, i+3 );   
    }
    bufCube = VertexBuffer.Create(
    [ { data : cubePosData, attrSize : 3, attrLoc : progDraw.inPos },
    { data : cubeNVData,  attrSize : 3, attrLoc : progDraw.inNV },
    { data : cubeColData, attrSize : 3, attrLoc : progDraw.inCol } ],
    cubeInxData );

    bufQuad.pos = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
    gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ] ), gl.STATIC_DRAW );
    bufQuad.inx = gl.createBuffer();
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
    gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ), gl.STATIC_DRAW );  
    
    camera = new Camera( [0, 3, 0.0], [0, 0, 0], [0, 0, 1], 90, vp_size, 0.5, 100 );

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

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

    var fbsize = Math.max(vp_size[0], vp_size[1]);
    fbsize = 1 << 31 - Math.clz32(fbsize); // nearest power of 2

    blurFB = [];
    for ( var i = 0; i < 2; ++ i ) {
        fb = gl.createFramebuffer();
        fb.width = fbsize;
        fb.height = fbsize;
        gl.bindFramebuffer( gl.FRAMEBUFFER, fb );
        fb.color0_texture = gl.createTexture();
        gl.bindTexture( gl.TEXTURE_2D, fb.color0_texture );
        gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
        gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
        gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, fb.width, fb.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
        fb.renderbuffer = gl.createRenderbuffer();
        gl.bindRenderbuffer( gl.RENDERBUFFER, fb.renderbuffer );
        gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, fb.width, fb.height );
        gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fb.color0_texture, 0 );
        gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fb.renderbuffer );
        gl.bindTexture( gl.TEXTURE_2D, null );
        gl.bindRenderbuffer( gl.RENDERBUFFER, null );
        gl.bindFramebuffer( gl.FRAMEBUFFER, null );
        blurFB.push( fb );
    }
}

function Fract( val ) { 
    return val - Math.trunc( val );
}
function CalcAng( deltaTime, intervall ) {
    return Fract( deltaTime / (1000*intervall) ) * 2.0 * Math.PI;
}
function CalcMove( deltaTime, intervall, range ) {
    var pos = self.Fract( deltaTime / (1000*intervall) ) * 2.0
    var pos = pos < 1.0 ? pos : (2.0-pos)
    return range[0] + (range[1] - range[0]) * pos;
}    
function EllipticalPosition( a, b, angRag ) {
    var a_b = a * a - b * b
    var ea = (a_b <= 0) ? 0 : Math.sqrt( a_b );
    var eb = (a_b >= 0) ? 0 : Math.sqrt( -a_b );
    return [ a * Math.sin( angRag ) - ea, b * Math.cos( angRag ) - eb, 0 ];
}

function IdentM44() {
    return [ 1, 0, 0, 0,    0, 1, 0, 0,    0, 0, 1, 0,    0, 0, 0, 1 ];
};

function RotateAxis(matA, angRad, axis) {
    var aMap = [ [1, 2], [2, 0], [0, 1] ];
    var a0 = aMap[axis][0], a1 = aMap[axis][1]; 
    var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad);
    var matB = matA.slice(0);
    for ( var i = 0; i < 3; ++ i ) {
        matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng;
        matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng;
    }
    return matB;
}

function Rotate(matA, angRad, axis) {
    var s = Math.sin(angRad), c = Math.cos(angRad);
    var x = axis[0], y = axis[1], z = axis[2]; 
    matB = [
        x*x*(1-c)+c,   x*y*(1-c)-z*s, x*z*(1-c)+y*s, 0,
        y*x*(1-c)+z*s, y*y*(1-c)+c,   y*z*(1-c)-x*s, 0,
        z*x*(1-c)-y*s, z*y*(1-c)+x*s, z*z*(1-c)+c,   0,
        0,             0,             0,             1 ];
    return Multiply(matA, matB);
}    

function Multiply(matA, matB) {
    matC = IdentM44();
    for (var i0=0; i0<4; ++i0 )
        for (var i1=0; i1<4; ++i1 )
            matC[i0*4+i1] = matB[i0*4+0] * matA[0*4+i1] + matB[i0*4+1] * matA[1*4+i1] + matB[i0*4+2] * matA[2*4+i1] + matB[i0*4+3] * matA[3*4+i1]  
    return matC;
}

function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; }
function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
function Normalize( v ) {
    var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
    return [ v[0] / len, v[1] / len, v[2] / len ];
}

Camera = function( pos, target, up, fov_y, vp, near, far ) {
this.Time = function() { return Date.now(); }
this.pos = pos;
this.target = target;
this.up = up;
this.fov_y = fov_y;
this.vp = vp;
this.near = near;
this.far = far;
this.orbit_mat = this.current_orbit_mat = this.model_mat = this.current_model_mat = IdentM44();
this.mouse_drag = this.auto_spin = false;
this.auto_rotate = true;
this.mouse_start = [0, 0];
this.mouse_drag_axis = [0, 0, 0];
this.mouse_drag_angle = 0;
this.mouse_drag_time = 0;
this.drag_start_T = this.rotate_start_T = this.Time();
this.Ortho = function() {
    var fn = this.far + this.near;
    var f_n = this.far - this.near;
    var w = this.vp[0];
    var h = this.vp[1];
    return [
        2/w, 0,   0,       0,
        0,   2/h, 0,       0,
        0,   0,   -2/f_n,  0,
        0,   0,   -fn/f_n, 1 ];
};  
this.Perspective = function() {
    var n = this.near;
    var f = this.far;
    var fn = f + n;
    var f_n = f - n;
    var r = this.vp[0] / this.vp[1];
    var t = 1 / Math.tan( Math.PI * this.fov_y / 360 );
    return [
        t/r, 0, 0,          0,
        0,   t, 0,          0,
        0,   0, -fn/f_n,   -1,
        0,   0, -2*f*n/f_n, 0 ];
}; 
this.LookAt = function() {
    var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] );
    var mx = Normalize( Cross( this.up, mz ) );
    var my = Normalize( Cross( mz, mx ) );
    var tx = Dot( mx, this.pos );
    var ty = Dot( my, this.pos );
    var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos ); 
    return [mx[0], my[0], mz[0], 0, mx[1], my[1], mz[1], 0, mx[2], my[2], mz[2], 0, tx, ty, tz, 1]; 
};
this.Orbit = function() {
    return Multiply(this.LookAt(), this.OrbitMatrix());
}; 
this.OrbitMatrix = function() {
    return (this.mouse_drag || (this.auto_rotate && this.auto_spin)) ? Multiply(this.current_orbit_mat, this.orbit_mat) : this.orbit_mat;
};
this.AutoModelMatrix = function() {
    return this.auto_rotate ? Multiply(this.current_model_mat, this.model_mat) : this.model_mat;
};
this.Update = function(vp_size) {
    if (vp_size)
        this.vp = vp_size;
    var current_T = this.Time();
    this.current_model_mat = IdentM44()
    if (this.mouse_drag) {
        this.current_orbit_mat = Rotate(IdentM44(), this.mouse_drag_angle, this.mouse_drag_axis);
    } else if (this.auto_rotate) {
        if (this.auto_spin ) {
            if (this.mouse_drag_time > 0 ) {
                var angle = this.mouse_drag_angle * (current_T - this.rotate_start_T) / this.mouse_drag_time;
                this.current_orbit_mat = Rotate(IdentM44(), angle, this.mouse_drag_axis);
            }
        } else {
            var auto_angle_x = Fract( (current_T - this.rotate_start_T) / 13000.0 ) * 2.0 * Math.PI;
            var auto_angle_y = Fract( (current_T - this.rotate_start_T) / 17000.0 ) * 2.0 * Math.PI;
            this.current_model_mat = RotateAxis( this.current_model_mat, auto_angle_x, 0 );
            this.current_model_mat = RotateAxis( this.current_model_mat, auto_angle_y, 1 );
        }
    }
};
this.ChangeMotionMode = function(drag, spin, auto ) {
    var new_drag = drag;
    var new_auto = new_drag ? false : auto;
    var new_spin = new_auto ? spin : false;
    change = this.mouse_drag != new_drag || this.auto_rotate != new_auto || this.auto_spin != new_spin; 
    if (!change)
        return;
    if (new_drag && !this.mouse_drag) {
        this.drag_start_T = this.Time();
        this.mouse_drag_angle = 0.0;
        this.mouse_drag_time = 0;
    }
    if (new_auto && !this.auto_rotate)
        this.rotate_start_T = this.Time();
    this.mouse_drag = new_drag; 
    this.auto_rotate = new_auto;  
    this.auto_spin = new_spin;
    this.orbit_mat = Multiply(this.current_orbit_mat, this.orbit_mat);
    this.current_orbit_mat = IdentM44();
    this.model_mat = Multiply(this.current_model_mat, this.model_mat);
    this.current_model_mat = IdentM44();
};
this.OnMouseDown = function( event ) {
    var rect = gl.canvas.getBoundingClientRect();
    if ( event.clientX < rect.left || event.clientX > rect.right ) return;
    if ( event.clientY < rect.top || event.clientY > rect.bottom ) return;
    if (event.button == 0) { // left button
        this.mouse_start = [event.clientX, event.clientY]; 
        this.ChangeMotionMode( true, false, false );
    }
};
this.OnMouseUp = function( event ) {
    if (event.button == 0) { // left button
        this.ChangeMotionMode( false, true, true );
    } else if (event.button == 1) {// middle button
        this.ChangeMotionMode( false, false, !this.auto_rotate );
    }
};
this.OnMouseMove = function( event ) {
    var dx = (event.clientX-this.mouse_start[0]) / this.vp[0];
    var dy = (event.clientY-this.mouse_start[1]) / this.vp[1];
    var len = Math.sqrt(dx*dx + dy*dy);
    if (this.mouse_drag && len > 0) {
        this.mouse_drag_angle = Math.PI*len;
        this.mouse_drag_axis = [dy/len, 0, -dx/len];
        this.mouse_drag_time = this.Time() - this.drag_start_T;
    }
};

this.domElement = document;
var cam = this;
//this.domElement.addEventListener( 'contextmenu', function(e) { event.preventDefault(); }, false );
this.domElement.addEventListener( 'mousedown', function(e) { cam.OnMouseDown(e) }, false );
this.domElement.addEventListener( 'mouseup', function(e) { cam.OnMouseUp(e) }, false );
this.domElement.addEventListener( 'mousemove', function(e) { cam.OnMouseMove(e) }, false );
//this.domElement.addEventListener( 'mousewheel', hid_events.onMouseWheel, false );
//this.domElement.addEventListener( 'DOMMouseScroll', hid_events.onMouseWheel, false ); // firefox
}

var ShProg = {};
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 == 0 )
            return 0;
        shaderObjs.push( shderObj );
    }
    var progObj = this.Link( shaderObjs )
    if ( progObj != 0 ) {
        progObj.attrInx = {};
        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.attrInx[name] = gl.getAttribLocation( progObj, name );
        }
        progObj.uniLoc = {};
        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.uniLoc[name] = gl.getUniformLocation( progObj, name );
        }
    }
    return progObj;
}
ShProg.AttrI = function( progObj, name ) { return progObj.attrInx[name]; } 
ShProg.UniformL = function( progObj, name ) { return progObj.uniLoc[name]; } 
ShProg.Use = function( progObj ) { gl.useProgram( progObj ); } 
ShProg.SetI1  = function( progObj, name, val ) { if(progObj.uniLoc[name]) gl.uniform1i( progObj.uniLoc[name], val ); }
ShProg.SetF1  = function( progObj, name, val ) { if(progObj.uniLoc[name]) gl.uniform1f( progObj.uniLoc[name], val ); }
ShProg.SetF2  = function( progObj, name, arr ) { if(progObj.uniLoc[name]) gl.uniform2fv( progObj.uniLoc[name], arr ); }
ShProg.SetF3  = function( progObj, name, arr ) { if(progObj.uniLoc[name]) gl.uniform3fv( progObj.uniLoc[name], arr ); }
ShProg.SetF4  = function( progObj, name, arr ) { if(progObj.uniLoc[name]) gl.uniform4fv( progObj.uniLoc[name], arr ); }
ShProg.SetM33 = function( progObj, name, mat ) { if(progObj.uniLoc[name]) gl.uniformMatrix3fv( progObj.uniLoc[name], false, mat ); }
ShProg.SetM44 = function( progObj, name, mat ) { if(progObj.uniLoc[name]) gl.uniformMatrix4fv( progObj.uniLoc[name], false, mat ); }
ShProg.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;
} 
ShProg.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("Could not initialise shaders");
    gl.useProgram( null );
    return status ? prog : null;
}

var VertexBuffer = {
Create: function(attribs, indices) {
    var buffer = { buf: [], attr: [], inx: gl.createBuffer(), inxLen: indices.length };
    for (var i=0; i<attribs.length; ++i) {
        buffer.buf.push(gl.createBuffer());
        buffer.attr.push({ size : attribs[i].attrSize, loc : attribs[i].attrLoc });
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buf[i]);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array( attribs[i].data ), gl.STATIC_DRAW);
    }
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer.inx);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    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);
    }
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufObj.inx);
    gl.drawElements(bufObj.primitve_type ? bufObj.primitve_type : gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0);
    for (var i=0; i<bufObj.buf.length; ++i)
       gl.disableVertexAttribArray(bufObj.attr[i].loc);
    gl.bindBuffer( gl.ARRAY_BUFFER, null );
    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
} };

initScene();

})();
html,body { margin: 0; overflow: hidden; }
#gui { position : absolute; top : 0; left : 0; }
<script id="draw-shader-vs" type="x-shader/x-vertex">
precision mediump float;

attribute vec3 inPos;
attribute vec3 inNV;
attribute vec3 inCol;

varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;

uniform mat4 u_projectionMat44;
uniform mat4 u_modelViewMat44;

void main()
{
    vertNV      = mat3( u_modelViewMat44 ) * normalize( inNV );
    vertCol     = inCol;
    vec4 pos    = u_modelViewMat44 * vec4( inPos, 1.0 );
    vertPos     = pos.xyz / pos.w;
    gl_Position = u_projectionMat44 * pos;
}
</script>

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

varying vec3 vertPos;
varying vec3 vertNV;
varying vec3 vertCol;

uniform float u_shininess;

void main()
{
    vec3 color = vertCol;
    vec3  normalV  = normalize( vertNV );
    vec3  eyeV     = normalize( -vertPos );
    vec3  halfV    = normalize( eyeV + normalV );
    float NdotH    = max( 0.0, dot( normalV, halfV ) );
    float shineFac = ( u_shininess + 2.0 ) * pow( NdotH, u_shininess ) / ( 2.0 * 3.14159265 );
    gl_FragColor   = vec4( color.rgb * (0.2 + NdotH), 1.0 );
} 
</script>

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

attribute vec2 inPos;

varying   vec2 pos;

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

<script id="blur-shader-fs" type="x-shader/x-fragment">
precision mediump float;

varying vec2 pos;

uniform sampler2D u_texture;
uniform vec2      u_textureSize;
uniform float     u_sigma;
uniform float     u_radius;
uniform vec2      u_dir;

float CalcGauss( float x, float sigma )
{
    if ( sigma <= 0.0 )
        return 0.0;
  return exp( -(x*x) / (2.0 * sigma) ) / (2.0 * 3.14157 * sigma);
}

void main()
{
    vec2 texC     = pos.st * 0.5 + 0.5;
    vec4 texCol   = texture2D( u_texture, texC );
    vec4 gaussCol = vec4( texCol.rgb, 1.0 );
    vec2 step     = u_dir / u_textureSize;
    for ( int i = 1; i <= 32; ++ i )
    {
        float weight = CalcGauss( float(i) / 32.0, u_sigma * 0.5 );
        if ( weight < 1.0/255.0 )
            break;
        texCol    = texture2D( u_texture, texC + u_radius * step * float(i) );
        gaussCol += vec4( texCol.rgb * weight, weight );
        texCol    = texture2D( u_texture, texC - u_radius * step * float(i) );
        gaussCol += vec4( texCol.rgb * weight, weight );
    }
    gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
    gl_FragColor = vec4( gaussCol.rgb, 1.0 );
}
</script>

<div>
<form id="gui" name="inputs">
<table>
<tr> <td> <font color= #CCF>radius</font> </td> 
        <td> <input type="range" id="radius" min="1" max="1000" value="350" onchange="changeEventHandler(event);"/></td> </tr>
<tr> <td> <font color= #CCF>blur</font> </td> 
        <td> <input type="range" id="sigma" min="1" max="100" value="5" onchange="changeEventHandler(event);"/></td> </tr>
</table>
</form>
</div>

<canvas id="canvas" style="border: none;"></canvas>

Respondido el 12 de diciembre de 19 a las 17:12

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.