Ver la versión completa : Una ayuda mezclando colores
anibarro
18/03/2008, 20:22
Buenas, tengo un problemilla de rendimiento a la hora de suavizar texturas, y estoy buscando una forma de suavizarla que sea mas rapida.
Digamos que tengo los 6 puntos de la primera imagen, y necesito colorear el espacio intermedio.
La forma que mas rapida me va, es la de no interpolar y pintar la mitad de cada color.
Interpolando el color de cada punto en funcion de la distancia a cada vertice da una resultado impresionante, pero es MUY lento, al menos con las funciones que uso de una-i para hacer blend entre dos colores RGB565.
Lo que busco es hacer una especie de "dither", aunque sea de baja calidad, para mezclar los colores, ahorrando crear otros nuevos. Adjunto tambien imagen de el dither que hablo, aunque no necesito que sea de tanta calida claro.
¿Alguien sabe una forma rapida de conseguir esto? La funcion que uso ahora para hallar el color del punto es GE_BlendColors565(color1, color2, porcentaje)
Gracias ;)
Con dithering siempre sera mas lento, si interpolas el color sin "desempaquetarlo" ira mas rapido pero tendra un poco menos de calidad... pon el codigo de la funcion y se podra ver que se puede mejorar.
anibarro
18/03/2008, 21:31
Intente encontrar una manera de interpolar el color directamente, sin descomponerlo, pero no se me ocurrio como :S
La funcion esta sacada de aqui: http://www.flipcode.com/archives/Color_Manipulation.shtml
Y es esta:
//----------------------------------------------------------------------
// Use: Make a 32 levels alfa blend betwen two 565 colours.
// Returns: The blended colour.
// Parameters: iAlfa=0 Only c1 is set, iAlfa=32 only c2 is set
//----------------------------------------------------------------------
__inline unsigned GE_BlendColors565( const unsigned c1, const unsigned c2, int iAlfa)
{
unsigned ta = c1 & MASCARA_A; // 0000__g1__
unsigned tb = c2 & MASCARA_B; // 0000r2__b2
ta *= (32-iAlfa);
tb *= ( iAlfa);
ta += ( iAlfa) *(c2 & MASCARA_A); // 0000__g2__
tb += (32-iAlfa) *(c1 & MASCARA_B); // 0000r1__b1
ta = (ta>>BITS_BAJOS) & MASCARA_A;
ta += (tb>>BITS_BAJOS) & MASCARA_B;
return(ta);
}
(En el link salen los defines que faltan)
A mi me daba la impresion que el dithering seria mucho mas rapido, digamos que la funcion que te dice el color en funcion de un parametro, lo calcularia a partir de un valor predefinido.
El problema es que no se como calcular ese valor predefinido. Habia pensado crear un vector tal que asi (de 16 niveles por ejemplo): [1110110101001000] y si le pido el nivel 0, devolveria el color de la derecha pq hay un 1, si le pido el nivel 3 devolveria el de la izquierda, y asi...pero sale un bodrio :(
Si se pudiese hacer algo asi, se podrian implementar en un numero de 16 o 32bits en vez de un vector, y aun iria mas rapido
y no has pensado en hacer una escala menos suave? se ve que con el blend recalculas todos los colores pero yo pienso que con calcular unos pocos y hacer alguna media con los restantes deberia quedar decente, es que con lo del "porcentaje" creo que se va un buen pico de CPU y recurrir a ella menos es lo suyo.
Quizad lo que te interese sea mas algún calculo de filtrado bilinear, quizad mirando el codigo de algun que otro emulador puedas sacar algo util.
anibarro
18/03/2008, 22:40
Darumo no se cuanto ayudaria eso...en realidad lo que hace es filtrado bilinear, y el porcentaje solo tiene 32 niveles, no creo que bajarlo mas ayudase mucho :/
Adjunto 3 imagenes, una sin filtrado, otra con filtrado bilinear y otra con el cutre dither que probe...la idea es encontrar un dither que sea rapido y no quede tan mal como ese :/
Yo busco conseguir algo como este dithering: http://www.flipcode.com/archives/Realtime_Voxel_Landscape_Engines-Part_5_Quality_Improvement.shtml
Ahi va mi dithering que hice el siglo pasado...
#include "dither.h"
#define ABS(x) ((x>0)? ( x) : (-x) )
#define SGN(x) ((x<0)? (-1) : ( 1) )
#define SCREEN_ADR 0xa000
#define SCREEN_ADR_LIN ((SCREEN_ADR) << 4 )
void DitherUp(int xi, int xf, int y, unsigned ci, unsigned cf)
{
char *screen;
long dcolor;
short int icolor,error;
short unsigned color;
char c;
screen=(char *)SCREEN_ADR_LIN+xi+y*320;
c=ci>>8;
dcolor=((long)(cf-ci)<<8) / (xf-xi);
icolor=(dcolor>>16);
dcolor&=0xffff;
color=ci<<8;
error=0x8000;
while (xi<=xf) {
if ( (error+=(color>>1)) >0 ){
error+=0x8000;
*screen++=(c+1);
} else
*screen++=c;
c+=icolor;
if ((color+=dcolor) < dcolor)
c++;
xi++;
}
}
void DitherDown(int xi, int xf, int y, unsigned ci, unsigned cf)
{
char *screen;
long dcolor;
short int icolor,error;
short unsigned color;
char c;
screen=(char *)SCREEN_ADR_LIN+xf+y*320;
c=cf>>8;
dcolor=( (long) (ci-cf)<<8 ) / (xf-xi);
icolor=(dcolor>>16);
dcolor&=0xffff;
color=cf<<8;
error=0x8000;
while (xi<=xf) {
if ( (error+=(color>>1)) >0 ) {
error+=0x8000;
*screen--=(c+1);
} else
*screen--=c;
c+=icolor;
if ((color+=dcolor) < dcolor)
c++;
xi++;
}
}
void DitherSpan(short xi, short xf, short y, short unsigned ci, short unsigned cf)
{
if(xi<xf)
((ci<=cf)? DitherUp(xi,xf,y,ci,cf) : DitherDown(xi,xf,y,ci,cf) );
}
uff, cuantos comentarios, ya se sabe, si costo programarlo debe costar entenderlo...
Un par de cosas, como se ve esta hecho para el modo 0x13, pero no creo que tengas muchos problemas en cambiarlo, incluso en usar colores leyendolos de una tabla.
Hay dos rutinas una para hacer el dithering hacia arriba (con colores cada vez mayores o con un incide mayor), y otra hacia abajo. Se supone que estas dos versiones serian privadas, el usuario solo usaria DitherSpan.
En el codigo veras cosas un poco raras como los 0x8000, esto es porque la primera version la hice en ensamblador del 68000 y las rutinas usaban el bit de carry, como en C no puedes hacer saltos dependiedo de los bits de estado hay que hacer estas chapucillas.
Los parametros son los siguientes:
xi : coordenada x Inicial...
xf : coordenada x final, siempre mayor que xi
y : coordenada y de la linea horizontal con dithering
ci : color inicial (16 bits), se supone que el byte alto es el indice del color o a una tabla, la parte baja serian la parte decimal del color
cf: color final, igual que el inicialPara hacer dithering en un cuadrado asegurate de que la parte decimal del color varia, o apareceran unas lineas verticales.
No tengo imagenes de como queda pero si has visto la intro del Interfase del Atari ST (el cubo con sombreado gouraud), es exactamente igual... la saque de ahi[wei5]
anibarro
19/03/2008, 00:17
Ahora veo porque decias que iba a ser mas lento xD Muchas gracias pero necesito algo mucho mas simple :( Creo que al final se quedara sin filtrar...
¿Y se puede saber que estas haciendo para la 2x? es que tiene una pintaza...
anibarro
19/03/2008, 15:56
De momento solo estoy viendo si es viable hacer una especie de remake del outcast, pero hasta que no acabe de añadirle cosas y empiece a optimizar no lo sabre...
No tengo la gp2x, por lo que lo estoy haciendo las pruebas en un gps con un ARM9 y 64MB. Esta todo programado a partir de un acceso directo al buffer de la pantalla, por lo que compilarlo para la GP2X serian 2 minutos
Uau! un remake del outcast! seria increible.
Pero el outcast original necesitava un pentium 3 a 500Mhz con 128 megas para ir bien... aunque si le quitas todos los efectos...
jean la montard
19/03/2008, 21:04
aunque sea sin filtrar ya mereceria la pena :amor2:
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.