示例#1
0
// renderShadowLayer - Calculates projection for, and renders, one shadow layer
void DistantLand::renderShadowLayer(int layer, float radius)
{
    DECLARE_MWBRIDGE
    D3DXVECTOR3 lookAt, nearPos;
    D3DXVECTOR3 up(0, 0, 1);
    D3DXMATRIX *view = &smView[layer], *proj = &smProj[layer], *viewproj = &smViewproj[layer];

    // Select light vector, sunPos during daytime, sunVec during night
    D3DXVECTOR4 lightVec = (sunPos.z > 0) ? -sunPos : sunVec;

    // Centre of projection is ahead of the player
    // Not as far in z direction as player is likely looking at the ground plane rather than below
    lookAt.x = eyePos.x + radius * eyeVec.x;
    lookAt.y = eyePos.y + radius * eyeVec.y;
    lookAt.z = eyePos.z + 0.5 * radius * eyeVec.z;

    // Quantize projection centre to reduce texture swimming
    lookAt.x = 16.0 * floor(lookAt.x / 16.0);
    lookAt.y = 16.0 * floor(lookAt.y / 16.0);
    lookAt.z = 16.0 * floor(lookAt.z / 16.0);

    // Create shadow frustum centred on lookAt, looking along lightVec
    const float zrange = 8192.0;
    nearPos.x = lookAt.x - zrange * lightVec.x;
    nearPos.y = lookAt.y - zrange * lightVec.y;
    nearPos.z = lookAt.z - zrange * lightVec.z;

    D3DXMatrixLookAtRH(view, &nearPos, &lookAt, &up);
    D3DXMatrixOrthoRH(proj, 2 * radius, (1 + fabs(lightVec.z)) * radius, 0, 2.0 * zrange);
    *viewproj = (*view) * (*proj);

    // Texel quantization produces hideous temporal aliasing
    //viewproj->_41 = floor(viewproj->_41 * 512.0) / 512.0;
    //viewproj->_42 = floor(viewproj->_42 * 512.0) / 512.0;

    effect->SetMatrixArray(ehShadowViewproj, viewproj, 1);
    effectShadow->CommitChanges();

    // Cull
    ViewFrustum range_frustum(viewproj);
    VisibleSet visible_set;

    currentWorldSpace->NearStatics->GetVisibleMeshesCoarse(range_frustum, visible_set);
    currentWorldSpace->FarStatics->GetVisibleMeshesCoarse(range_frustum, visible_set);
    currentWorldSpace->VeryFarStatics->GetVisibleMeshesCoarse(range_frustum, visible_set);

    // Render land and statics
    if(mwBridge->IsExterior())
        renderDistantLand(effectShadow, view, proj);

    device->SetVertexDeclaration(StaticDecl);
    visible_set.Render(device, effectShadow, effect, &ehTex0, &ehHasAlpha, &ehWorld, SIZEOFSTATICVERT);
}
示例#2
0
void DistantLand::renderWaterReflection(const D3DXMATRIX *view, const D3DXMATRIX *proj)
{
    DECLARE_MWBRIDGE

    // Switch to render target
    RenderTargetSwitcher rtsw(texReflection, surfReflectionZ);
    device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, horizonCol, 1.0, 0);

    // Calculate reflected view matrix, mirror plane at water mesh level
    D3DXMATRIX reflView;
    D3DXPLANE plane(0, 0, 1.0, -(mwBridge->WaterLevel() - 1.0));
    D3DXMatrixReflect(&reflView, &plane);
    D3DXMatrixMultiply(&reflView, &reflView, view);
    effect->SetMatrix(ehView, &reflView);

    // Calculate new projection
    D3DXMATRIX reflProj = *proj;
    editProjectionZ(&reflProj, 4.0, Configuration.DL.DrawDist * kCellSize);
    effect->SetMatrix(ehProj, &reflProj);

    // Clipping setup
    D3DXMATRIX clipMat;

    // Clip geometry on opposite side of water plane
    plane *= mwBridge->IsUnderwater(eyePos.z) ? -1.0 : 1.0;

    // If using dynamic ripples, the water level can be lowered by up to 0.5 * waveheight
    // so move clip plane downwards at the cost of some reflection errors
    if(Configuration.MGEFlags & DYNAMIC_RIPPLES)
        plane.d += 0.5 * Configuration.DL.WaterWaveHeight;

    // Doing inverses separately is a lot more numerically stable
    D3DXMatrixInverse(&clipMat, 0, &reflView);
    D3DXMatrixTranspose(&clipMat, &clipMat);
    D3DXPlaneTransform(&plane, &plane, &clipMat);

    D3DXMatrixInverse(&clipMat, 0, &reflProj);
    D3DXMatrixTranspose(&clipMat, &clipMat);
    D3DXPlaneTransform(&plane, &plane, &clipMat);

    if(visDistant.size() == 0)
    {
        // Workaround for a Direct3D bug with clipping planes, where SetClipPlane
        // has no effect on the shader pipeline if the last rendered draw call was using
        // the fixed function pipeline. This is usually covered by distant statics, but
        // not in compact interiors where all distant statics may be culled.
        // Provoking a DrawPrimitive with shader here makes the following SetClipPlane work.
        effect->BeginPass(PASS_WORKAROUND);
        device->SetVertexDeclaration(WaterDecl);
        device->SetStreamSource(0, vbFullFrame, 0, 12);
        device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
        effect->EndPass();
    }

    device->SetClipPlane(0, plane);
    device->SetRenderState(D3DRS_CLIPPLANEENABLE, 1);

    // Rendering
    if(mwBridge->IsExterior() && (Configuration.MGEFlags & REFLECTIVE_WATER))
    {
        // Draw land reflection, with opposite culling
        effect->BeginPass(PASS_RENDERLANDREFL);
        device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
        renderDistantLand(effect, &reflView, &reflProj);
        effect->EndPass();
    }

    if(isDistantCell() && (Configuration.MGEFlags & REFLECT_NEAR))
    {
        // Draw statics reflection, with opposite culling and no dissolve
        DWORD p = (mwBridge->CellHasWeather() && !mwBridge->IsUnderwater(eyePos.z)) ? PASS_RENDERSTATICSEXTERIOR : PASS_RENDERSTATICSINTERIOR;
        effect->SetFloat(ehNearViewRange, 0);
        effect->BeginPass(p);
        device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
        renderReflectedStatics(&reflView, &reflProj);
        effect->EndPass();
        effect->SetFloat(ehNearViewRange, nearViewRange);
    }

    if((Configuration.MGEFlags & REFLECT_SKY) && !recordSky.empty() && !mwBridge->IsUnderwater(eyePos.z))
    {
        // Draw sky reflection, with opposite culling
        effect->BeginPass(PASS_RENDERSKY);
        device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
        renderReflectedSky();
        effect->EndPass();
    }

    // Restore view state
    device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
    effect->SetMatrix(ehView, view);
    effect->SetMatrix(ehProj, proj);
}
示例#3
0
// renderStage0 - Render distant land at beginning of scene 0, after sky
void DistantLand::renderStage0()
{
    DECLARE_MWBRIDGE
    IDirect3DStateBlock9 *stateSaved;
    UINT passes;

    // Get Morrowind camera matrices
    device->GetTransform(D3DTS_VIEW, &mwView);
    device->GetTransform(D3DTS_PROJECTION, &mwProj);

    // Set variables derived from current camera configuration
    setView(&mwView);
    adjustFog();
    setupCommonEffect(&mwView, &mwProj);

    // Select distant static set
    selectDistantCell();
    isRenderCached &= (Configuration.MGEFlags & USE_MENU_CACHING) && mwBridge->IsMenu();

    if(!isRenderCached)
    {
        ///LOG::logline("Sky prims: %d", recordSky.size());

        if(isDistantCell())
        {
            // Save state block manually since we can change FVF/decl
            device->CreateStateBlock(D3DSBT_ALL, &stateSaved);
            effect->BeginPass(PASS_SETUP);
            effect->EndPass();

            // Shadow map early render
            if(Configuration.MGEFlags & USE_SHADOWS)
            {
                if(mwBridge->CellHasWeather() && !mwBridge->IsMenu())
                {
                    effectShadow->Begin(&passes, D3DXFX_DONOTSAVESTATE);
                    renderShadowMap();
                    effectShadow->End();
                }
            }

            // Distant everything; bias the projection matrix such that
            // distant land gets drawn behind anything Morrowind would draw
            D3DXMATRIX distProj = mwProj;
            distProj._33 += kDistantZBias;
            effect->SetMatrix(ehProj, &distProj);

            effect->Begin(&passes, D3DXFX_DONOTSAVESTATE);

            if(!mwBridge->IsUnderwater(eyePos.z))
            {
                // Draw distant landscape
                if(mwBridge->IsExterior())
                {
                    effect->BeginPass(PASS_RENDERLAND);
                    renderDistantLand(effect, &mwView, &distProj);
                    effect->EndPass();
                }

                // Draw distant statics, with alpha dissolve as they pass the near view boundary
                DWORD p = mwBridge->CellHasWeather() ? PASS_RENDERSTATICSEXTERIOR : PASS_RENDERSTATICSINTERIOR;
                effect->SetFloat(ehDissolveRange, 7168.0);
                effect->BeginPass(p);
                cullDistantStatics(&mwView, &distProj);
                renderDistantStatics();
                effect->EndPass();
            }

            // Sky scattering and sky objects (should be drawn late as possible)
            if((Configuration.MGEFlags & USE_ATM_SCATTER) && mwBridge->CellHasWeather())
            {
                effect->BeginPass(PASS_RENDERSKY);
                renderSky();
                effect->EndPass();
            }

            // Update reflection
            if(mwBridge->CellHasWater())
                renderWaterReflection(&mwView, &distProj);

            // Update water simulation
            if(Configuration.MGEFlags & DYNAMIC_RIPPLES)
                simulateDynamicWaves();

            effect->End();

            // Reset matrices
            effect->SetMatrix(ehView, &mwView);
            effect->SetMatrix(ehProj, &mwProj);

            // Save distant land only frame to texture
            if(~Configuration.MGEFlags & NO_MW_MGE_BLEND)
                texDistantBlend = PostShaders::borrowBuffer(1);

            // Restore render state
            stateSaved->Apply();
            stateSaved->Release();
        }
        else
        {
            // Clear water reflection to avoid seeing previous cell environment reflected
            // Must be done every frame to react to lighting changes
            clearReflection();

            // Update water simulation
            if(Configuration.MGEFlags & DYNAMIC_RIPPLES)
            {
                // Save state block manually since we can change FVF/decl
                device->CreateStateBlock(D3DSBT_ALL, &stateSaved);

                effect->Begin(&passes, D3DXFX_DONOTSAVESTATE);
                simulateDynamicWaves();
                effect->End();

                // Restore render state
                stateSaved->Apply();
                stateSaved->Release();
            }
        }
    }

    // Clear stray recordings
    recordMW.clear();
    recordSky.clear();
}