2011-12-28 43 views
5

Tôi định tạo một trình chỉnh sửa ảnh đơn giản trong JS. Câu hỏi chính của tôi là, có thể tạo bộ lọc hiển thị trong thời gian thực không? Ví dụ, điều chỉnh độ sáng và độ bão hòa. Tất cả những gì tôi cần là một hình ảnh 2D, nơi tôi có thể áp dụng các bộ lọc bằng cách sử dụng GPU.Xử lý hình ảnh 2D với WebGL

Tất cả các hướng dẫn tôi đã đọc rất phức tạp và không thực sự giải thích ý nghĩa của API. Hãy chỉ cho tôi hướng đi đúng. Cảm ơn.

Trả lời

3

Bạn có thể tạo một trình đổ bóng pixel tùy chỉnh cho từng thao tác bạn định sử dụng. Chỉ cần tìm hiểu một số GLSL và làm theo hướng dẫn "Learning WebGL" để nắm bắt WebGL cơ bản.

Bạn có thể hiển thị hình ảnh của mình bằng trình chỉnh sửa thông số bạn có thể bao gồm để kiểm soát các kiểu trực quan khác nhau và sau đó khi người dùng nhấp "ok", bạn có thể đọc lại pixel để lưu trữ làm hình ảnh hiện tại của mình.

Chỉ cần nhớ tránh hình ảnh tên miền chéo, vì điều đó sẽ vô hiệu hóa việc đọc lại pixel.

Ngoài ra, hãy kiểm tra quick reference card (PDF) để biết thông tin nhanh về các hoạt động của trình đổ bóng.

+0

Bây giờ tôi có thể hiển thị hình ảnh phẳng trên canvas. Có thể viết nó mà không có phần 3D không? Đối với tài liệu học tập, tôi nên tìm chính xác những gì? Dường như có OpenGL ES, OpenGL bình thường, GLSL, WebGL cùng với tất cả các phiên bản khác nhau. –

+0

Bạn chỉ có thể vẽ kết cấu của mình bằng phép chiếu orographic với màn hình tứ giác thẳng hàng. Từ tài liệu học tập, bạn có thể tập trung vào GLSL là ngôn ngữ bạn sẽ sử dụng cho các hiệu ứng của mình – Chiguireitor

17

Tôi sẽ viết một hướng dẫn và đăng lên blog của mình nhưng tôi không biết khi nào tôi sẽ có thời gian để hoàn thành, dưới đây là những gì tôi có Here's a more detailed set of posts on my blog.

WebGL thực sự là thư viện rasterization. Tôi lấy các thuộc tính (luồng dữ liệu), đồng phục (biến) và hy vọng bạn cung cấp tọa độ "khoảng trống" trong dữ liệu 2d và màu cho pixel.

Dưới đây là một ví dụ đơn giản của 2d trong WebGL (một số chi tiết rời ra)

// Get A WebGL context 
var gl = canvas.getContext("experimental-webgl"); 

// setup GLSL program 
vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader"); 
fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader"); 
program = createProgram(gl, vertexShader, fragmentShader); 
gl.useProgram(program); 

// look up where the vertex data needs to go. 
var positionLocation = gl.getAttribLocation(program, "a_position"); 

// Create a buffer and put a single clipspace rectangle in 
// it (2 triangles) 
var buffer = gl.createBuffer(); 
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
    -1.0, -1.0, 
    1.0, -1.0, 
    -1.0, 1.0, 
    -1.0, 1.0, 
    1.0, -1.0, 
    1.0, 1.0]), gl.STATIC_DRAW); 
gl.enableVertexAttribArray(positionLocation); 
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); 

// draw 
gl.drawArrays(gl.TRIANGLES, 0, 6); 

Đây là 2 shaders

<script id="2d-vertex-shader" type="x-shader/x-vertex"> 
attribute vec2 a_position; 
void main() { 
    gl_Position = vec4(a_position, 0, 1); 
} 
</script> 

<script id="2d-fragment-shader" type="x-shader/x-fragment"> 
void main() { 
    gl_FragColor = vec4(0,1,0,1); // green 
} 
</script> 

này sẽ vẽ một hình chữ nhật màu xanh lá cây toàn bộ kích thước của canvas.

Trong WebGL, bạn có trách nhiệm cung cấp trình đổ bóng đỉnh cung cấp các tọa độ không gian. Các tọa độ không gian luôn luôn đi từ -1 đến +1 bất kể kích thước của canvas. Nếu bạn muốn 3ngày nó thuộc vào bạn để cung cấp shaders rằng chuyển đổi từ 3D sang 2D vìWebGL chỉ là một API rasterization

Trong một ví dụ đơn giản, nếu bạn muốn làm việc theo pixel bạn có thể vượt qua trong một hình chữ nhật có sử dụng pixel thay vì tọa kẹp không gian và chuyển đổi để cắt không gian trong shader

Ví dụ:

<script id="2d-vertex-shader" type="x-shader/x-vertex"> 
attribute vec2 a_position; 

uniform vec2 u_resolution; 

void main() { 
    // convert the rectangle from pixels to 0.0 to 1.0 
    vec2 zeroToOne = a_position/u_resolution; 

    // convert from 0->1 to 0->2 
    vec2 zeroToTwo = zeroToOne * 2.0; 

    // convert from 0->2 to -1->+1 (clipspace) 
    vec2 clipSpace = zeroToTwo - 1.0; 

    gl_Position = vec4(clipSpace, 0, 1); 
} 
</script> 

Bây giờ chúng ta có thể vẽ hình chữ nhật bằng cách thay đổi các dữ liệu chúng tôi cung cấp

// set the resolution 
var resolutionLocation = gl.getUniformLocation(program, "u_resolution"); 
gl.uniform2f(resolutionLocation, canvas.width, canvas.height); 

// setup a rectangle from 10,20 to 80,30 in pixels 
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
    10, 20, 
    80, 20, 
    10, 30, 
    10, 30, 
    80, 20, 
    80, 30]), gl.STATIC_DRAW); 

Bạn sẽ thấy WebGL xem góc dưới cùng bên phải là 0,0. Để làm cho nó trở thành góc trên cùng bên phải truyền thống được sử dụng cho đồ họa 2d, chúng tôi chỉ cần lật tọa độ y.

gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); 

Bạn muốn thao tác hình ảnh mà bạn cần chuyển vào họa tiết.Trong cùng một cách kích thước của canvas được đại diện bởi clipspace phối kết cấu đang được tham chiếu bởi tọa độ texture mà đi từ 0 đến 1.

<script id="2d-vertex-shader" type="x-shader/x-vertex"> 
attribute vec2 a_position; 
attribute vec2 a_texCoord; 

uniform vec2 u_resolution; 

varying vec2 v_texCoord; 

void main() { 
    // convert the rectangle from pixels to 0.0 to 1.0 
    vec2 zeroToOne = a_position/u_resolution; 

    // convert from 0->1 to 0->2 
    vec2 zeroToTwo = zeroToOne * 2.0; 

    // convert from 0->2 to -1->+1 (clipspace) 
    vec2 clipSpace = zeroToTwo - 1.0; 

    gl_Position = vec4(clipSpace, 0, 1); 

    // pass the texCoord to the fragment shader 
    // The GPU will interpolate this value between points. 
    v_texCoord = a_texCoord; 
} 
</script> 

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

// our texture 
uniform sampler2D u_image; 

// the texCoords passed in from the vertex shader. 
varying vec2 v_texCoord; 

void main() { 
    gl_FragColor = texture2D(u_image, v_texCoord); 
} 
</script> 

Để vẽ một hình ảnh đòi hỏi tải hình ảnh và kể từ đó xảy ra không đồng bộ chúng ta cần để thay đổi mã của chúng tôi một chút. Lấy tất cả mã chúng tôi có và đặt nó vào một hàm có tên "render"

var image = new Image(); 
image.src = "http://someimage/on/our/server"; // MUST BE SAME DOMAIN!!! 
image.onload = function() { 
    render(); 
} 

function render() { 
    ... 
    // all the code we had before except gl.draw 


    // look up where the vertex data needs to go. 
    var texCoordLocation = gl.getAttribLocation(program, "a_texCoord"); 

    // provide texture coordinates for the rectangle. 
    var texCoordBuffer = gl.createBuffer(); 
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
     1.0, 1.0, 
     0.0, 1.0, 
     0.0, 0.0, 
     1.0, 1.0, 
     0.0, 0.0, 
     1.0, 0.0]), gl.STATIC_DRAW); 
    gl.enableVertexAttribArray(texCoordLocation); 
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0); 

    var texture = gl.createTexture(); 
    gl.bindTexture(gl.TEXTURE_2D, texture); 
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 

    gl.draw(...) 

Nếu bạn muốn xử lý hình ảnh, bạn chỉ cần thay đổi trình đổ bóng. Ví dụ: Hoán đổi màu đỏ và màu xanh

Hoặc kết hợp với các pixel bên cạnh.

uniform vec2 u_textureSize; 

void main() { 
    vec2 onePixel = vec2(1.0, 1.0)/u_textureSize; 
    gl_FragColor = (texture2D(u_image, v_texCoord) + 
        texture2D(u_image, v_texCoord + vec2(onePixel.x, 0.0)) + 
        texture2D(u_image, v_texCoord + vec2(-onePixel.x, 0.0)))/3.0; 
} 

Và chúng ta phải vượt qua trong kích thước của kết cấu

var textureSizeLocation = gl.getUniformLocation(program, "u_textureSize"); 
... 
gl.uniform2f(textureSizeLocation, image.width, image.height); 

Etc ... Nhấp vào liên kết cuối cùng dưới đây cho một mẫu chập.

Dưới đây là phiên bản làm việc với một tiến triển hơi khác nhau

Draw Rect in Clip Space

Draw Rect in Pixels

Draw Rect with origin at top left

Draw a bunch of rects in different colors

Draw an image

Draw an image red and blue swapped

Draw an image with left and right pixels averaged

Draw an image with a 3x3 convolution

Draw an image with multiple effects

+0

Cảm ơn bạn đã giải thích chi tiết. Tôi đang gặp một chút vấn đề ở đây, hy vọng bạn biết về nó. http://stackoverflow.com/questions/8679596/extra-space-in-webgl-despite-same-dimension –

+0

Một câu hỏi khác. Làm cách nào để tự động gọi kết hợp các hàm dựa trên đầu vào của người dùng? Đối với exmaple, blur + saturation hoặc chỉ làm sắc nét một mình. Trong ví dụ của bạn tôi thấy bạn sử dụng hạt nhân, một cái gì đó tôi không hiểu. Cảm ơn. –

+0

Tôi nhận được hạt nhân từ đây (http://docs.gimp.org/en/plug-in-convmatrix.html) và tại đây (http://www.codeproject.com/KB/graphics/ImageConvolution.aspx) Để thêm chúng lên, bạn có 2 thứ trên đỉnh đầu. # 1) bạn có thể cố gắng tạo bóng râm khi đang di chuyển. # 2) bạn có thể hiển thị với bộ đệm khung và lặp lại cho từng bước – gman

0

Chỉ cần cố gắng glfx (http://evanw.github.com/glfx.js/) Tôi nghĩ rằng đó là chính xác những gì bạn cần. Bạn có thể sử dụng bộ các trình đổ bóng được xác định trước hoặc dễ dàng thêm của bạn;) tận hưởng! Nó rất dễ dàng với glfx!

<script src="glfx.js"></script> 
<script> 

window.onload = function() { 
    // try to create a WebGL canvas (will fail if WebGL isn't supported) 
    try { 
     var canvas = fx.canvas(); 
    } catch (e) { 
     alert(e); 
     return; 
    } 

    // convert the image to a texture 
    var image = document.getElementById('image'); 
    var texture = canvas.texture(image); 

    // apply the ink filter 
    canvas.draw(texture).ink(0.25).update(); 

    // replace the image with the canvas 
    image.parentNode.insertBefore(canvas, image); 
    image.parentNode.removeChild(image); 
}; 

</script> 
<img id="image" src="image.jpg"> 
Các vấn đề liên quan