如何“陷阱"我的表面补丁可以防止背景从裂缝中渗出? [英] How to "trap" my surface patches to prevent the background from bleeding through the cracks?

查看:15
本文介绍了如何“陷阱"我的表面补丁可以防止背景从裂缝中渗出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了应对竞争中的.已完成的挑战可用 这里.]

%!%一个带阴影的圆柱体!呜呼!%(mat.ps) 运行%!%mat.ps%Matrix 和 Vector 数学例程/.error where { pop/signalerror { .error } def } if/dot { % u v2 复制长度 交换长度 ne {/dot cvx/undefinedresult 信号错误} 如果% 紫外线0 % u v 总和0 1 3 索引长度 1 sub { % u v sum i3 index 1 index get exch % u v sum u_i i3 index exch get % u v sum u_i v_imul add % u v sum% u v 总和3 1 roll pop pop % sum} 绑定定义% [ x1 x2 x3 ] [ y1 y2 y3 ] 交叉 [ x2*y3-y2*x3 x3*y1-x1*y3 x1*y2-x2*y1 ]/cross { % u vdup 长度 3 ne2 索引长度 3 ne 或 {/cross cvx/undefinedresult 信号错误} 如果% 紫外线exch aload pop 4 3 roll aload pop % x1 x2 x3 y1 y2 y3[5 索引 2 索引 mul % ... [ x2*y33 index 6 index mul sub % ... [ x2*y3-y2*x35 index 5 index mul % ... [ x2*y3-y2*x3 x3*y18 index 4 index mul sub % ... [ x2*y3-y2*x3 x3*y1-x1*y38 index 5 index mul % ... [ x2*y3-y2*x3 x3*y1-x1*y3 x1*y28 index 7 index mul sub % ... [ x2*y3-y2*x3 x3*y1-x1*y3 x1*y2-x2*y1]7 1 卷 6 { 弹出 } 重复} 绑定定义/transpose { STATICDICT 开始/A 交换定义/M 长度定义/N A 0 得到长度定义[0 1 N 1 sub {/n exch def[0 1 M 1 sub {/m exch def我得到 n 得到} 为了]} 为了]end } dup 0 6 dict put def/matmul { STATICDICT 开始/B 交换定义B 0 get type/arraytype ne {/B [B] def } if/A 交换定义A 0 get type/arraytype ne {/A [A] def } if/Q B 长度定义/R B 0 得到长度定义/P A 长度定义Q A 0 得到长度 ne {/A A 转置 def/P A 长度定义Q A 0 得到长度 ne {A B 端/matmul cvx/undefinedresult 信号错误} 如果} 如果[0 1 R 1 sub {/r exch def[0 1 P 1 sub {/p exch def00 1 Q 1 sub {/q exch defa p 得到 q 得到B q 得到 r 得到 mul添加} 为了} 为了]} 为了]end } dup 0 10 dict put def%u v {operator} vop u(op)v% 将二元运算符应用于相应的元素% 在两个向量中产生第三个向量作为结果/vop { 1 dict 开始/op 交换定义2 复制长度 交换长度 ne {/vop cvx 结束/undefinedresult 信号错误} 如果[ 3 1 卷 % [ u v0 1 2 索引长度 1 sub { % [ ... u v i3 复制 exch pop get % u v i u_i3 复制 pop get % u v i u_i v_iop exch pop % u v u_i(op)v_i3 1 滚动 % u_i(op)v_i u v} 对于 % [ ... u v流行流行]结束 } 定义% 向量的长度/mag { 0 exch { dup mul add } forall } def% x y z ang ->x y' z'/rotx { 3 dict 开始/theta exch def/z 交换定义/y 交换定义y theta cos mulz theta sin mul suby theta sin mulz theta cos mul add结束 } 定义% x y z ang ->x' y z'/roty { 4 dict 开始/theta exch def/z 交换定义/y 交换定义/x 交换定义x theta cos mulz theta sin mul add是x theta sin mul negz theta cos mul add结束 } 定义% x y z ang ->x' y' z/rotz { 4 dict 开始/theta exch def/z 交换定义/y 交换定义/x 交换定义x theta cos muly theta sin mul subx theta sin muly theta cos mul addz结束 } 定义% x y z ->x' y' z'/模型 {%ang 罗蒂%ang .25 mul rotx%alpha 旋转贝塔罗蒂伽玛轮定义% 眼坐标/ex .1 定义/ey .1 定义/ez 5 定义/eyedir [ex ey ez]dup mag [ exch dup dup ]{div} vop定义% x y z ->XY/项目 {3 字典开始/z 交换定义/y 交换定义/x 交换定义1 ez z 细分x ez mul z ex mul sub1 指数倍y ez mul z ey mul sub3 2 卷结束 } 定义/光[ 3 -7 -2 1 ]dup mag [ exch dup dup dup ]{div} vop定义/Ia .4 def % 事件环境强度/Ka .4 def % 环境漫反射常数/Il .5 def % 光源的入射强度/Kd .3 def % 漫反射常数%h R N/柱面{ 20 dict开始/N 交换定义/R 交换定义/h 交换定义/dz 1 N div def/dt 360 dz mul def/hdz h dz mul def0 dz 1 dz 子{h mul h 2 div sub/z exch def0 dt 360 {/t exch def/v1 [ t cos R mult sin R mulz ] 定义/v4 [ v1 aload pop popz hdz 添加] def/t t dt 添加定义/v2 [ t cos R mult sin R mulz ] 定义/v3 [ v2 aload pop popz hdz 添加] def[ v1 v2 v3 v4 ] {加载 4 1 卷模型 4 3 卷 astore pop} 对所有人/normal v4 v1 {sub} vopv2 v1 {sub} vop交叉定义/nlen 正常 mag def/normal 正常 [nlen nlen nlen] {div} vop def[normal aload pop 1] [eyedir aload pop 1] dot 0 lt {/action { moveto/action { lineto } def } def[ v1 v2 v3 v4 ]{ aload pop 项目动作}对所有人近距离% gsave[正常加载弹出1]光%[ex ey ez neg 1] %"radiant"点Il Kd mul mulIa Ka mul add设置灰色填% 存储%                中风} 如果} 为了} 为了结束 } 定义300 400 翻译280 dup dup movetodup neg dup neg linetodup neg dup linetodup neg lineto closepath .6 setgray 填充1 70 dup dup scale div setlinewidth%/beta 0 定义%/伽玛 0 定义%4 2 50 缸/beta 90 定义/伽玛 0 定义4 2 50缸%/beta 0 定义%/伽玛 90 def%4 2 50 缸显示页面

解决方案

好吧,我想出了一个更容易让人接受的方案.

6% 的捏造简直让人难以忍受.

但肯建议可能涉及四舍五入.这意味着控制四舍五入应该获得对问题的某种控制措施.而且看起来是真的.

所以我尝试在所有 movetolineto 调用前加上对 prep 的调用:

/prep {转变%2{% 交易所%地面圆形的%天花板%2 mul cvi 2 div %round%} 重复转换定义

评论显示了我尝试过的各种作品.对两个设备坐标进行舍入消除了所有水平出血线并留下非常细的垂直出血.假设 Ghostscript 通过水平扫描线光栅化,这似乎是有道理的:只需一点帮助,水平扫描线就更容易了,但接近垂直线更难.

但后来我将其与捏造结合起来.而且我发现只将设备 y 坐标四舍五入并将补丁尺寸修改 2% 可以消除所有流血.它真的照亮了这个蝙蝠洞.

我认为 2% 是可以接受的捏造水平.(?)

<小时>

不幸的是,当您调整 N 的值(切片数)时,以上所有内容都需要进行调整.覆盖整个表面的最简单的修复方法是用与填充相同的颜色描边边缘.这里唯一的难点是确保线宽适合比例.最简单的方法是将它们设置在一起.对于非常高的分辨率,这可能应该以某种方式进行调整以考虑 N.

1 70 dup dup scale div setlinewidth

<小时>

这是最终程序生成的图像之一,一个带有坐标轴和随机颜色的 Steinmetz 实体,视角略微倾斜(右脚稍微伸出一点).

In response to a challenge in comp.lang.postscript, I'm working-up my 3D chops trying to render a cylinder as projected rectangular patches. But I'm still seeing the wire-frame even after I comment-out the line-drawing, because the patches don't butt-up flush.

The cylinder is modeled along the z-axis by double-looping over z (-2 .. 2, step 4/N) and theta (0 .. 360, step 360/N). The four points of the rectangle are:

  • v1 = (Rcos T, Rsin T, z)
  • v4 = (Rcos T, Rsin T, z+dz)
  • v2 = (Rcos (T+dT), Rsin (T+dt), z)
  • v3 = (Rcos (T+dT), Rsin (T+dt), z+dz)

Then we apply a model->world rotation to all four points. Then we take the vectors v1->v4 and v1->v2 and do a cross product to get the normal vector for the patch. Take a dot product with the eye vector to check if the patch is on "this side" of the shape; if not, skip the drawing and procede to the next patch (fall off the bottom of the loop). Then we apply a perspective projection to each point and draw the quadrilateral with regular postscript 2D moveto and lineto. One last calculation on the normal vector to set the graylevel and then fill.

So the question is: Is there a usual way to deal with this? Is it a 3D problem or just a numerical problem (floating-point round-off kind of stuff)? Do I just add a little fudge-factor to my dz and dT when calculating the points? Or stroke the edges explicitly? These last 2 options both produce the desired result but I can't say that I'm satisfied with them. While each make be used on an individual illustration, it doesn't really solve the problem, you know?


I took a dump of the points being used. Here's the first few from N=12. It appears to me that, as predicted, v2 and v3 coincide precisely with v1 and v4 of the next piece on the band. These are the 2D "user coordinates" passed to moveto and lineto to produce the individual quadrilaterals. Since the CTM doesn't change, these points should map to the same pixels, right? So it does appear to be a very similar issue to the linked question. But I'm using Postscript precisely because I don't want to muck-about with writing my own rasterization routine :). I really think that the solution from the linked question, mapped to Postscript, would be to reverse the orientation of alternating checkerboard squares, at least for even N. That way, all corresponding edges are drawn in the same direction (as each other).

[-2.64550757 2.08465409]
[-3.00470281 1.69015563]
[-2.7090168 1.69015563]
[-2.38403082 2.08465409]

[-3.00470281 1.69015563]
[-3.28940701 0.936108589]
[-2.96660638 0.936108589]
[-2.7090168 1.69015563]

[-3.28940701 0.936108589]
[-3.4 -0.0666666701]
[-3.0666666 -0.0666666701]
[-2.96660638 0.936108589]

[-3.4 -0.0666666701]
[-3.28940701 -1.05890918]
[-2.96660638 -1.05890918]
[-3.0666666 -0.0666666701]

[-3.28940701 -1.05890918]
[-3.00470281 -1.78584146]
[-2.7090168 -1.78584146]
[-2.96660638 -1.05890918]


I've added a simple light model and tweaked it to bring out more mids. Jpeg output doesn't exhibit the problem, presumably due to the lossy compression. So here's a PNG snapshot.

The effect is much more apparent if I use the eye-vector as the light source. Here's xpost on the left showing the problem and gs on the right showing a modification where dz and dt are multiplied by a fudge factor of 1.06.

And the code: [Do not use this code. There is an error in the matmul routine. Corrected routines available here. Completed challenge available here.]

%!
%A shaded cylinder! Woohoo!

%(mat.ps) run
%!
%mat.ps
%Matrix and Vector math routines

/.error where { pop /signalerror { .error } def } if

/dot { % u v
    2 copy length exch length ne {
        /dot cvx /undefinedresult signalerror
    } if
    % u v
    0 % u v sum
    0 1 3 index length 1 sub { % u v sum i
        3 index 1 index get exch % u v sum u_i i
        3 index exch get % u v sum u_i v_i
        mul add % u v sum
    } for % u v sum

    3 1 roll pop pop % sum
} bind def

% [ x1 x2 x3 ] [ y1 y2 y3 ]  cross  [ x2*y3-y2*x3 x3*y1-x1*y3 x1*y2-x2*y1 ]
/cross { % u v
    dup length 3 ne
    2 index length 3 ne or {
        /cross cvx /undefinedresult signalerror
    } if
    % u v
    exch aload pop 4 3 roll aload pop % x1 x2 x3 y1 y2 y3
    [
        5 index 2 index mul % ... [ x2*y3
        3 index 6 index mul sub % ... [ x2*y3-y2*x3
        5 index 5 index mul % ... [ x2*y3-y2*x3 x3*y1
        8 index 4 index mul sub % ... [ x2*y3-y2*x3 x3*y1-x1*y3
        8 index 5 index mul % ... [ x2*y3-y2*x3 x3*y1-x1*y3 x1*y2
        8 index 7 index mul sub % ... [ x2*y3-y2*x3 x3*y1-x1*y3 x1*y2-x2*y1
    ]
    7 1 roll 6 { pop } repeat
} bind def

/transpose { STATICDICT begin
    /A exch def
    /M A length def
    /N A 0 get length def
    [
    0 1 N 1 sub { /n exch def
        [
        0 1 M 1 sub { /m exch def
            A m get n get
        } for
        ]
    } for
    ]
end } dup 0 6 dict put def

/matmul { STATICDICT begin
    /B exch def
    B 0 get type /arraytype ne { /B [B] def } if
    /A exch def
    A 0 get type /arraytype ne { /A [A] def } if
    /Q B length def
    /R B 0 get length def
    /P A length def
    Q A 0 get length ne {
        /A A transpose def
        /P A length def
        Q A 0 get length ne {
            A B end /matmul cvx /undefinedresult signalerror
        } if
    } if

    [
    0 1 R 1 sub { /r exch def
        [
        0 1 P 1 sub { /p exch def
            0
            0 1 Q 1 sub { /q exch def
                A p get q get
                B q get r get mul
                add
            } for
        } for
        ]
    } for
    ]

end } dup 0 10 dict put def

%u v {operator}  vop  u(op)v
%apply a binary operator to corresponding elements
%in two vectors producing a third vector as result
/vop { 1 dict begin
    /op exch def
    2 copy length exch length ne {
        /vop cvx end /undefinedresult signalerror
    } if

    [ 3 1 roll % [ u v
    0 1 2 index length 1 sub { % [ ... u v i
        3 copy exch pop get % u v i u_i
        3 copy pop get      % u v i u_i v_i
        op exch pop         % u v u_i(op)v_i
        3 1 roll            % u_i(op)v_i u v
    } for % [ ... u v
    pop pop ]

end } def


%length of a vector
/mag { 0 exch { dup mul add } forall } def

% x y z ang -> x y' z'
/rotx { 3 dict begin
    /theta exch def
    /z exch def
    /y exch def
    y theta cos mul
    z theta sin mul sub
    y theta sin mul
    z theta cos mul add
end } def

% x y z ang -> x' y z'
/roty { 4 dict begin
    /theta exch def
    /z exch def
    /y exch def
    /x exch def
    x theta cos mul
    z theta sin mul add
    y
    x theta sin mul neg
    z theta cos mul add
end } def

% x y z ang -> x' y' z
/rotz { 4 dict begin
    /theta exch def
    /z exch def
    /y exch def
    /x exch def
    x theta cos mul
    y theta sin mul sub
    x theta sin mul
    y theta cos mul add
    z
end } def

% x y z -> x' y' z'
/model {
%ang roty
%ang .25 mul rotx
%alpha rotz
beta roty
gamma rotx
} def

% Eye coords
/ex .1 def
/ey .1 def
/ez 5 def
/eyedir [ex ey ez]
    dup mag [ exch dup dup ]{div} vop
def

% x y z -> X Y
/project {
3 dict begin
    /z exch def
    /y exch def
    /x exch def
    1 ez z sub div
    x ez mul z ex mul sub
    1 index mul
    y ez mul z ey mul sub
    3 2 roll mul
end } def

/light
    [ 3 -7 -2 1 ]
    dup mag [ exch dup dup dup ]{div} vop
def
/Ia .4 def % Incident Ambient Intensity
/Ka .4 def % Ambient Diffuse reflection constant
/Il .5 def % Incident intensity of Lightsource
/Kd .3 def % Diffuse reflection constant

%h R N
/cylinder { 20 dict begin
    /N exch def
    /R exch def
    /h exch def
    /dz 1 N div def
    /dt 360 dz mul def
    /hdz h dz mul def

    0 dz 1 dz sub {
        h mul h 2 div sub /z exch def

        0 dt 360 { /t exch def
            /v1 [ t cos R mul
                t sin R mul
                z ] def
            /v4 [ v1 aload pop pop
                z hdz add ] def
            /t t dt add def
            /v2 [ t cos R mul
                t sin R mul
                z ] def
            /v3 [ v2 aload pop pop
                z hdz add ] def
            [ v1 v2 v3 v4 ] {
                aload 4 1 roll model 4 3 roll astore pop
            } forall
            /normal v4 v1 {sub} vop
                    v2 v1 {sub} vop
                    cross def
            /nlen normal mag def
            /normal normal [nlen nlen nlen] {div} vop def
            [normal aload pop 1] [eyedir aload pop 1] dot 0 lt {
                /action { moveto /action { lineto } def } def
                [ v1 v2 v3 v4 ]
                { aload pop project action }
                forall
                closepath
%                gsave
                    [normal aload pop 1]
                    light
                    %[ex ey ez neg 1] %"radiant"
                    dot
                    Il Kd mul mul
                    Ia Ka mul add
                    setgray
                    fill
%                grestore
%                stroke
            } if

        } for
    } for
end } def

300 400 translate
280 dup dup moveto
dup neg dup neg lineto
dup neg dup lineto
dup neg lineto closepath .6 setgray fill
1 70 dup dup scale div setlinewidth

%/beta 0 def
%/gamma 0 def
%4 2 50 cylinder

/beta 90 def
/gamma 0 def
4 2 50 cylinder

%/beta 0 def
%/gamma 90 def
%4 2 50 cylinder

showpage   

解决方案

Alright, I've come up with something that sits a little easier in the gut.

6% fudging just feels to horrible to bear.

But Ken suggested that rounding could be involved. That means taking control of the rounding should gain one some measure of control over the problem. And it looks like it's true.

So I tried prepending all moveto and lineto calls with a call to prep:

/prep {
    transform
    %2 {
    %    exch
        %floor
        round
        %ceiling
        %2 mul cvi 2 div %round
    %} repeat
    itransform
} def

The comments show the various pieces I tried. Rounding on both device coordinates eliminated all horizontal bleed-lines and leaves very thin vertical bleeds. This seems to make sense assuming Ghostscript rasterizes by horizontal scanlines: it has an easier time with the horizontal ones with just a little help, but near-verticals are tougher.

But then I combined this with fudging. And I found that rounding just the device-y 'ordinate and fudging the patch dimensions by 2% eliminates all bleeds. It really lit up this batcave.

2% is an acceptable level of fudging, I think. (?)


Unfortunately, all the above requires tweaking when you adjust the value of N (the number of slices). The simplest fix to cover the whole surface is to stroke the edges in the same color as the fill. The only difficult point here is making sure the linewidth is appropriate for the scale. And the easy way to do that is to set them both together. For very high resolutions, this should probably be adjusted in some way to account for N.

1 70 dup dup scale div setlinewidth


Here's one of the images generated by the final program, a Steinmetz solid with coordinate axes and random colors, in a slightly skewed perspective (its right foot sticks out a little).

这篇关于如何“陷阱"我的表面补丁可以防止背景从裂缝中渗出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆