2015-05-30 18 views
10

Tôi đang cố gắng viết một hàm trong GLSL trả về khoảng cách đã ký cho hình chữ nhật. Hình chữ nhật được căn chỉnh theo trục. Tôi cảm thấy một chút khó khăn; Tôi chỉ không thể quấn đầu xung quanh những gì tôi cần làm để làm cho nó hoạt động.Tính toán khoảng cách đã ký giữa điểm và hình chữ nhật

Điều tốt nhất tôi đã đưa ra là thế này:

float sdAxisAlignedRect(vec2 uv, vec2 tl, vec2 br) 
{ 
    // signed distances for x and y. these work fine. 
    float dx = max(tl.x - uv.x, uv.x - br.x); 
    float dy = max(tl.y - uv.y, uv.y - br.y); 
    dx = max(0.,dx); 
    dy = max(0.,dy); 
    return sqrt(dx*dx+dy*dy); 
} 

nào tạo ra một hình chữ nhật giống như:

enter image description here

Các dòng hiển thị khoảng cách từ hình chữ nhật. Nó hoạt động tốt nhưng CHỈ cho khoảng cách NGOÀI hình chữ nhật. Bên trong hình chữ nhật, khoảng cách là tĩnh 0..

Làm thế nào để tôi cũng nhận được khoảng cách chính xác bên trong hình chữ nhật bằng cách sử dụng công thức hợp nhất?

Trả lời

13

Làm thế nào về vấn đề này ...

float sdAxisAlignedRect(vec2 uv, vec2 tl, vec2 br) 
{ 
    vec2 d = max(tl-uv, uv-br); 
    return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y)); 
} 

Đây là result, nơi đánh dấu màu xanh lá cây một khoảng cách tích cực và tiêu cực đỏ (mã dưới đây):

enter image description here


Breakdown:

  1. Nhận khoảng cách đã ký từ đường viền x và y. u - leftright - u là khoảng cách hai trục x. Lấy tối đa các giá trị này cho khoảng cách đã ký với đường viền gần nhất. Xem d.xd.y được hiển thị riêng lẻ trong các hình ảnh bên dưới.

  2. Kết hợp x và y:

    1. Nếu cả hai giá trị là tiêu cực, lấy tối đa (ví dụ gần nhất với đường biên giới). Điều này được thực hiện với min(0.0, max(d.x, d.y)).

    2. Nếu chỉ có một giá trị là dương, đó là khoảng cách chúng tôi muốn.

    3. Nếu cả hai giá trị đều dương, điểm gần nhất là góc, trong trường hợp đó chúng tôi muốn độ dài. Điều này có thể được kết hợp với trường hợp trên bằng cách lấy chiều dài và đảm bảo cả hai giá trị là dương: length(max(vec2(0.0), d)).

    Hai phần này với phương trình loại trừ lẫn nhau, nghĩa là chỉ có một phần sẽ tạo ra giá trị khác 0 và có thể được cộng lại.

enter image description hereenter image description here


void mainImage(out vec4 fragColor, in vec2 fragCoord) 
{ 
    vec2 uv = fragCoord.xy/iResolution.xy; 
    uv -= 0.5; 
    uv *= vec2(iResolution.x/iResolution.y,1.0); 
    uv += 0.5; 
    float d = sdAxisAlignedRect(uv, vec2(0.3), vec2(0.7)); 
    float m = 1.0 - abs(d)/0.1; 
    float s = sin(d*400.0) * 0.5 + 0.5; 
    fragColor = vec4(s*m*(-sign(d)*0.5+0.5),s*m*(sign(d)*0.5+0.5),0,1); 
} 
+0

Tuyệt vời! Công việc có hoàn hảo không. – tenfour

+0

@jozxyqk Bạn đã nghĩ ra chức năng này như thế nào? –

+0

@ v.shashenko dùng thử và lỗi thực sự. Tôi đã cập nhật câu trả lời để đi vào chi tiết hơn một chút. – jozxyqk

Các vấn đề liên quan