graphics 3d postscript

graphics - ¿Cómo "atrapar" mis parches de superficie para evitar que el fondo se desangre por las grietas?



3d postscript (1)

Bien, he encontrado algo que se siente un poco más fácil en el intestino.

6% de fudge simplemente se siente horrible de soportar.

Pero Ken sugirió que el redondeo podría estar involucrado. Eso significa que tomar el control del redondeo debería obtener una cierta medida de control sobre el problema. Y parece que es verdad.

Así que probé anteponiendo todas las llamadas moveto y lineto con una llamada a prep :

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

Los comentarios muestran las diversas piezas que probé. El redondeo en ambas coordenadas del dispositivo eliminó todas las líneas de sangrado horizontal y deja sangrados verticales muy delgados. Esto parece tener sentido suponiendo que Ghostscript rasteriza por líneas de exploración horizontales: tiene un tiempo más fácil con las horizontales con solo un poco de ayuda, pero las casi verticales son más difíciles.

Pero luego combiné esto con fudging. Y encontré que al redondear solo el dispositivo -y ''ordenando y modificando las dimensiones del parche en un 2%, se eliminan todas las hemorragias. Realmente iluminó esta cueva de murciélagos.

El 2% es un nivel aceptable de fudge, creo. (?)

Lamentablemente, todo lo anterior requiere ajustes cuando ajusta el valor de N (el número de cortes). La solución más sencilla para cubrir toda la superficie es trazar los bordes del mismo color que el relleno. El único punto difícil aquí es asegurarse de que el ancho de línea sea apropiado para la báscula. Y la manera más fácil de hacerlo es unirlos a los dos. Para resoluciones muy altas, esto probablemente debería ajustarse de alguna manera para dar cuenta de N.

1 70 dup dup scale div setlinewidth

Esta es una de las imágenes generadas por el programa final, un sólido de Steinmetz con ejes coordinados y colores aleatorios, en una perspectiva ligeramente sesgada (su pie derecho sobresale un poco).

En respuesta a un desafío en comp.lang.postscript, estoy trabajando mis chuletas 3D tratando de renderizar un cilindro como parches rectangulares proyectados. Pero sigo viendo el marco de alambre incluso después de comentar el trazado de línea, porque los parches no se acumulan.

El cilindro se modela a lo largo del eje z haciendo doble clic sobre z (-2 .. 2, paso 4 / N) y theta (0 .. 360, paso 360 / N). Los cuatro puntos del rectángulo son:

  • v1 = (R cos T, R sin T, z)
  • v4 = (R cos T, R sin T, z + dz)
  • v2 = (R cos (T + dT), R sin (T + dt), z)
  • v3 = (R cos (T + dT), R sin (T + dt), z + dz)

Luego aplicamos un modelo-> rotación mundial a los cuatro puntos. Luego tomamos los vectores v1-> v4 y v1-> v2 y hacemos un producto cruzado para obtener el vector normal para el parche. Tome un producto de puntos con el vector del ojo para verificar si el parche está en "este lado" de la forma; si no, omita el dibujo y proceda al próximo parche (caiga del fondo del bucle). Luego aplicamos una proyección en perspectiva a cada punto y dibujamos el cuadrilátero con un movimiento de posdata 2D en 2D y línea. Un último cálculo en el vector normal para establecer el nivel graylevel y luego llenar.

Entonces la pregunta es: ¿hay una manera usual de lidiar con esto? ¿Es un problema 3D o simplemente un problema numérico (redondeo de punto flotante)? ¿Acabo de agregar un poco de Fudge-factor a mi dz y dT al calcular los puntos? ¿O acaricia los bordes de forma explícita? Estas dos últimas opciones producen el resultado deseado, pero no puedo decir que esté satisfecho con ellas. Si bien cada uno se utiliza en una ilustración individual, en realidad no resuelve el problema , ¿sabes?

Tomé un volcado de los puntos que se utilizan. Aquí están los primeros de N = 12. Me parece que, como se predijo, v2 y v3 coinciden precisamente con v1 y v4 de la siguiente pieza de la banda . Estas son las "coordenadas de usuario" 2D pasadas a moveto y lineto para producir los cuadriláteros individuales. Dado que la CTM no cambia, estos puntos deben asignarse a los mismos píxeles, ¿no? Por lo tanto, parece ser un problema muy similar a la cuestión vinculada. Pero estoy usando Postscript precisamente porque no quiero perder el tiempo escribiendo mi propia rutina de rasterización :). Realmente creo que la solución de la pregunta vinculada, asignada a Postscript, sería invertir la orientación de los cuadrados alternos de tablero de ajedrez, al menos para incluso N. De esta manera, todos los bordes correspondientes se dibujan en la misma dirección (como el uno al otro).

[-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]

He agregado un modelo ligero simple y lo pellizqué para traer más medios. La salida de Jpeg no muestra el problema, presumiblemente debido a la compresión con pérdida. Así que aquí hay una instantánea PNG.

El efecto es mucho más evidente si utilizo el vector ocular como fuente de luz. Aquí está xpost a la izquierda mostrando el problema ygs a la derecha mostrando una modificación donde dz y dt se multiplican por un factor de fundición de 1.06.

Y el código: [ No use este código. Hay un error en la rutina matmul. Rutinas corregidas disponibles aquí . Completed challenge disponible aquí . ]

%! %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