Render3D: Another rework on viewport transformations in SoftRasterizer and OpenGL. Completes fixes on #27.

- Also fixes major rendering regressions with SoftRasterizer in Metroid
Prime Hunters and Princess Debut. (Regressions from e02d134.)
This commit is contained in:
rogerman 2017-02-23 15:40:23 -08:00
parent 5335312704
commit c71da856f5
3 changed files with 44 additions and 42 deletions

View File

@ -3149,12 +3149,21 @@ Render3DError OpenGLRenderer_1_2::SetupTexture(const POLY &thePoly, size_t polyR
Render3DError OpenGLRenderer_1_2::SetupViewport(const u32 viewportValue)
{
const GLfloat wScalar = this->_framebufferWidth / GPU_FRAMEBUFFER_NATIVE_WIDTH;
const GLfloat hScalar = this->_framebufferHeight / GPU_FRAMEBUFFER_NATIVE_HEIGHT;
const GLfloat wScalar = this->_framebufferWidth / (GLfloat)GPU_FRAMEBUFFER_NATIVE_WIDTH;
const GLfloat hScalar = this->_framebufferHeight / (GLfloat)GPU_FRAMEBUFFER_NATIVE_HEIGHT;
VIEWPORT viewport;
viewport.decode(viewportValue);
glViewport(viewport.x * wScalar, viewport.y * hScalar, viewport.width * wScalar, viewport.height * hScalar);
// The maximum viewport y-value is 191. Values above 191 need to wrap
// around and go negative.
//
// Test case: The Homie Rollerz character select screen sets the y-value
// to 253, which then wraps around to -2.
glViewport( viewport.x * wScalar,
(viewport.y > 191) ? (viewport.y - 0xFF) * hScalar : viewport.y * hScalar,
viewport.width * wScalar,
viewport.height * hScalar);
return OGLERROR_NOERR;
}

View File

@ -1006,7 +1006,7 @@ static void* execRasterizerUnit(void *arg)
static void* SoftRasterizer_RunCalculateVertices(void *arg)
{
SoftRasterizerRenderer *softRender = (SoftRasterizerRenderer *)arg;
softRender->performViewportTransforms<false>();
softRender->performViewportTransforms();
softRender->performBackfaceTests();
softRender->performCoordAdjustment();
@ -1479,12 +1479,10 @@ size_t SoftRasterizerRenderer::performClipping(const VERTLIST *vertList, const P
return clipper.clippedPolyCounter;
}
template<bool CUSTOM> void SoftRasterizerRenderer::performViewportTransforms()
void SoftRasterizerRenderer::performViewportTransforms()
{
const float xfactor = (float)this->_framebufferWidth/(float)GPU_FRAMEBUFFER_NATIVE_WIDTH;
const float yfactor = (float)this->_framebufferHeight/(float)GPU_FRAMEBUFFER_NATIVE_HEIGHT;
const float xmax = (float)this->_framebufferWidth-(CUSTOM?0.001f:0); //fudge factor to keep from overrunning render buffers
const float ymax = (float)this->_framebufferHeight-(CUSTOM?0.001f:0);
const float wScalar = (float)this->_framebufferWidth / (float)GPU_FRAMEBUFFER_NATIVE_WIDTH;
const float hScalar = (float)this->_framebufferHeight / (float)GPU_FRAMEBUFFER_NATIVE_HEIGHT;
//viewport transforms
for (size_t i = 0; i < this->_clippedPolyCount; i++)
@ -1494,12 +1492,21 @@ template<bool CUSTOM> void SoftRasterizerRenderer::performViewportTransforms()
{
VERT &vert = poly.clipVerts[j];
// TODO: Possible divide by zero with the w-coordinate.
// Is the vertex being read correctly? Is 0 a valid value for w?
// If both of these questions answer to yes, then how does the NDS handle a NaN?
// For now, simply prevent w from being zero.
//
// Test case: Dance scenes in Princess Debut can generate undefined vertices
// when the -ffast-math option (relaxed IEEE754 compliance) is used.
const float vertw = (vert.coord[3] != 0.0f) ? vert.coord[3] : 0.00000001f;
//homogeneous divide
vert.coord[0] = (vert.coord[0]+vert.coord[3]) / (2*vert.coord[3]);
vert.coord[1] = (vert.coord[1]+vert.coord[3]) / (2*vert.coord[3]);
vert.coord[2] = (vert.coord[2]+vert.coord[3]) / (2*vert.coord[3]);
vert.texcoord[0] /= vert.coord[3];
vert.texcoord[1] /= vert.coord[3];
vert.coord[0] = (vert.coord[0]+vertw) / (2*vertw);
vert.coord[1] = (vert.coord[1]+vertw) / (2*vertw);
vert.coord[2] = (vert.coord[2]+vertw) / (2*vertw);
vert.texcoord[0] /= vertw;
vert.texcoord[1] /= vertw;
//CONSIDER: do we need to guarantee that these are in bounds? perhaps not.
//vert.coord[0] = max(0.0f,min(1.0f,vert.coord[0]));
@ -1507,44 +1514,30 @@ template<bool CUSTOM> void SoftRasterizerRenderer::performViewportTransforms()
//vert.coord[2] = max(0.0f,min(1.0f,vert.coord[2]));
//perspective-correct the colors
vert.fcolor[0] /= vert.coord[3];
vert.fcolor[1] /= vert.coord[3];
vert.fcolor[2] /= vert.coord[3];
vert.fcolor[0] /= vertw;
vert.fcolor[1] /= vertw;
vert.fcolor[2] /= vertw;
//viewport transformation
VIEWPORT viewport;
viewport.decode(poly.poly->viewport);
vert.coord[0] *= viewport.width;
vert.coord[0] += viewport.x;
// The maximum viewport y-value is 191. Values above 191 need to wrap
// around and go negative.
//
// Test case: The Homie Rollerz character select screen sets the y-value
// to 253, which then wraps around to -2.
vert.coord[1] *= viewport.height;
vert.coord[1] += viewport.y;
vert.coord[1] += (viewport.y > 191) ? (viewport.y - 0xFF) : viewport.y;
vert.coord[1] = 192 - vert.coord[1];
//this is required to fix Homie Rollerz character select.
//this was also a better fix for Princess Debut's giant out of range polys.
//Basically, invalid viewports are blithely used here, and the math overflows and wraps around
//NOTE: this is a crude approximation of the correct fixed point modular arithmetic
//NOTE: you'd think we need >= 256 here, but that just isnt the way it works out (on softrasterizer) right now. coordinates @ 256.0 exactly will come in here.
if(vert.coord[0] > 256) vert.coord[0] -= 256;
if(vert.coord[1] > 256) vert.coord[1] -= 256;
if(vert.coord[0] < 0) vert.coord[0] += 256;
if(vert.coord[1] < 0) vert.coord[1] += 256;
//now, this is really lame. probably the rasterizer should be dealing with this, but
//1. its easier here
//2. its more likely reusable in opengl this way (well, this is a bunch more calculations that should be earlier in the pipeline and obligatorily shared)
//I do have some evidence that this wrecks the hardware extremely, but nothing's likely to use that effect.
//This is a sanity check only.
if(vert.coord[1] >= 192) vert.coord[1] = 192;
vert.coord[0] *= xfactor;
vert.coord[1] *= yfactor;
vert.coord[0] *= wScalar;
vert.coord[1] *= hScalar;
}
}
}
//these templates needed to be instantiated manually
template void SoftRasterizerRenderer::performViewportTransforms<true>();
template void SoftRasterizerRenderer::performViewportTransforms<false>();
void SoftRasterizerRenderer::performCoordAdjustment()
{
@ -1665,7 +1658,7 @@ Render3DError SoftRasterizerRenderer::BeginRender(const GFX3D &engine)
}
else
{
this->performViewportTransforms<false>();
this->performViewportTransforms();
this->performBackfaceTests();
this->performCoordAdjustment();
this->GetAndLoadAllTextures();

View File

@ -127,7 +127,7 @@ public:
SoftRasterizerRenderer();
virtual ~SoftRasterizerRenderer();
template<bool CUSTOM> void performViewportTransforms();
void performViewportTransforms();
void performBackfaceTests();
void performCoordAdjustment();
void GetAndLoadAllTextures();