0
\$\begingroup\$

I'm trying to implement supersampling antialiasing in my software renderer.And per my understanding,I need first render everything to a 4x- scaled buffer then average every four pixels' colors of that 4x-scaled buffer to a smaller 1X buffer.However,supersampling should be transparent to user,user would only pass in vertices within that 1X-scaled smaller buffer.And my question is how to map vertices from a smaller buffer to a scaled buffer?

some definition of my buffers:

    Surface     sysBuffer;
    Surface     superSamplingSysBuffer;
    static constexpr unsigned int ScreenWidth = 400;
    static constexpr unsigned int ScreenHeight = 300;
    static constexpr bool superSampling = true;
    static constexpr unsigned int superSamplingNum = 4;

Initialization:

    Graphics::Graphics(HWNDKey& key)
    :
    sysBuffer(ScreenWidth, ScreenHeight),
    superSamplingSysBuffer(ScreenWidth* superSamplingNum, ScreenHeight* superSamplingNum)

Composition of a single frame:

void Game::ComposeFrame(){
    gfx.DrawLineBresenham(0, 200, 200, 200, Color{ 255,255,255 });
}

Line Drawing:

void Graphics::DrawLineBresenham(float x1, float y1, float x2, float y2, Color c) {

    if (Graphics::superSampling) {
        x1 *= Graphics::superSamplingNum;//MY attempts to mapping points to bigger buffer
        y1 *= Graphics::superSamplingNum;
        x2 *= Graphics::superSamplingNum;
        y2 *= Graphics::superSamplingNum;
    }

    if (fabs(x2 - x1) < 1e-6) {
        if (y1 > y2)
        {
            std::swap(x1, x2);
            std::swap(y1, y2);
        }

        int xInt1 = static_cast<int>((x1 + 0.5f));

        for (; y1 < y2; y1++) {
            PutPixel(xInt1, int(y1 + 0.5f), c);
        }
        return;
    }
    else {
        float k, d;
        k = (y2 - y1) / (x2 - x1);
        if (k >= 1.f) {
            if (y1 > y2)
            {
                std::swap(x1, x2);
                std::swap(y1, y2);
            }
            d = 1.f - 0.5f * k;
            for (; y1 < y2; y1++) {
                PutPixel(int(x1 + 0.5f), int(y1 + 0.5f), c);
                if (d >= 0.f)
                {
                    x1++;
                    d += (1.f - k);
                }
                else {
                    d += 1.f;
                }
            }
            return;
        }
        if (0.f <= k && k < 1.f) {
            if (x1 > x2)
            {
                std::swap(x1, x2);
                std::swap(y1, y2);
            }
            d = 0.5f - k;
            for (; x1 < x2; x1++) {
                PutPixel(int(x1 + 0.5f), int(y1 + 0.5f), c);
                if (d < 0.f) {
                    y1++;
                    d += (1.f - k);
                }
                else {
                    d -= k;
                }
            }
            return;
        }
        if (k >= -1.f && k < 0.f) {
            if (x1 > x2) {
                std::swap(x1, x2);
                std::swap(y1, y2);
            }
            d = -0.5f - k;
            for (; x1 < x2; x1++) {
                PutPixel(int(x1 + 0.5f), int(y1 + 0.5f), c);
                if (d > 0.f) {
                    y1--;
                    d -= (1.f + k);
                }
                else {
                    d -= k;
                }
            }
            return;
        }
        if (k < -1.f) {
            if (y1 < y2) {
                std::swap(x1, x2);
                std::swap(y1, y2);
            }

            d = -1.f - 0.5f * k;

            for (; y1 > y2; y1--) {
                PutPixel(int(x1 + 0.5f), int(y1 + 0.5f), c);
                if (d < 0.f) {
                    x1++;
                    d -= (1.f + k);
                }
                else {
                    d -= 1.f;
                }
            }
            return;
        }
    }


}

Finally downsampling:

void Graphics::EndFrame()
{
    HRESULT hr;


    if (superSampling) {//AVERAGING COLORS
        float sum[4] = { 0 };
        for (int i = 0; i < ScreenWidth; i++) {
            for (int j = 0; j < ScreenHeight; j++) {
                for (int k = i * superSamplingNum; k < (i * superSamplingNum + (superSamplingNum)); k++) {
                    for (int l = j * superSamplingNum; l < (j * superSamplingNum + (superSamplingNum )); l++) {
                        Color temp = superSamplingSysBuffer.GetPixel(k, j);
                        sum[0] += (float)temp.GetR();
                        sum[1] += (float)temp.GetG();
                        sum[2] += (float)temp.GetB();
                        sum[3] += (float)temp.GetA();
                    }
                }

                sum[0] *= 0.25f;
                sum[1] *= 0.25f;
                sum[2] *= 0.25f;
                sum[3] *= 0.25f;
                Color result((unsigned char)sum[3], (unsigned char)sum[0], (unsigned char)sum[1], (unsigned char)sum[2]);
                sysBuffer.PutPixel(i, j, result);
                sum[0] = 0.f;
                sum[1] = 0.f;
                sum[2] = 0.f;
                sum[3] = 0.f;

            }
        }
    }
    //SOME DX11 irrelevent things
    // lock and map the adapter memory for copying over the sysbuffer
    if (FAILED(hr = pImmediateContext->Map(pSysBufferTexture.Get(), 0u,
        D3D11_MAP_WRITE_DISCARD, 0u, &mappedSysBufferTexture)))
    {
        throw CHILI_GFX_EXCEPTION(hr, L"Mapping sysbuffer");
    }
    // perform the copy line-by-line
    sysBuffer.Present(mappedSysBufferTexture.RowPitch,
        reinterpret_cast<BYTE*>(mappedSysBufferTexture.pData));
    // release the adapter memory
    pImmediateContext->Unmap(pSysBufferTexture.Get(), 0u);

    // render offscreen scene texture to back buffer
    pImmediateContext->IASetInputLayout(pInputLayout.Get());
    pImmediateContext->VSSetShader(pVertexShader.Get(), nullptr, 0u);
    pImmediateContext->PSSetShader(pPixelShader.Get(), nullptr, 0u);
    pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    const UINT stride = sizeof(FSQVertex);
    const UINT offset = 0u;
    pImmediateContext->IASetVertexBuffers(0u, 1u, pVertexBuffer.GetAddressOf(), &stride, &offset);
    pImmediateContext->PSSetShaderResources(0u, 1u, pSysBufferTextureView.GetAddressOf());
    pImmediateContext->PSSetSamplers(0u, 1u, pSamplerState.GetAddressOf());
    pImmediateContext->Draw(6u, 0u);

    // flip back/front buffers
    if (FAILED(hr = pSwapChain->Present(1u, 0u)))
    {
        throw CHILI_GFX_EXCEPTION(hr, L"Presenting back buffer");
    }
}

Supersampling off: Supersampling off

Supersampling on:

enter image description here

Disired effect: enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ Your coordinates when rendering to or sampling from the buffer will generally be normalized (either in the -1...1 range of normalized device coordinates or the 0...1 range of texture coordinates), regardless of the actual resolution of the buffer. So there should be approximately nothing novel for you to do here. Can you show us how you've tried to write this code so far, and where specifically you're running into trouble or getting output different than desired? \$\endgroup\$ – DMGregory Dec 31 '20 at 4:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.