🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Q&A

解決済

4回答

2312閲覧

グーローシェーディングの実装の仕方が分かりません。

littlestream

総合スコア37

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

0グッド

0クリップ

投稿2019/11/01 10:42

編集2019/11/02 04:31

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}

イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

stdio

2019/11/04 07:25

自己解決したなら、ベストアンサーを選択して質問とクローズして下さい。
guest

回答4

0

ベストアンサー

自己解決しました

というコードの,頂点の法線ベクトルの算出処理が間違っていたりしませんか?
例えば,↓のような雰囲気のコードになるように思うのですが.

XYZ vvv[1000];//全ての頂点の法線をクリアする for(int i=0;i<頂点の個数;i++) { vvv[i].x=0.0f;//Clear vvv[i].y=0.0f;//Clear vvv[i].z=0.0f;//Clear vvv[i].count = 0; //※これのクリアは要らないのでしょうか? } for( int iPoly=0; iPoly<三角形ポリゴン個数; ++iPoly ) { int i1=三角形[iPoly]の1つ目の頂点のindex; int i2=三角形[iPoly]の2つ目の頂点のindex; int i3=三角形[iPoly]の3つ目の頂点のindex; XYZ n=CalcNormal2(Pnt[i1],Pnt[i2],Pnt[i3]); //これで三角形[iPoly]の法線が求まるのだとして vvv[i1].x+=n.x; vvv[i1].y+=n.y; vvv[i1].z+=n.z; ++vvv[i1].count; //「個数」に意味がないならvvv[i1].count=1とかでも良い気がするが vvv[i2].x+=n.x; vvv[i2].y+=n.y; vvv[i2].z+=n.z; ++vvv[i2].count; vvv[i3].x+=n.x; vvv[i3].y+=n.y; vvv[i3].z+=n.z; ++vvv[i3].count; } //頂点の法線ベクトルの単位化 for( int iVtx=0; iVtx<頂点の個数; ++iVtx ) { if(vvv[iVtx].count>0)Normalize(&vvv[i]); }

投稿2019/11/04 07:19

fana

総合スコア11987

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

littlestream

2019/11/04 21:19

参考になりました。ありがとうございます!
guest

0

自己解決しました。一応、WndProc関数を貼っておきます。
イメージ説明

c/c++

1int min_[HEIGHT]; 2int max_[HEIGHT]; 3typedef struct VTX{ 4 double x,y,z; 5 int count; 6 int R,G,B; 7}VTX; 8 9typedef struct XYZ{ 10 double x; 11 double y; 12 double z; 13 int count; 14}XYZ; 15typedef struct XY{ 16 double x; 17 double y; 18}XY; 19 20#define RAD (3.14159265/180) 21#define MAX_XYZ 1000 22 23XYZ Pnt[MAX_XYZ]; 24XY Pnt2[MAX_XYZ]; 25int Poly[1000][4]; 26double vpx=1.0f,vpy=1.0f,vpz=-800.0f; 27double D=624; 28 29void Projection2DAxisFrom3DAxis(HWND hwnd) 30{ 31 HDC hdc = GetDC(hwnd); 32 33 for(int i=0;i<MAXVTX;i++) 34 { 35 Pnt2[i].x=(Pnt[i].x*D)/(Pnt[i].z-vpz)+160.0f; 36 Pnt2[i].y=-(Pnt[i].y*D)/(Pnt[i].z-vpz)+120.0f; 37 //PSET(Pnt2[i].x,Pnt2[i].y,0x00ff0000); 38 //char str[100]; 39 //sprintf(str,"%d",i); 40 //TextOut(hdc,Pnt2[i].x,Pnt2[i].y,str,strlen(str)); 41 } 42} 43void SetPoly(int num,int n1,int n2,int n3) 44{ 45 Poly[num][0]=n1;//頂点番号を指定 46 Poly[num][1]=n2; 47 Poly[num][2]=n3; 48} 49void SetXYZ(int num,double x,double y,double z) 50{ 51 if(num<0 || num>=MAX_XYZ) return; 52 Pnt[num].x=x;//頂点座標を指定 53 Pnt[num].y=y; 54 Pnt[num].z=z; 55} 56void PSET(int x,int y,int col) 57{ 58 //点を打つ 59 if(x<0 || x>=WIDTH-2) return; 60 if(y<0 || y>=HEIGHT-2) return; 61 62 lpPixel[x+(y*WIDTH)]=col; 63} 64inline void LINE2COL(int x1,int y1,int x2,int y2,int COL,int COL2) 65{ 66 //線を描くのと左か右かを判断する関数 67 int NewX,NewY; 68 69 for(int j=0;j<1024;j++) 70 { 71 NewX=x1*(1024-j)+x2*j>>10; 72 NewY=y1*(1024-j)+y2*j>>10; 73 74 int R1,R2,G1,G2,B1,B2; 75 76 R1=(COL>>16) & 0xFF; 77 G1=(COL>>8) & 0xFF; 78 B1=(COL) & 0xFF; 79 80 R2=(COL2>>16) & 0xFF; 81 G2=(COL2>>8) & 0xFF; 82 B2=(COL2) & 0xFF; 83 84 85 int R=R1*(1024-j)+R2*j>>10; 86 int G=G1*(1024-j)+G2*j>>10; 87 int B=B1*(1024-j)+B2*j>>10; 88 89 PSET(NewX,NewY,RGB(R,G,B)); 90 91 if(min_[(int)NewY]>NewX){ 92 min_[(int)NewY]=NewX; 93 cmin[(int)NewY]=RGB(R,G,B); 94 } 95 if(max_[(int)NewY]<NewX){ 96 max_[(int)NewY]=NewX; 97 cmax[(int)NewY]=RGB(R,G,B); 98 } 99 100 } 101} 102 103int min_Y(int y1,int y2,int y3) 104{ 105 if(y1<y2 && y1<y3) return y1; 106 if(y2<y1 && y2<y3) return y2; 107 if(y3<y1 && y3<y2) return y3; 108} 109 110int max_Y(int y1,int y2,int y3) 111{ 112 if(y1>y2 && y1>y3) return y1; 113 if(y2>y1 && y2>y3) return y2; 114 if(y3>y1 && y3>y2) return y3; 115} 116 117inline void GouraudShade(int x1,int y1,int x2,int y2,int x3,int y3,int C1,int C2,int C3) 118{ 119 120 //入れ忘れ(笑) 121 for(int i=0;i<SCREENHEIGHT;i++) 122 { 123 min_[i]=65816; 124 max_[i]=-65816; 125 cmin[i]=RGB(0,0,0); 126 cmax[i]=RGB(0,0,0); 127 } 128 129 LINE2COL(x1,y1,x2,y2,C1,C2); 130 LINE2COL(x2,y2,x3,y3,C2,C3); 131 LINE2COL(x1,y1,x3,y3,C1,C3); 132 133 for(int Y=min_Y(y1,y2,y3);Y<max_Y(y1,y2,y3);Y++) 134 { 135 int R1=(cmin[Y]>>16) & 0xFF; 136 int G1=(cmin[Y]>>8) & 0xFF; 137 int B1=(cmin[Y]) & 0xFF; 138 139 int R2=(cmax[Y]>>16) & 0xFF; 140 int G2=(cmax[Y]>>8) & 0xFF; 141 int B2=(cmax[Y]) & 0xFF; 142 143 LINE2COL(min_[Y],Y,max_[Y],Y,RGB(R1,G1,B1),RGB(R2,G2,B2)); 144 145 } 146 147} 148 149void LoadOBJFile(char filename[10000],HWND hwnd) 150{ 151 152 static int flag=0; 153 FILE *fp; 154 fp=fopen(filename,"r"); 155 if(fp==NULL) 156 { 157 MessageBox(NULL,"ファイルがありません。","OK?",MB_OK); 158 SelectObject(hdcBMP, hBMPOLD); 159 160 DeleteObject(hdcBMP); 161 DeleteObject(hBMP); 162 163 PostQuitMessage(0); 164 165 return; 166 } 167 168 int i=0; 169 int j=0; 170 171 while(fgets(FileStr[i],50,fp)!=NULL) 172 { 173 j=0; 174 //以下の内容が通用しないのでテキストエディタ(最悪Windowsのメモ帳でも可) 175 //で空白を,(カンマ)に置換する必要がある、 176 177 //while(FileStr[i][j]) 178 { 179 // if(FileStr[i][j]==' ') FileStr[i][j]=','; 180 // ++j; 181 } 182 ++i; 183 } 184 185 LastLine=i;//最後の行数を保存する 186 char opecode[10000]={0}; 187 double XF,YF,ZF; 188 int TriNum1,TriNum2,TriNum3; 189 int k=0; 190 191 for(int i=0;i<LastLine;i++) 192 { 193 194 opecode[0]=FileStr[i][0]; 195 //CameraPos.D=535.0f; 196 //CameraPos.Z=-810.0f; 197 198 //PSET(400,300,GetColor(0,0,255)); 199 if(opecode[0]=='v') 200 { 201 sscanf(FileStr[i],"%c,%lf,%lf,%lf", 202 opecode,&XF,&YF,&ZF); 203 SetXYZ(k,XF*SCALE,YF*SCALE,ZF*SCALE); 204 Projection2DAxisFrom3DAxis(hwnd); 205 //i=0; 206 207 ++k; 208 MAXVTX=k; 209 } 210 211 212 if(opecode[0]=='f') 213 { 214 sscanf(FileStr[i],"%c,%d,%d,%d", 215 opecode,&TriNum1,&TriNum2,&TriNum3); 216 if(flag==0) 217 { 218 j=0; 219 flag=1; 220 } 221 222 SetPoly(j,(int)TriNum1-1,(int)TriNum2-1,(int)TriNum3-1); 223 224 Projection2DAxisFrom3DAxis(hwnd); 225 226 ++j; 227 MAXPOL=j; 228 229 } 230 231 232 } 233 234} 235 236XYZ CalcCross(XYZ a,XYZ b,XYZ c) 237{ 238 XYZ d={0.0f}; 239 XYZ a2,b2; 240 241 a2.x=a.x-b.x; 242 a2.y=a.y-b.y; 243 a2.z=a.z-b.z; 244 245 b2.x=a.x-c.x; 246 b2.y=a.y-c.y; 247 b2.z=a.z-c.z; 248 249 double len=sqrt(a2.x*a2.x+a2.y*a2.y+a2.z*a2.z); 250 a2.x/=len; 251 a2.y/=len; 252 a2.z/=len; 253 254 double len2=sqrt(b2.x*b2.x+b2.y*b2.y+b2.z*b2.z); 255 b2.x/=len2; 256 b2.y/=len2; 257 b2.z/=len2; 258 259 260 //23-32 31-13 12-21 261 //aY*bZ-aZ*bY aZ*bX-aX*bZ aX*bY-aY*bX 262 d.x=a2.y*b2.z-a2.z*b2.y; 263 d.y=a2.z*b2.x-a2.x*b2.z; 264 d.z=a2.x*b2.y-a2.y*b2.x; 265 266 return d; 267} 268 269 270LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { 271 272 273 274 HDC hdc; 275 PAINTSTRUCT ps; 276 277 switch (iMsg) { 278 279 case WM_TIMER: 280 { 281 if(GetAsyncKeyState(VK_ESCAPE)<0) 282 SendMessage(hwnd,WM_DESTROY,NULL,NULL); 283 double X=0.0f; 284 double Y=0.0f; 285 double Z=0.0f; 286 287 //Z+=0.1f; 288 //Y+=0.1f; 289 if(GetAsyncKeyState(VK_RIGHT)<0) Y=-2.5f; 290 else if(GetAsyncKeyState(VK_LEFT)<0) Y=2.5f; 291 else Y=0.0f; 292 293 if(GetAsyncKeyState(VK_DOWN)<0) X=-2.5f; 294 else if(GetAsyncKeyState(VK_UP)<0) X=2.5f; 295 else X=0.0f; 296 297 Rotate(X,Y,0); 298 static int X1=0,X2=0; 299 int n=8; 300 301 302 303 InvalidateRect(hwnd,NULL,NULL); 304 } 305 return 0; 306 case WM_CREATE: 307 MyOutputDebugString("起動しました。"); 308 //Init();//3次元座標を代入 309 310 LoadOBJFile("./DO-NATSU.obj",hwnd); 311 //LoadOBJFile("./cube.obj",hwnd); 312 //LoadOBJFile("./true20mentai.obj",hwnd); 313 314 315 SetTimer(hwnd,100,1000/60,NULL); 316 /* BITMAPINFOをゼロクリア */ 317 ZeroMemory(&biInfo, sizeof(BITMAPINFO)); 318 319 /* BITMAPINFO設定 */ 320 biInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 321 biInfo.bmiHeader.biWidth = WIDTH; 322 biInfo.bmiHeader.biHeight = -HEIGHT; 323 biInfo.bmiHeader.biPlanes = 1; 324 biInfo.bmiHeader.biBitCount = 32; 325 biInfo.bmiHeader.biCompression = BI_RGB; 326 327 /* ウインドウのDCを取得 */ 328 hdc = GetDC(hwnd); 329 330 /* biInfoの形式でDIBSectionを作成 */ 331 hBMP =CreateDIBSection(hdc, &biInfo, DIB_RGB_COLORS, (LPVOID*)(&lpPixel), NULL, 0); 332 333 /* DIBSection用のメモリDCを作成 */ 334 hdcBMP = CreateCompatibleDC(hdc); 335 336 /* メモリDCにDIBSectionを選択 */ 337 hBMPOLD = (HBITMAP)SelectObject(hdcBMP, hBMP); 338 339 /* 不要になったウインドウのDCを解放 */ 340 ReleaseDC(hwnd, hdc); 341 342 return 0; 343 case WM_PAINT: 344 { 345 hdc = BeginPaint(hwnd, &ps); 346 347 ClearScreen();//画面を消す 348 349 //PSET(320,240,0x00ff0000);//点を打つ 350 //LINE(320,240,640,380,0x00ff0000); 351 352 Projection2DAxisFrom3DAxis(hwnd);//透視投影 353 354 //PSET(320,240,0x00FFFFFF); 355 XYZ vvv[1000];//全ての頂点の法線をクリアする 356 357 for(int i=0;i<MAXVTX;i++) 358 { 359 vvv[i].x=0.0f;//Clear 360 vvv[i].y=0.0f;//Clear 361 vvv[i].z=0.0f;//Clear 362 } 363 364 XYZ a[1000]; 365 XYZ b[1000]; 366 XYZ n3[1000]; 367 368 for(int i=0;i<MAXVTX;i+=3) 369 { 370 int i1=Poly[i][0]; 371 int i2=Poly[i][1]; 372 int i3=Poly[i][2]; 373 374 XYZ n=CalcCross(Pnt[i1],Pnt[i2],Pnt[i3]); 375 //外積を行った 376 377 Normalize(&n); 378 //正規化を行った 379 380 vvv[i1].x+=n.x; 381 vvv[i1].y+=n.y; 382 vvv[i1].z+=n.z; 383 384 vvv[i2].x+=n.x; 385 vvv[i2].y+=n.y; 386 vvv[i2].z+=n.z; 387 388 vvv[i3].x+=n.x; 389 vvv[i3].y+=n.y; 390 vvv[i3].z+=n.z; 391 392 393 } 394 395 for(int i=0;i<MAXVTX;i++) 396 { 397 Normalize(&vvv[i]); 398 //vvv[i].x/=vvv[i].count ; 399 //vvv[i].y/=vvv[i].count ; 400 //vvv[i].z/=vvv[i].count ; 401 } 402 //頂点ベクトルは求まった(はず...)から、頂点カラーを面にある全ての頂点で求める 403 404 //XYZ vpx=200,vpy=-120,vpz=100; 405 for(int i=0;i<MAXVTX;i+=1) 406 { 407 408 //PSET(Pnt2[i].x,Pnt[i].y,RGB(0,0,255)); 409 410 int i1=Poly[i][0]; 411 int i2=Poly[i][1]; 412 int i3=Poly[i][2]; 413 414 XYZ n=CalcCross(Pnt[i1],Pnt[i2],Pnt[i3]); 415 416 XYZ light={100,-120,200}; 417 double lenlight=sqrt((double)light.x*light.x+light.y*light.y+light.z*light.z); 418 419 light.x/=lenlight; 420 light.y/=lenlight; 421 light.z/=lenlight; 422 423 double spe1=vvv[i1].x*light.x+vvv[i1].y*light.y+vvv[i1].z*light.z; 424 double spe2=vvv[i2].x*light.x+vvv[i2].y*light.y+vvv[i2].z*light.z; 425 double spe3=vvv[i3].x*light.x+vvv[i3].y*light.y+vvv[i3].z*light.z; 426 427 double vv=sqrt((vpx*vpx+vpy*vpy+vpz*vpz));//視線ベクトルの長さを求める 428 429 double v1=vpx/(vv+0.01f);//視線ベクトルの正規化 430 double v2=vpy/(vv+0.01f);// 431 double v3=vpz/(vv+0.01f);// 432 double ViewCos; 433 434 435 ViewCos=(v1*n.x+v2*n.y+v3*n.z); 436 //視線ベクトルと面ごとの法線ベクトルの内積 437 438 if(ViewCos<0) 439 GouraudShade(Pnt2[Poly[i][0]].x,Pnt2[Poly[i][0]].y, 440 Pnt2[Poly[i][1]].x,Pnt2[Poly[i][1]].y, 441 Pnt2[Poly[i][2]].x,Pnt2[Poly[i][2]].y, 442 //RGB(ViewCos*255,ViewCos*255,ViewCos*255) 443 RGB(spe1*255,spe1*255,spe1*255), 444 RGB(spe2*255,spe2*255,spe2*255), 445 RGB(spe3*255,spe3*255,spe3*255) 446 ); 447 448 } 449 450 451 //反時計回りの座標軸 452 //三角形を表示する 453 //DrawTextureMapping(240,0,0,120,240,0); 454 455 //FillGraRect(0,0,320,20,255,0,0,0,255,0); 456 457 /* DIBSectionをDIBとして描画 */ 458 StretchDIBits(hdc, 0, 0, WIDTH, HEIGHT, 459 0, 0, WIDTH, HEIGHT, lpPixel, &biInfo, 460 DIB_RGB_COLORS,SRCCOPY); 461 CalcFPS(hdc); 462 463 EndPaint(hwnd, &ps); 464 465 DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH))); 466 } 467 return 0; 468 469 case WM_DESTROY: /* ウインドウ破棄時 */ 470 471 SelectObject(hdcBMP, hBMPOLD); 472 473 DeleteObject(hdcBMP); 474 DeleteObject(hBMP); 475 476 PostQuitMessage(0); 477 478 return 0; 479 480 } 481 482 return DefWindowProc(hwnd, iMsg, wParam, lParam); 483 484} 485

投稿2019/11/04 05:34

編集2019/11/04 22:34
littlestream

総合スコア37

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2019/11/04 06:21

色が不連続な横線(?)がたくさん見えますが,これでOKなんでしょうか? (あと,質問時と同じモデルデータの結果例も示される方が良いかな,とか)
ikadzuchi

2019/11/04 06:47

私にも解決しているように見えません。 グラデーションは最初の画像でも同様に掛かっていましたし、 頂点カラーも最初の画像と同様に間違っていそうです。 また「色が不連続な横線」も、最初の画像と同様に3角形の上と下で色に境ができているラスタライズの誤りにも見えます。
fana

2019/11/04 07:09 編集

(見た目にはモデルの複雑さが判断つきませんが)仮に単純なドーナツ形状(で,光源も1個)であれば,こんな複雑に白黒が縞々に入り乱れたりしないのではないかと思います. (各変数が何なのか詳細不明ですがコードの雰囲気的に,vvv[]の算出が正常に思えません.countなるメンバがどうなってるのかも謎ですが,ループ構造自体が間違っている感)
littlestream

2019/11/04 12:52

先ほどこれらの書き込みに気がついた私はこのまま解決にしなくて良かったのだと思いました。 とりあえず、あと、もう少しだけソースを見てもらって少しでも解決したいと思います。
littlestream

2019/11/04 20:24

ソースを貼りましたが、if(vvv[i].count>0)は明らかなミスでした。 直してそのif文を消したら上手く行った気がするのですが・・・
littlestream

2019/11/04 23:27

気が付くのが遅れてすみません。 ikadzuchiさん、fanaさん、コメントありがとうございます。
fana

2019/11/05 01:32

こういうのは「まともにできていると確認が取れた箇所」を少しずつ広げていく感じで動作確認していくのが良いかと思います. 例えば, ・頂点の法線だとか面の法線だとかを描画してみる : 長さや向きがおかしい場合はすぐにわかる ・面上の各位置を「一番近い頂点の色」で塗ってみる : 頂点の色が正しいかどうかの確認 ・… 等. 途中の各変数の値が簡単に想像がつくような単純なモデル(最初に使っていた立方体とか,適当に荒く分割した球とか)を与えて結果を確認してみると良いのではないかと思います. あと,視点位置を変えてぐるぐるといろんな方向から見るでしょうから,座標軸とか光源の位置(or向き)を示す何かを表示しておくとわかりやすいかと.
littlestream

2019/11/05 03:29

fanaさん、 頂点の法線ベクトルを図示するアイデアは初心者ながら思っていましたが、実際に使えるテクニックと今教えてもらったので後で試してみます。メッセージボックスやDOSのprintfデバッグだけではなく、グラフィック関係のデバッグについては教えてもらって嬉しいですし、感謝しています。今仕事先の昼休みなのでスマホから書き込んでいます。どうもありがとうございました?
littlestream

2019/11/05 03:30

?は失礼しました。どうもありがとうございました。
guest

0

グラデーションは掛かっているのでそこそこできていそうに見えます。
問題は頂点カラーが正しくなさそうな点と、
3角形の上と下で色に境ができているのでラスタライズも微妙に間違っていそうです。(図で赤で囲った2箇所)
イメージ説明
また、立方体に(グーローなどの滑らかなタイプの)シェーディングをするのは結果が分かりづらいのでやめた方がよいです。もっと球に近い、例えば正20面体くらいの立体の方がよいです。
ところで元データは何でしょうか。
なんとなく、3角形の向きが交互に逆になっていたりしないかと思うのですが。

1.まず、頂点ベクトルがうまく計算出来ないです。

頂点ベクトルとは何ですか?
文脈からして頂点の法線ベクトルでしょうか。言葉は正確に伝えてください。

この共有する頂点という意味がよく分からないです。

私にもあなたの言葉の意味がよく分からないです。
文脈からして、ある頂点を共有するすべての面の法線ベクトルの平均を取ってその頂点の法線ベクトルとするあたりの話だとは思いますが。

2.頂点ベクトルと光源ベクトルとの内積は理屈は分からないですが、計算自体は出来ます。内積で2つのベクトルのなす角度のコサインが求まるらしいのですが...

まあ計算ができるなら問題ないのではないでしょうか。
理屈…というか解釈ですが、内積は座標から求める方法と、図形的な長さとなす角から求める方法があり、座標から求めた内積を図形的に見ると角度が分かるという流れで理解するとよいかもしれません。

ちなみに、

今回の問題に無関係な内容ですね。

3.あと内積で求めた頂点カラーをどういうループにすれば 頂点カラーを適用できるのか分からないです。

「内積で求めた頂点カラー」とは何でしょうか。頂点カラーは光源と法線のなす角によって決まるものだと思いますが。
「どういうループにすれば 頂点カラーを適用できるのか」というのも何を指しているのか分かりません。各ピクセルの色を求める方法でしょうか。見たところそれらしいグラデーションになっているのでその部分は正しそうに見えます。

4.最後に、グーローシェーディングの2次元版?はうまく行きました。

「グーローシェーディングの2次元版?」とは?

面ごとの法線ベクトルを 頂点ベクトルという変数をでっちあげて面ごとの法線ベクトルをその面ごとの頂点ベクトルに 足すのと足した回数を調べておいて平均化したものに、RGB値のR値、G値、B値 それぞれに掛けてしまう方法

正直何を言っているのか分からないのでもう少し文章を練り直していただけませんか。

投稿2019/11/02 17:03

ikadzuchi

総合スコア3047

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

littlestream

2019/11/03 02:43

>正直何を言っているのか分からないのでもう少し文章を練り直していただけませんか。 わかりました。もう少し練り直したいと思います。 >あと、立方体の元データですが、頂点番号だけTextOutで表示して目視で作っていました。なので、 もう少しマシな立体データで挑戦するためにDXライブラリバージョンで自作した LoadObjFile関数をWIN32API版に移植しようと思います。
littlestream

2019/11/03 02:44

あと、回答ありがとうございました!
guest

0

多分、私は(質問の概要的に)回答はできないと思いますが、アドバイスを。

5.うまく行かないので、困っています。

とありますが、「どのようにうまくいかないのか」を明確にするといいかもしれません。例えば、__半円急になるところがぺしゃんこになる__とか。

頂点ベクトルと光源ベクトルとの内積は理屈は分からないですが、計算自体は

出来ます。

では、「できる」とあるので、質問と認識しづらいです。(私の読解力が低いからか...?)

「〇〇はどのようにすればいいか」とかみたいに疑問形でやったほうがわかりやすいかと思います。
(あくまで私の考え)

投稿2019/11/02 02:15

BeatStar

総合スコア4962

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

littlestream

2019/11/02 02:59

>BeatStarさんへ 回答ありがとうございます! 質問の仕方が悪かったのですね。 もう少し分からない部分を整理して考え直したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問