0.グーローシェーディングがうまく計算して描画できません。
1.まず、頂点ベクトルがうまく計算出来ないです。全ての法線ベクトルの
共有する頂点を全て足して平均を求めるか、ベクトルの長さを1.0にして
収める正規化をすると良いみたいな事が書かれていました。
この共有する頂点という意味がよく分からないです。
ちなみに法線べクトル自体は求める事が出来ます。
頂点が反時計回りだとして、
頂点が3点のポリゴンだとすると、
Ax,Ay,Az
Bx,By,Bz
Cx,Cy,Cz
があるとすると、
double nx1=Ax-Bx;
double ny1=Ay-By;
double nz1=Az-Bz;
double nx2=Ax-Cx;
double ny2=Ay-Cy;
double nz2=Az-Cz;
double NVX=ny1nz2-nz1ny2;
double NVY=nx1nz2-nz1nx2;
double NVZ=nx1ny2-ny1nx2;
と求まるはずです。
外積で求まるのは、右ねじ方向に垂直な法線ベクトルだと、
ゲーム開発のための数学・物理学入門という本に書かれていました。
https://www.amazon.co.jp/%E3%82%B2%E3%83%BC%E3%83%A0%E9%96%8B%E7%99%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E6%95%B0%E5%AD%A6%E3%83%BB%E7%89%A9%E7%90%86%E5%AD%A6%E5%85%A5%E9%96%80-%E6%94%B9%E8%A8%82%E7%89%88-Professional-game-programming/dp/4797356774
正規化は
ベクトルの大きさを1にする計算方法です。
まず、その正規化したいベクトルの長さを
double veclen=sqrt(axax+ayay+az*az)+0.01f;//0除算を防ぐ為に0.01を足す
求めて、
それぞれの成分にこのveclenで割って行う処理だと思います。
つまり、
ax/=veclen;
ay/=veclen;
az/=veclen;
です。
2.頂点ベクトルと光源ベクトルとの内積は理屈は分からないですが、計算自体は
出来ます。内積で2つのベクトルのなす角度のコサインが求まるらしいのですが...
内積は、2つのベクトルの同じ成分同士を掛けて、全て足すと上の本で習いました。
例えば、光源ベクトルが100,-120,200だとすると、
光源ベクトルの大きさはlen=sqrt(100100+(-120-120)+200*200);で求まります。
正規化すると、
(100/len,-120/len,200/len)
(0.394055203,-0.472866243,0.788110406)
光源ベクトルと頂点ベクトルの内積は、
頂点ベクトルが(Nx,Ny,Nz),光源ベクトルが(Lx,Ly,Lz)だとすると、
double DotProductResult=NxLx+NyLy+Nz*Lz;
ちなみに、内積をこの法線ベクトルと視線ベクトル(カメラ?)と行う事で
カメラの方を向いているかどうかわかるので、そのポリゴンの法線ベクトルが
が0より小さければ描画して良いかどうかがカリングという法線ベクトル法
という陰面消去で分かります。
3.あと内積で求めた頂点カラーをどういうループにすれば
頂点カラーを適用できるのか分からないです。
4.最後に、グーローシェーディングの2次元版?はうまく行きました。
5.うまく行かないので、困っています。どうすれば求まるのか
誰か教えてください。
一部のソースコードを公開します。
なので、よく分かっていないのですが、面ごとの法線ベクトルを
頂点ベクトルという変数をでっちあげて面ごとの法線ベクトルをその面ごとの頂点ベクトルに
足すのと足した回数を調べておいて平均化したものに、RGB値のR値、G値、B値
それぞれに掛けてしまう方法なのかどうかすら分かってません。
c/c++言語
1 2void PSET(int x,int y,int col) 3{ 4 //点を打つ 5 if(x<0 || x>WIDTH) return; 6 if(y<0 || y>HEIGHT) return; 7 8 lpPixel[x+(y*WIDTH)]=col; 9} 10 11inline void ScanEdge(int x1,int y1,int x2,int y2,int c1,int c2) 12{ 13 14 int b1=(c1>>16) & 0xFF; 15 int g1=(c1>>8) & 0xFF; 16 int r1=c1 & 0xFF; 17 18 int b2=(c2>>16) & 0xFF; 19 int g2=(c2>>8) & 0xFF; 20 int r2=c2 & 0xFF; 21 22 for(double i=0.0f;i<=1.00f;i+=0.0001f)//0.0~1.0を、0~1024に直す 23 { 24 int ax=x1*(1.0-i)+x2*i;//線形補間の固定小数点処理化(X成分 25 int ay=y1*(1.0-i)+y2*i;//(固定小数点(Y成分 26 double k=(ay-y1)/(double)(y2-y1);//0.0~1.0を0~256に直す 27 28 if(ay<0 || ay>=HEIGHT) continue; 29 if(minX2[ay]>ax)//minなX(左側の線分) 30 { 31 minX2[ay]=ax; 32 int b=(1.0-k)*b1+k*b2; 33 int g=(1.0-k)*g1+k*g2; 34 int r=(1.0-k)*r1+k*r2; 35 36 if(r<0) r=0; if(r>255) r=255; 37 if(g<0) g=0; if(g>255) g=255; 38 if(b<0) b=0; if(b>255) b=255; 39 40 cmin[ay]=RGB(b,g,r); 41 PSET(ax,ay,cmin[ay]); 42 } 43 if(maxX2[ay]<ax)//maxなX(右側の線分) 44 { 45 maxX2[ay]=ax; 46 47 int b=(1.0-k)*b1+k*b2; 48 int g=(1.0-k)*g1+k*g2; 49 int r=(1.0-k)*r1+k*r2; 50 51 if(r<0) r=0; if(r>255) r=255; 52 if(g<0) g=0; if(g>255) g=255; 53 if(b<0) b=0; if(b>255) b=255; 54 55 56 57 cmax[ay]=RGB(b,g,r); 58 59 PSET(ax,ay,cmax[ay]); 60 } 61 62 } 63} 64 65inline void TRIANGLE2(int x1,int y1,int x2,int y2,int x3,int y3,int c1,int c2,int c3) 66{ 67 68 for(int i=0;i<HEIGHT;i++) 69 { 70 minX2[i]=65536; 71 maxX2[i]=-65536; 72 cmin[i]=RGB(0,0,0); 73 cmax[i]=RGB(0,0,0); 74 } 75 76 77 ScanEdge(x1,y1,x2,y2,c1,c2); 78 ScanEdge(x2,y2,x3,y3,c2,c3); 79 ScanEdge(x3,y3,x1,y1,c3,c1); 80 81 for(int y=0;y<HEIGHT;y++) 82 { 83 if(minX2[y]==65536 || maxX2[y]==-65536) continue; 84 85 for(int x=minX2[y];x<=maxX2[y];x++) 86 { 87 int r1=cmin[y] & 0xFF; 88 int g1=cmin[y]>>8 & 0xFF; 89 int b1=cmin[y]>>16 & 0xFF; 90 91 int r2=cmax[y] & 0xFF; 92 int g2=cmax[y]>>8 & 0xFF; 93 int b2=cmax[y]>>16 & 0xFF; 94 95 int j=((x-minX2[y])<<8)/(maxX2[y]-minX2[y]+1); 96 97 int r=r1*((1<<8)-j)+(r2)*j>>8; 98 int g=g1*((1<<8)-j)+(g2)*j>>8; 99 int b=b1*((1<<8)-j)+(b2)*j>>8; 100 101 int NewR=r; 102 int NewG=g; 103 int NewB=b; 104 105 if(NewR<0) NewR=0; if(NewR>255) NewR=255; 106 if(NewG<0) NewG=0; if(NewG>255) NewG=255; 107 if(NewB<0) NewB=0; if(NewB>255) NewB=255; 108 109 110 PSET(x,y,RGB(NewB,NewG,NewR)); 111 } 112 } 113} 114 115XYZ CalcNormal2(XYZ a,XYZ b,XYZ c) 116{ 117 XYZ d={0.0f}; 118 XYZ a2,b2; 119 120 a2.x=a.x-b.x; 121 a2.y=a.y-b.y; 122 a2.z=a.z-b.z; 123 124 b2.x=a.x-c.x; 125 b2.y=a.y-c.y; 126 b2.z=a.z-c.z; 127 128 double len=sqrt(a2.x*a2.x+a2.y*a2.y+a2.z*a2.z); 129 a2.x/=len; 130 a2.y/=len; 131 a2.z/=len; 132 133 double len2=sqrt(b2.x*b2.x+b2.y*b2.y+b2.z*b2.z); 134 b2.x/=len2; 135 b2.y/=len2; 136 b2.z/=len2; 137 138 139 //23-32 31-13 12-21 140 //aY*bZ-aZ*bY aZ*bX-aX*bZ aX*bY-aY*bX 141 d.x=a2.y*b2.z-a2.z*b2.y; 142 d.y=a2.z*b2.x-a2.x*b2.z; 143 d.z=a2.x*b2.y-a2.y*b2.x; 144 145 return d; 146} 147 148 149LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { 150 151 152 153 HDC hdc; 154 PAINTSTRUCT ps; 155 156 switch (iMsg) { 157 158 case WM_TIMER: 159 { 160 if(GetAsyncKeyState(VK_ESCAPE)<0) 161 SendMessage(hwnd,WM_DESTROY,NULL,NULL); 162 double X=0.0f; 163 double Y=0.0f; 164 double Z=0.0f; 165 166 //Z+=0.1f; 167 //Y+=0.1f; 168 if(GetAsyncKeyState(VK_RIGHT)<0) Y=-2.5f; 169 else if(GetAsyncKeyState(VK_LEFT)<0) Y=2.5f; 170 else Y=0.0f; 171 172 if(GetAsyncKeyState(VK_DOWN)<0) X=-2.5f; 173 else if(GetAsyncKeyState(VK_UP)<0) X=2.5f; 174 else X=0.0f; 175 176 Rotate(X,Y,0); 177 static int X1=0,X2=0; 178 int n=8; 179 180 181 182 InvalidateRect(hwnd,NULL,NULL); 183 } 184 return 0; 185 case WM_CREATE: 186 MyOutputDebugString("起動しました。"); 187 Init();//3次元座標を代入 188 189 SetTimer(hwnd,100,5,NULL); 190 /* BITMAPINFOをゼロクリア */ 191 ZeroMemory(&biInfo, sizeof(BITMAPINFO)); 192 193 /* BITMAPINFO設定 */ 194 biInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 195 biInfo.bmiHeader.biWidth = WIDTH; 196 biInfo.bmiHeader.biHeight = -HEIGHT; 197 biInfo.bmiHeader.biPlanes = 1; 198 biInfo.bmiHeader.biBitCount = 32; 199 biInfo.bmiHeader.biCompression = BI_RGB; 200 201 /* ウインドウのDCを取得 */ 202 hdc = GetDC(hwnd); 203 204 /* biInfoの形式でDIBSectionを作成 */ 205 hBMP =CreateDIBSection(hdc, &biInfo, DIB_RGB_COLORS, (LPVOID*)(&lpPixel), NULL, 0); 206 207 /* DIBSection用のメモリDCを作成 */ 208 hdcBMP = CreateCompatibleDC(hdc); 209 210 /* メモリDCにDIBSectionを選択 */ 211 hBMPOLD = (HBITMAP)SelectObject(hdcBMP, hBMP); 212 213 /* 不要になったウインドウのDCを解放 */ 214 ReleaseDC(hwnd, hdc); 215 216 return 0; 217 case WM_PAINT: 218 { 219 hdc = BeginPaint(hwnd, &ps); 220 221 ClearScreen();//画面を消す 222 223 //PSET(320,240,0x00ff0000);//点を打つ 224 //LINE(320,240,640,380,0x00ff0000); 225 226 int xy[4][2]={ 227 320,5, 228 220,300, 229 500,430, 230 630,280 231 }; 232 int Col[4]= 233 { 234 0x00ff0000, 235 0x0000ff00, 236 0x000000ff, 237 0x00ffffff 238 }; 239 240 241 Projection2DAxisFrom3DAxis(hdc);//透視投影 242 243 //PSET(320,240,0x00FFFFFF); 244 XYZ vvv[12];//全ての頂点の法線をクリアする 245 246 for(int i=0;i<12;i++) 247 { 248 vvv[i].x=0.0f;//Clear 249 vvv[i].y=0.0f;//Clear 250 vvv[i].z=0.0f;//Clear 251 } 252 253 XYZ a[13]; 254 XYZ b[13]; 255 XYZ n[13]; 256 257 for(int i=0;i<12;i++) 258 { 259 int i1=Poly[i][0]; 260 int i2=Poly[i][1]; 261 int i3=Poly[i][2]; 262 263 XYZ n=CalcNormal2(Pnt[i1],Pnt[i2],Pnt[i3]); 264 vvv[i1].x+=n.x; 265 vvv[i1].y+=n.y; 266 vvv[i1].z+=n.z; 267 268 vvv[i2].x+=n.x; 269 vvv[i2].y+=n.y; 270 vvv[i2].z+=n.z; 271 272 vvv[i3].x+=n.x; 273 vvv[i3].y+=n.y; 274 vvv[i3].z+=n.z; 275 276 vvv[i1].count++; 277 vvv[i2].count++; 278 vvv[i3].count++; 279 //全ての頂点毎に、全ての面の頂点座標と比較して、 280 281 } 282 283 for(int i=0;i<8;i++) 284 { 285 if(vvv[i].count>0) 286 { 287 vvv[i].x/=vvv[i].count ; 288 vvv[i].y/=vvv[i].count ; 289 vvv[i].z/=vvv[i].count ; 290 } 291 } 292 293 //頂点ベクトルは求まった(はず...)から、頂点カラーを面にある全ての頂点で求める 294 double ViewCos[12]; 295 //XYZ vpx=200,vpy=-120,vpz=100; 296 for(int i=0;i<12;i++) 297 { 298 double a=sqrt(vvv[i].x*vvv[i].x+vvv[i].y*vvv[i].y+vvv[i].z*vvv[i].z)+0.01f; 299 300 int i1=Poly[i][0]; 301 int i2=Poly[i][1]; 302 int i3=Poly[i][2]; 303 304 XYZ n=CalcNormal2(Pnt[i1],Pnt[i2],Pnt[i3]); 305 306 vvv[i].x/=a; 307 vvv[i].y/=a; 308 vvv[i].z/=a; 309 310 XYZ light={100,-120,200}; 311 double lenlight=sqrt((double)light.x*light.x+light.y*light.y+light.z*light.z); 312 313 light.x/=lenlight; 314 light.y/=lenlight; 315 light.z/=lenlight; 316 317 double spe1=vvv[i1].x*light.x+vvv[i1].y*light.y+vvv[i1].z*light.z; 318 double spe2=vvv[i2].x*light.x+vvv[i2].y*light.y+vvv[i2].z*light.z; 319 double spe3=vvv[i3].x*light.x+vvv[i3].y*light.y+vvv[i3].z*light.z; 320 321 double vv=sqrt((vpx*vpx+vpy*vpy+vpz*vpz));//視線ベクトルの長さを求める 322 323 double v1=vpx/(vv+0.01f);//視線ベクトルの正規化 324 double v2=vpy/(vv+0.01f);// 325 double v3=vpz/(vv+0.01f);// 326 327 ViewCos[i]=(v1*n.x+v2*n.y+v3*n.z); 328 //視線ベクトルと面ごとの法線ベクトルの内積 329 if(ViewCos[i]<0) 330 TRIANGLE2(Pnt2[Poly[i][0]].x,Pnt2[Poly[i][0]].y, 331 Pnt2[Poly[i][1]].x,Pnt2[Poly[i][1]].y, 332 Pnt2[Poly[i][2]].x,Pnt2[Poly[i][2]].y, 333 RGB(spe1*255,spe1*255,spe1*255), 334 RGB(spe2*255,spe2*255,spe2*255), 335 RGB(spe3*255,spe3*255,spe3*255) 336 ); 337 338 } 339 340 341 //反時計回りの座標軸 342 //三角形を表示する 343 //DrawTextureMapping(320,0,0,480,640,0); 344 345 //FillGraRect(0,0,320,20,255,0,0,0,255,0); 346 CalcFPS(hdc); 347 /* DIBSectionをDIBとして描画 */ 348 StretchDIBits(hdc, 0, 0, WIDTH, HEIGHT, 349 0, 0, WIDTH, HEIGHT, lpPixel, &biInfo, 350 DIB_RGB_COLORS,SRCCOPY); 351 352 353 EndPaint(hwnd, &ps); 354 355 DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH))); 356 } 357 return 0; 358 359 case WM_DESTROY: /* ウインドウ破棄時 */ 360 361 SelectObject(hdcBMP, hBMPOLD); 362 363 DeleteObject(hdcBMP); 364 DeleteObject(hBMP); 365 366 PostQuitMessage(0); 367 368 return 0; 369 370 } 371 372 return DefWindowProc(hwnd, iMsg, wParam, lParam); 373 374}
回答4件
あなたの回答
tips
プレビュー