javascript - Hacer que el llenado del lienzo incluya el trazo en las formas
Ok, entonces estoy haciendo un motor de renderizado 3D en JavaScript puro, como un desafío, por supuesto, para probar mis habilidades de álgebra lineal. No estoy usando WebGL, así que por favor no digas "usa WebGL".
De todos modos, el software tomará triángulos, una cámara y transformaciones locales, y representará los datos en la pantalla (incluso lo hice interactivo)
Sin embargo, solo hay 6 líneas de código de renderizado, que son:
// some shading and math calculations then this:
context.fillStyle = color;
context.strokeStyle = color;
context.beginPath();
context.moveTo(x0, y0);
context.lineTo(x1, y1);
context.lineTo(x2, y2);
context.lineTo(x0, y0);
context.closePath();
context.fill();
context.stroke();
Y aunque eso funciona, cae a 10 fps con caras de más de 4k en mi Chromebook. (60 fps en una computadora normal)
De todos modos, eso produce esto:
Pero para hacerlo más rápido, y porque los cambios de estado del lienzo son lentos, eliminé el trazo, haciendo que el código de renderizado sea:
// some shading and math calculations then this:
context.fillStyle = color;
//context.strokeStyle = color;
context.beginPath();
context.moveTo(x0, y0);
context.lineTo(x1, y1);
context.lineTo(x2, y2);
context.lineTo(x0, y0);
context.closePath();
context.fill();
//context.stroke();
que funciona el doble de rápido, pero lo que se muestra en la pantalla es esto: (modelo diferente)
que tiene líneas feas en todas partes en los bordes de los triángulos (que se eliminan cuando vuelvo a agregar el trazo)
Sin embargo, los fps se duplican y las ganancias de rendimiento son grandes...
Así que creo que las líneas se deben a que el relleno del lienzo no incluye el área donde se habría trazado (el contorno, por así decirlo).
He intentado arreglarlo con matemáticas, y aunque funciona hay algunos casos extremos en los que no lo hace
Entonces mi pregunta es la siguiente: ¿Hay alguna manera de hacer que el relleno del contexto incluya el área del trazo sin trazar, porque es muy costoso?
Respuesta #1
Usar tanto el trazo como el relleno forzará la rasterización dos veces, lo que explica el tiempo aproximadamente doble.
La razón por la que obtienes fallos entre los triángulos se debe a errores de redondeo y al anti-aliasing. No hay una solución directa para esto; el trazo cubrirá los fallos, por supuesto, pero hacerlo sin el trazo requerirá que desplaces y expandas al menos cada dos triángulos.
Sin embargo, podrías usar un pequeño truco para cubrir el hueco, y eso es volver a dibujar toda la imagen (como mapa de bits) encima desplazada solo un píxel (podrías salirte con 0,5 píxeles, pero entonces se necesitaría antialiasing). Esto añade tiempo, pero mucho menos que la rasterización o el recálculo de las rutas.
Di que el resultado a la izquierda es lo que tienes (simulado aquí) con un claro espacio. Volver a dibujarlo encima como se muestra a la derecha cubrirá el espacio sin demasiada distorsión.
Simplemente usa:
ctx.drawImage(sourceCanvas, 1, 1);
Consejo: al llamar solo a fill() no necesitas closePath() ya que se llama implícitamente, ahorrando una operación. Ganancia microscópica quizás, pero aún así (con geometría más compleja incluso podría tener influencia :) ).
Nota: dibujar sobre sí mismo causará una asignación interna de una copia temporal del bitmap. Sin embargo, solo necesitarás hacer una operación extra de drawImage(). La opción es usar renderizado fuera del lienzo pero dibujar dos veces en un lienzo principal mostrado. De cualquier manera...
var ctx = c.getContext("2d");
ctx.fillStyle = "#777";
tri(10,10, 72,17, 40.2, 100);
// simulates gap
ctx.fillStyle = "#222";
tri(72.5,17.5, 40.7,100.5, 90,25);
// fill entire image back again, drawn twice here for demo
ctx.drawImage(c, 100, 0);
ctx.drawImage(c, 0, 0, 100, 150, 101, 1, 100, 150);
ctx.fillText("Raster", 5, 8);
ctx.fillText("Offset self", 105, 8);
function tri(x0,y0,x1,y1,x2,y2) {
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.fill();
}<canvas id=c></canvas>

