PDA

View Full Version : [Vari/C++/lowlevel] Bitwise Operations e Bitmasks, non ci capisco una ceppa!


Tommo
21-10-2009, 15:07
Salve,
ho bisogno di creare uno sparo che colpisca tutto tranne i soldati del mio team.
In concreto, uso PhysX e questo si può fare assegnando ad ogni Forma una Mask/Group, e quindi filtrando questi ShapeGroup tramite una bitwise Mask apposita.

La Shape Mask è definita come unsigned short e va da 0 a 31;
la bitwise mask è un unsigned int.

In teoria, ogni team ha una specifica Shape Mask; quindi lancio un Ray che attraversa la scena, configurato per escludere tutte le mask diverse da quelle del mio team.

In pratica essendo completamente a digiuno di operazioni bitwise, non ho idea di come creare un raggio che colpisca tutti i gruppi (0, 30) ma non quello del mio team (31) e viceversa per il nemico (0,31)(30) :muro:

Per ora usavo la maschera ottenuta dal codice (trovato in giro:asd:):

unsigned short teamMask = 0x1f; //31
unsigned int mask = ~(1<< teamMask );

Tuttavia qualsiasi sia teamMask questo mi ritorna 65535... per cui (anche se ignoro il motivo) viene ignorato tutto escluso il gruppo (0).

Mi serve l'aiuto di qualche lowlevel pro :asd:

banryu79
21-10-2009, 17:48
Ciao Tommo,
se la mask di un Ray deve "escludere" tutte le mask diverse dal tuo team, significa che, viceversa, deve "includere" solo la mask del tuo team.

Se il ragionamento è corretto presumo che l'operazione che avviene tra la ray_mask e tutte le group_mask intersecate dal ray sia un semplice & (AND) tra la group_mask da testare e il valore della ray_mask negata (NOT ~).
Se il risultato di questa operazione è diverso da zero (almeno un bit è rimasto a 1) allora la group_mask testata è "esclusa" (cioè colpita dal ray).

// per ogni team_mask intersecata dal Ray
result_mask = team_mask & (~ray_mask);
if (result_mask != 0) {
// colpito-escluso
}

Con questa operazione esiste una sola group_mask che risulterebbe "esclusa" (cioè non colpita): la grop_mask di valore uguale alla ray_mask ;)

Per rendere la cosa un attimo più visiva:

myteam_mask = [1][1][1][1][1][1] // vale 31
myray_mask = [1][1][1][1][1][1]

~myray_mask -->[0][0][0][0][0][0]

myteam_mask & (~myray_mask) --> [1][1][1][1][1][1] & [0][0][0][0][0][0] --> 0
Tutti i falg a zero, cioè "non colpito".
Qualsiasi altra mask produrrebbe almeno un flag di vlaore 1, "cioè colpito".

Spero di non aver capito male :D

Tommo
22-10-2009, 14:23
Allora,
intanto grazie per la risposta :D

la cosa è molto contorta e le evidenze sperimentali ancora di più :asd:
-le mask numero pari non trovano il gruppo 0.
-la maschera che passi dice cosa NON toccare, cioè se mask & shapeMask != 0 allora non viene visto.

Ad esempio assegnando al p1 e al p2 i numeri 1 e 3, si ha che ray( ..., 1 & 3,... ) ignora tutto tranne il suolo.

Siam riusciti ad ottenere quello che serve (cioè che lo sparo colpisce 0 e gruppo_nemico) usando l'arcana formula
~(1<<teamGroup)

Comunque non ne vedo ancora il verso :asd:

PS: sapendo questo, come faccio a creare una mask che vede unicamente 0?
Teoricamente sarebbe NOT 0 ma praticamente non va :asd:

marco.r
23-10-2009, 12:02
Premessa: quando hai a che fare con bitmask, non pensare tanto ai valori dei numeri quanto ai bit che sono a 1.

Non conosco Physix, ma il fatto che la shape mask abbia valori solo tra 0 e 31 mi fa supporre che funzioni nel modo seguente:

Al numero di shape mask N viene associata la bitmask ( 1 << N ) (ovvero l'N-esimo bit a 1)

Se tu vuoi una mask che non abbia dentro il gruppo 30, devi mettere a uno tutti i bit tranne il 30-esimo, come spiegato nel post precedente.

Poi sei stato un po' avaro di dettagli, ma faro' le seguenti ipotesi:

* Le bitmask di solito di costruiscono con un | non con un &.
* Tipicamente le bitmask indicano quel che si vuole tenere, non togliere
* Devi shiftare tu opportunamente i bit per fare la maschera (ovvero gruppo 0 -> (1<<0) == 1 )

Se non e' cosi' devi adattare la spiegazione che segue.

Se voglio una maschera che tenga i gruppi 1 e 3, allora devo fare ( 1<<1 ) | (1 << 3)
ovvero 0010 | 1000 == 1010

In quest'ottica i tuoi dubbi si spiegano facilmente


-le mask numero pari non trovano il gruppo 0.

Una mask "numero pari", non e' altro che un maschera con l'ultimo bit a zero, ovvero una che non fara' mai passare il bit piu' basso. Quindi sia che tu usi 0 che (1<<0) il gruppo non passera' mai, perche' in OR con la bitmask dara' sempre zero.


-la maschera che passi dice cosa NON toccare, cioè se mask & shapeMask != 0 allora non viene visto.

Ad esempio assegnando al p1 e al p2 i numeri 1 e 3, si ha che ray( ..., 1 & 3,... ) ignora tutto tranne il suolo.

1 & 3 equivale a 0001 & 0011 che da 1. Se tu vuoi che vengano visti i gruppi 1 e 3 devi probabilmente settare gli N-esimi bit a 1, che e' un po' diverso, e farlo con un or, ovvero

0001 | 0100 = 0101

ray( ..., (1<<0) | (1<<2),... )



Siam riusciti ad ottenere quello che serve (cioè che lo sparo colpisce 0 e gruppo_nemico) usando l'arcana formula
~(1<<teamGroup)

Niente di arcano. supponendo che teamGroup sia 3, con la formula sopra qui ottieni
~ (1 << 3) == ~(00001000) == (11110111)
Ovvero tutto (anche lo zero, nell'ipotesi che sia 1<<0 ) tranne il tuo team.


PS: sapendo questo, come faccio a creare una mask che vede unicamente 0?
Teoricamente sarebbe NOT 0 ma praticamente non va :asd:
~0 piglia tutto.
In teoria dovrebbe essere semplicemente 1.

banryu79
23-10-2009, 12:38
Ciao marco.r,
scusa ma all'inizio (cioè prima di postare una risp a Tommo) pensavo anch'io esattamente la stessa cosa che hai spiegato.
C'è solo un dettaglio che non mi torna:

La Shape Mask è definita come unsigned short e va da 0 a 31;
la bitwise mask è un unsigned int.

e, considerato C++ come linguaggio:

An unsigned short can hold all the values between 0 and USHRT_MAX inclusive. USHRT_MAX must be at least 65535.

The short types must contain at least 16 bits to hold the required range of values.

Quindi se la maschera dei gruppi è definita come unsigned short (e il range di valori logici accettati sono compresi inclusivamente tra 0 e 31) vedo un problema nell'avere un 31esimo bit settato nel caso del gruppo 31, dato che quelli garantiti come minimo sono 16... forse non mi è chiaro qualcosa?



Poi sei stato un po' avaro di dettagli, ma faro' le seguenti ipotesi:

Sì, è un maledetto :asd:

marco.r
23-10-2009, 12:54
Quindi se la maschera dei gruppi è definita come unsigned short (e il range di valori logici accettati sono compresi inclusivamente tra 0 e 31) vedo un problema nell'avere un 31esimo bit settato nel caso del gruppo 31, dato che quelli garantiti come minimo sono 16... forse non mi è chiaro qualcosa?


Non ha detto se e' definito come un unsigned int in generale o sulla sua piattaforma. Nel secondo caso tornerebbe tutto, anche perche' su piattaforme 32/64 bit gli interi sono a 32 bit, cosi' come, se non ricordo male, in CUDA.

banryu79
23-10-2009, 12:57
Non ha detto se e' definito come un unsigned int in generale o sulla sua piattaforma.
Non ci avevo pensato ma avevo immaginato che fosse il tipo documentato come input dalla libreria.

Tommo
23-10-2009, 13:10
Ha completamente ragione marco.r :D

Cmq siamo riusciti a risolvere portando finalmente tutto terra terra :D
E' vero, la bitmask indica quello che si vuole tenere, ed ad esempio

ray( 1<<gruppo ) vede solo quel gruppo.
1<<0 vede solo il terreno, 1<<1 solo il player 1 etc... combinandoli ed invertendoli vien fuori tutto quello che serve :D

lo sparo è quindi risolto come ray( ~(1<<myTeam ) ).

Grazie dell'aiuto :D

PS: la bitmask era NxU32, cioè unsigned int 32 su tutte le piattaforme... scusate se era ambiguo!