문제

나는 소프트웨어 레스터 라이저를 만들고 있으며 약간의 걸려 넘어졌다 : 나는 원근법에 대한 텍스처 매핑을 작동시키는 것 같다.

내 알고리즘은 먼저 줄거리를 플롯 할 좌표를 정렬하는 것입니다. y. 이것은 가장 높고 가장 낮은 중심점을 반환합니다. 그런 다음 델타를 사용하여 스캔 라인을 가로 질러 걷습니다.

// ordering by y is put here

order[0] = &a_Triangle.p[v_order[0]];
order[1] = &a_Triangle.p[v_order[1]];
order[2] = &a_Triangle.p[v_order[2]];

float height1, height2, height3;

height1 = (float)((int)(order[2]->y + 1) - (int)(order[0]->y));
height2 = (float)((int)(order[1]->y + 1) - (int)(order[0]->y));
height3 = (float)((int)(order[2]->y + 1) - (int)(order[1]->y));

// x 

float x_start, x_end;
float x[3];
float x_delta[3];

x_delta[0] = (order[2]->x - order[0]->x) / height1;
x_delta[1] = (order[1]->x - order[0]->x) / height2;
x_delta[2] = (order[2]->x - order[1]->x) / height3;

x[0] = order[0]->x;
x[1] = order[0]->x;
x[2] = order[1]->x;

그리고 우리는 렌더링합니다 order[0]->y 에게 order[2]->y, 증가 x_start 그리고 x_end 델타에 의해. 상단 부분을 렌더링 할 때 델타는 x_delta[0] 그리고 x_delta[1]. 하단 부분을 렌더링 할 때 델타는 x_delta[0] 그리고 x_delta[2]. 그런 다음 스캔 라인에서 x_start와 x_end 사이를 선형으로 보간합니다. UV 좌표는 y에 의해 순서대로 같은 방식으로 보간되어 시작과 끝에서 시작하여 델타의 각 단계에 적용됩니다.

이것은 올바른 UV 매핑을 원근감하려고 할 때를 제외하고는 잘 작동합니다. 기본 알고리즘은 취해야합니다 UV/z 그리고 1/z 각 정점에 대해 그들 사이에 보간됩니다. 각 픽셀에 대해 UV 좌표가됩니다 UV_current * z_current. 그러나 결과는 다음과 같습니다.

alt text

역전 된 부분은 델타가 어디로 뒤집 히는지 알려줍니다. 보시다시피, 두 삼각형은 둘 다 지평선의 다른 지점으로가는 것 같습니다.

공간의 한 지점에서 z를 계산하는 데 사용하는 것은 다음과 같습니다.

float GetZToPoint(Vec3 a_Point)
{
    Vec3 projected = m_Rotation * (a_Point - m_Position);

    // #define FOV_ANGLE 60.f
    // static const float FOCAL_LENGTH = 1 / tanf(_RadToDeg(FOV_ANGLE) / 2);
    // static const float DEPTH = HALFHEIGHT * FOCAL_LENGTH; 
    float zcamera = DEPTH / projected.z;

    return zcamera;
}

맞아요, AZ 버퍼 문제입니까?

도움이 되었습니까?

해결책

Zbuffer는 그것과 아무 관련이 없습니다.

Zbuffer는 삼각형이 겹치는 경우에만 유용하며 올바르게 그려지는지 확인하려고합니다 (예 : Z에서 올바르게 주문). Zbuffer는 삼각형의 모든 픽셀에 대해 이전에 배치 된 픽셀이 카메라에 가까운 지 여부를 결정하고 그렇다면 삼각형의 픽셀을 그리지 않습니다.

겹치지 않는 2 개의 삼각형을 그리기 때문에 이것은 문제가 될 수 없습니다.

나는 고정 지점으로 소프트웨어 레스터 라이저를 한 번 (휴대 전화의 경우) 만들었지 만 노트북에 소스가 없습니다. 그러니 오늘 밤 내가 어떻게했는지 확인하겠습니다. 본질적으로 당신이 가진 것은 나쁘지 않습니다! 이와 같은 것은 매우 작은 오류로 인해 발생할 수 있습니다.

디버깅의 일반적인 팁이를 통해 몇 가지 테스트 삼각형 (슬로프 왼쪽, 슬로프 오른쪽, 90도 각도 등)을 갖추고 디버거를 사용하여 논리가 케이스를 어떻게 처리하는지 확인하는 것입니다.

편집하다:

Rasterizer의 Peudocode (U, V 및 Z 만 고려됩니다 ... Gouraud를 원한다면 RG 및 B를 위해 모든 작업을 수행해야합니다.

아이디어는 삼각형을 2 부분으로 분해 할 수 있다는 것입니다. 상단 부분과 하단 부분. 상단은 y [0]에서 Y [1]이고 하단 부분은 y [1]에서 Y [2]입니다. 두 세트 모두 보간중인 단계 변수를 계산해야합니다. 아래 예제는 상단 부분을 수행하는 방법을 보여줍니다. 필요한 경우 하단 부분도 제공 할 수 있습니다.

아래 '의사 코드'조각에서 바닥 부분에 필요한 보간 오프셋을 이미 계산합니다.

  • 먼저 코디 (x, y, z, u, v)를 순서대로 주문하여 coord [0] .y <coord [1] .y <coord [2] .y.
  • 다음으로 2 개의 좌표 세트가 동일한지 확인하십시오 (x 및 y 만 확인). 그렇다면 그리지 마십시오
  • 예외 : 삼각형에는 평평한 상단이 있습니까? 그렇다면 첫 번째 경사는 무한합니다
  • 예외 2 : 삼각형의 바닥이 평평한가?
  • 두 개의 경사 (왼쪽 및 오른쪽)를 계산합니다.
    LeftDeltax = (x [1] -x [0]) / (y [1] -y [0]) 및 RightDeltax = (x [2] -x [0]) / (y [2] -y [0] )
  • 삼각형의 두 번째 부분은 다음에 따라 계산됩니다. 삼각형의 왼쪽이 실제로 leftside에있는 경우 (또는 교환이 필요한 경우)

코드 조각 :

 if (leftDeltaX < rightDeltaX)
 {
      leftDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
      rightDeltaX2 = rightDeltaX
      leftDeltaU = (u[1]-u[0]) / (y[1]-y[0]) //for texture mapping
      leftDeltaU2 = (u[2]-u[1]) / (y[2]-y[1])
      leftDeltaV = (v[1]-v[0]) / (y[1]-y[0]) //for texture mapping
      leftDeltaV2 = (v[2]-v[1]) / (y[2]-y[1])
      leftDeltaZ = (z[1]-z[0]) / (y[1]-y[0]) //for texture mapping
      leftDeltaZ2 = (z[2]-z[1]) / (y[2]-y[1])
 }
 else
 {
      swap(leftDeltaX, rightDeltaX);
      leftDeltaX2 = leftDeltaX;
      rightDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
      leftDeltaU = (u[2]-u[0]) / (y[2]-y[0]) //for texture mapping
      leftDeltaU2 = leftDeltaU
      leftDeltaV = (v[2]-v[0]) / (y[2]-y[0]) //for texture mapping
      leftDeltaV2 = leftDeltaV
      leftDeltaZ = (z[2]-z[0]) / (y[2]-y[0]) //for texture mapping
      leftDeltaZ2 = leftDeltaZ
  }
  • x [0]에서 currentleftx와 currentrightx를 설정합니다.
  • LeftDeltav에서 CurrentLeftu, LeftDeltav에서 CurrentLeftv 및 LeftDeltaz의 CurrentLeftz를 설정합니다.
  • 첫 번째 y 범위에 대한 계산 시작 및 종말점 : Starty = Ceil (y [0]); endy = CEIL (Y [1])
  • 서브 픽셀 정확도에 대한 y의 분수 부분에 대한 Prestep x, u, v 및 z (플로트에도 필요하다고 생각합니다) 내 고정 점 알고리즘에 대한 라인과 텍스처를 만들기 위해 필요했습니다. 디스플레이의 해상도)
  • x가 y [1]에 있어야하는 위치를 계산하십시오. [0] 및 u 및 v 및 z에 대해 동일합니다 : Halfwayu = (u [2] -u [0]) * (y [1] -y [0]) / (y [2] -y [0]) + u [0
  • Halfwayx를 사용하여 U 및 V 및 Z의 스테퍼를 계산합니다. if (Halfwayx -x [1] == 0) {slopeu = 0, slopev = 0, slopez = 0} else {slopeu = (Halfwayu -u [1 ]) /(Halfwayx -x [1])} // (및 v와 z에 대해서도 동일)
  • y 상단을 클리핑하십시오 (삼각형 상단이 화면에서 오프가있는 경우 (또는 클리핑 사각형)가있는 경우, 우리가 그려지기 시작하는 곳을 계산하십시오).
  • y = 스타디; y <endy; y ++) {
    • 화면의 바닥이 과거입니까? 렌더링 중지!
    • 첫 번째 수평선 LeftCurx = Ceil (startx)의 Calc Startx 및 Endx; LeftCury = CEIL (Endy);
    • 화면 (또는 클리핑 영역)의 왼쪽 수평 테두리로 그릴 라인을 클립합니다.
    • 대상 버퍼에 대한 포인터 준비 (매번 배열 인덱스를 통해 너무 느리게 수행) 설계되지 않은 int buf = destbuf + (y피치) + startx; (24 비트 또는 32 비트 렌더링을 수행하는 경우 서명되지 않은 int) 여기에서 Zbuffer 포인터를 준비하십시오 (이 사용중인 경우)
    • for (x = startx; x <endx; x ++) {
      • 이제 원근감 텍스처 매핑의 경우 (Bilineair 보간 없음 사용) : 다음을 수행합니다) :

코드 조각 :

         float tv = startV / startZ
         float tu = startU / startZ;
         tv %= texturePitch;  //make sure the texture coordinates stay on the texture if they are too wide/high
         tu %= texturePitch;  //I'm assuming square textures here. With fixed point you could have used &=
         unsigned int *textPtr = textureBuf+tu + (tv*texturePitch);   //in case of fixedpoints one could have shifted the tv. Now we have to multiply everytime. 
         int destColTm = *(textPtr);  //this is the color (if we only use texture mapping)  we'll be needing for the pixel
  • 더미 라인
    • 더미 라인
      • 더미 라인
      • 선택 사항 :이 좌표에서 이전에 플롯 된 픽셀이 우리보다 높거나 낮은 경우 Zbuffer를 확인하십시오.
      • 픽셀을 플로팅하십시오
      • startz += 슬로프; startu+= 경사; startv += slopev; // 모든 보간기를 업데이트합니다
    • } x 루프의 끝
    • LeftCurx+= LeftDeltax; RightCurx += RightDeltax; LeftCuru+= RightDeltau; LeftCurv += RightDeltav; LeftCurz += RightDeltaz; // y 보간기 업데이트
  • } y 루프의 끝

    // 이것이 첫 번째 부분의 끝입니다. 우리는 이제 삼각형의 절반을 그렸습니다. 상단에서 중간 y 좌표로. // 이제 우리는 기본적으로 똑같은 일을하지만 이제 삼각형의 하단 절반 (다른 보간기 세트 사용).

'더미 라인'에 대해 죄송합니다. 마크 다운 코드를 동기화해야했습니다. (의도 한대로 모든 것을 분류하는 데 시간이 걸렸습니다)

이것이 당신이 직면 한 문제를 해결하는 데 도움이된다면 알려주세요!

다른 팁

나는 당신의 질문에 도움을 줄 수 있다는 것을 모르겠지만, 당시에 읽은 소프트웨어 렌더링에 관한 최고의 책 중 하나는 온라인으로 제공됩니다. 그래픽 프로그래밍 블랙 북 Michael Abrash.

보간 된 경우 1/z, 당신은 곱해야합니다 UV/z ~에 의해 z, 아니다 1/z. 당신이 이것을 가지고 있다고 가정합니다 :

UV = UV_current * z_current

그리고 z_current 보간 중입니다 1/z, 당신은 그것을 변경해야합니다.

UV = UV_current / z_current

그런 다음 이름을 바꾸고 싶을 수도 있습니다 z_current 같은 것입니다 one_over_z_current.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top