いくつかの 2D イメージを、ユーザーが回転できる 3D ボリュームに変換するボリューム レンダリング プログラムを作成しました。ポイントの周りの各方向のグラデーションを取得して、3D テクスチャ (ライティング用) の各ポイントの法線を計算する必要があります。
法線を計算するには、フラグメント シェーダー内で 6 つの追加のテクスチャ アクセスが必要です。プログラムは、これらの余分なテクスチャ アクセスがなくてもはるかに高速であるため、各方向 (x、y、z) の勾配をバイト単位で事前計算し、それを元のテクスチャの BGA チャネルに格納しようとしています。CPU でテストすると、バイトに正しい値が含まれているように見えますが、シェーダーに到達すると、間違っているように見えます。シェーダーから失敗する理由を判断するのは難しいです。勾配値の一部が負であるためだと思います。しかし、テクスチャ タイプを (GL_UNSIGNED_BYTE ではなく) GL_BYTE として指定すると、それはまだ間違っており、元のテクスチャがどのように見えるべきかが台無しになります。データを色としてレンダリングするだけでは、何が問題なのか正確にわかりません。負の値をテクスチャに入れる正しい方法は何ですか? フラグメントシェーダーで値を読み取るときに、値が負であることをどのように知ることができますか?
次のコードは、バイト配列 (byte[] all) からグラデーションを計算し、それを 3D テクスチャとして読み込まれるバイト バッファー (byteBuffer bb) に変換する操作を実行する方法を示しています。関数 'toLoc(x,y,z,w,h,l)' は単純に (x+w*(y+z*h))*4) を返します。これは、3 次元の添え字を 1 次元のインデックスに変換します。画像はグレースケールなので、gba を破棄し、r チャネルのみを使用して元の値を保持します。残りのチャネル (gba) には勾配が格納されます。
int pixelDiffxy=5;
int pixelDiffz=1;
int count=0;
Float r=0f;
byte t=r.byteValue();
for(int i=0;i<w;i++){
for(int j=0;j<h;j++){
for(int k=0;k<l;k++){
count+=4;
if(i<pixelDiffxy || i>=w-pixelDiffxy || j<pixelDiffxy || j>=h-pixelDiffxy || k<pixelDiffz || k>=l-pixelDiffz){
//set these all to zero since they are out of bounds
all[toLoc(i,j,k,w,h,l)+1]=t;//green=0
all[toLoc(i,j,k,w,h,l)+2]=t;//blue=0
all[toLoc(i,j,k,w,h,l)+3]=t;//alpha=0
}
else{
int ri=(int)all[toLoc(i,j,k,w,h,l)+0] & 0xff;
//find the values on the sides of this pixel in each direction (use red channel)
int xgrad1=(all[toLoc(i-pixelDiffxy,j,k,w,h,l)])& 0xff;
int xgrad2=(all[toLoc(i+pixelDiffxy,j,k,w,h,l)])& 0xff;
int ygrad1=(all[toLoc(i,j-pixelDiffxy,k,w,h,l)])& 0xff;
int ygrad2=(all[toLoc(i,j+pixelDiffxy,k,w,h,l)])& 0xff;
int zgrad1=(all[toLoc(i,j,k-pixelDiffz,w,h,l)])& 0xff;
int zgrad2=(all[toLoc(i,j,k+pixelDiffz,w,h,l)])& 0xff;
//find the difference between the values on each side and divide by the distance between them
int xgrad=(xgrad1-xgrad2)/(2*pixelDiffxy);
int ygrad=(ygrad1-ygrad2)/(2*pixelDiffxy);
int zgrad=(zgrad1-zgrad2)/(2*pixelDiffz);
Vec3f grad=new Vec3f(xgrad,ygrad,zgrad);
Integer xg=(int) (grad.x);
Integer yg=(int) (grad.y);
Integer zg=(int) (grad.z);
//System.out.println("gs are: "+xg +", "+yg+", "+zg);
byte gby= (byte) (xg.byteValue());//green channel
byte bby= (byte) (yg.byteValue());//blue channel
byte aby= (byte) (zg.byteValue());//alpha channel
//System.out.println("gba is: "+(int)gby +", "+(int)bby+", "+(int)aby);
all[toLoc(i,j,k,w,h,l)+1]=gby;//green
all[toLoc(i,j,k,w,h,l)+2]=bby;//blue
all[toLoc(i,j,k,w,h,l)+3]=aby;//alpha
}
}
}
}
ByteBuffer bb=ByteBuffer.wrap(all);
final GL gl = drawable.getGL();
final GL2 gl2 = gl.getGL2();
final int[] bindLocation = new int[1];
gl.glGenTextures(1, bindLocation, 0);
gl2.glBindTexture(GL2.GL_TEXTURE_3D, bindLocation[0]);
gl2.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);//-byte alignment
gl2.glTexParameteri(GL2.GL_TEXTURE_3D, GL.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP);
gl2.glTexParameteri(GL2.GL_TEXTURE_3D, GL.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP);
gl2.glTexParameteri(GL2.GL_TEXTURE_3D, GL2.GL_TEXTURE_WRAP_R, GL2.GL_CLAMP);
gl2.glTexParameteri(GL2.GL_TEXTURE_3D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl2.glTexParameteri(GL2.GL_TEXTURE_3D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl2.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
gl2.glTexImage3D( GL2.GL_TEXTURE_3D, 0,GL.GL_RGBA,
w, h, l, 0,
GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, bb );//GL_UNSIGNED_BYTE
署名されたデータの大規模な配列をシェーダーに取得するより良い方法はありますか?