void Storm3D_SpotlightShared::setClipPlanes(const float *cameraView) { D3DXMATRIX m(cameraView); float determinant = D3DXMatrixDeterminant(&m); D3DXMatrixInverse(&m, &determinant, &m); D3DXMatrixTranspose(&m, &m); D3DXVECTOR3 d(direction.x, direction.y, direction.z); VC2 bd(d.x, d.z); bd.Normalize(); D3DXVECTOR3 p1(position.x - 8*bd.x, position.y, position.z - 8*bd.y); //D3DXVECTOR3 p1(position.x - 1*bd.x, position.y, position.z - 1*bd.y); D3DXVECTOR3 p2(p1.x, p1.y + 5.f, p1.z); float angle = D3DXToRadian(fov) * .55f; D3DXPLANE leftPlane; D3DXMATRIX leftTransform; D3DXMatrixRotationY(&leftTransform, -angle); D3DXVECTOR3 leftPoint(direction.x, 0, direction.z); D3DXVECTOR4 leftPoint2; D3DXVec3Transform(&leftPoint2, &leftPoint, &leftTransform); leftPoint = p1; leftPoint.x += leftPoint2.x; leftPoint.z += leftPoint2.z; D3DXPlaneFromPoints(&leftPlane, &p1, &p2, &leftPoint); D3DXPlaneNormalize(&leftPlane, &leftPlane); D3DXPlaneTransform(&leftPlane, &leftPlane, &m); D3DXPLANE rightPlane; D3DXMATRIX rightTransform; D3DXMatrixRotationY(&rightTransform, angle); D3DXVECTOR3 rightPoint(direction.x, 0, direction.z); D3DXVECTOR4 rightPoint2; D3DXVec3Transform(&rightPoint2, &rightPoint, &rightTransform); rightPoint = p1; rightPoint.x += rightPoint2.x; rightPoint.z += rightPoint2.z; D3DXPlaneFromPoints(&rightPlane, &rightPoint, &p2, &p1); D3DXPlaneNormalize(&rightPlane, &rightPlane); D3DXPlaneTransform(&rightPlane, &rightPlane, &m); D3DXPLANE backPlane; D3DXVECTOR3 pb(p1.x, p1.y, p1.z); D3DXPlaneFromPointNormal(&backPlane, &pb, &d); D3DXPlaneNormalize(&backPlane, &backPlane); D3DXPlaneTransform(&backPlane, &backPlane, &m); device.SetClipPlane(0, leftPlane); device.SetClipPlane(1, rightPlane); device.SetClipPlane(2, backPlane); device.SetRenderState(D3DRS_CLIPPLANEENABLE, D3DCLIPPLANE0 | D3DCLIPPLANE1 | D3DCLIPPLANE2); }
TEST( Transform, planeTransformation ) { // construct a transformation we'll use for testing Transform trans; Matrix transformMtx; { Matrix m1, m2; EulerAngles angles; angles.set( FastFloat::fromFloat( 45.0f ), FastFloat::fromFloat( 60.0f ), FastFloat::fromFloat( -10.0f ) ); m1.setTranslation( Vector( 1, 2, 3 ) ); m2.setRotation( angles ); transformMtx.setMul( m2, m1 ); trans.set( transformMtx ); } // create a test plane Plane testPlane; testPlane.set( Float_1, Float_0, Float_0, FastFloat::fromFloat( 10.0f ) ); // transform the plane Plane tamyTransformedPlane; trans.transform( testPlane, tamyTransformedPlane ); // let DX help us generate a transformed plane we can compare our results against D3DXPLANE dxTransformedPlane; D3DXMATRIX dxMtx = ( const D3DXMATRIX& )transformMtx; D3DXMatrixInverse( &dxMtx, NULL, &dxMtx ); D3DXMatrixTranspose( &dxMtx, &dxMtx ); D3DXPlaneTransform( &dxTransformedPlane, ( const D3DXPLANE* )&testPlane, &dxMtx ); COMPARE_PLANE( dxTransformedPlane, tamyTransformedPlane ); }
ETOOLS_API D3DXPLANE* WINAPI D3DX_PlaneTransform( D3DXPLANE *pOut, CONST D3DXPLANE *pP, CONST D3DXMATRIX *pM) { return D3DXPlaneTransform(pOut, pP, pM); }
void CMirror::updateTransform() { D3DXMatrixRotationYawPitchRoll(&m_matTrans, m_fAngle[0], m_fAngle[1], m_fAngle[2]); m_matTrans._41 = 4.f; m_matTrans._42 = 3.f; m_matTrans._43 = 1.f; D3DXPLANE plane(0.0f, 0.0f, 1.0f, 0.0f); D3DXMatrixInverse(&m_matMirror, NULL, &m_matTrans); D3DXMatrixTranspose(&m_matMirror, &m_matMirror); D3DXPlaneTransform(&plane, &plane, &m_matMirror); D3DXMatrixReflect(&m_matMirror, &plane); }
// called before rendering void Effect::startEffect() { if (!m_pEffect) return; m_clipPlaneChanged = false; // if a clipping plane is specified, it must be converted to projections space // the plane is currently assumed to be in world space. if (gRenderer.getClipPlaneEnable()) { D3DXMATRIX View, Projection,ViewProj; D3DXPLANE projPlane, worldPlane; //D3DXVECTOR4 projClipPlane; gRenderer.getClipPlane(&m_oldClipPlane); worldPlane.a = m_oldClipPlane.a; worldPlane.b = m_oldClipPlane.b; worldPlane.c = m_oldClipPlane.c; worldPlane.d = m_oldClipPlane.d; // get all matrices from device pD3DDevice->GetTransform(D3DTS_VIEW, & View); pD3DDevice->GetTransform(D3DTS_PROJECTION, & Projection); // multiply them ViewProj = View * Projection; //worldPlane.y *= -1; D3DXPlaneNormalize(&worldPlane, &worldPlane); D3DXMatrixInverse(&ViewProj, NULL ,&ViewProj); D3DXMatrixTranspose(&ViewProj ,&ViewProj); D3DXPlaneTransform(&projPlane, &worldPlane, &ViewProj); D3DXPlaneNormalize(&projPlane, &projPlane); Plane passIn(projPlane.a, projPlane.b, projPlane.c, projPlane.d); gRenderer.setClipPlane(passIn); m_clipPlaneChanged = true; } m_pEffect->Begin(0,0); m_pEffect->BeginPass(0); m_pEffect->CommitChanges(); }
// 카메라에 따라 occlusion의 평면을 갱신한다. void ROcclusionList::UpdateCamera(rmatrix &matWorld,rvector &cameraPos) { // TODO : matWorld 가 identity 가 아닌경우 검증이 안되어있음 float fDet; rmatrix invWorld; D3DXMatrixInverse(&invWorld,&fDet,&matWorld); // camera 의 좌표를 local로 가져온다 rvector localCameraPos; D3DXVec3TransformCoord(&localCameraPos,&cameraPos,&invWorld); rmatrix trInvMat; D3DXMatrixTranspose(&trInvMat, &invWorld); for(ROcclusionList::iterator i=begin();i!=end();i++) { ROcclusion *poc=*i; bool bm_pPositive=D3DXPlaneDotCoord(&poc->plane,&localCameraPos)>0; // 로컬의 평면의 방정식을 월드로 가져가고 싶다. matWorld 로 변환하면되는데, // D3DXPlaneTransform 의 사용법이 변환행렬의 inverse transpose 매트릭스를 넘겨줘야하므로 // tr(inv(matWorld)) 가 되므로 결국 tr(mat) 가 된다 D3DXPlaneTransform(poc->pPlanes,poc->pPlanes,&trInvMat); poc->pPlanes[0] = bm_pPositive ? poc->plane : -poc->plane; for(int j=0;j<poc->nCount;j++) { if(bm_pPositive) D3DXPlaneFromPoints(poc->pPlanes+j+1,&poc->pVertices[j],&poc->pVertices[(j+1)%poc->nCount],&localCameraPos); else D3DXPlaneFromPoints(poc->pPlanes+j+1,&poc->pVertices[(j+1)%poc->nCount],&poc->pVertices[j],&localCameraPos); // 로컬의 평면의 방정식을 월드로 가져가고 싶다. 위와 같다 D3DXPlaneTransform(poc->pPlanes+j+1,poc->pPlanes+j+1,&trInvMat); } } }
/************************************************************************* * D3DXPlaneTransformArray */ D3DXPLANE* WINAPI D3DXPlaneTransformArray( D3DXPLANE* out, UINT outstride, CONST D3DXPLANE* in, UINT instride, CONST D3DXMATRIX* matrix, UINT elements) { UINT i; TRACE("\n"); for (i = 0; i < elements; ++i) { D3DXPlaneTransform( (D3DXPLANE*)((char*)out + outstride * i), (CONST D3DXPLANE*)((const char*)in + instride * i), matrix); } return out; }
OPENGL_API void WINAPI glClipPlane (GLenum plane, const GLdouble *equation) { int planeIndex = plane - GL_CLIP_PLANE0; if (planeIndex < 0 || planeIndex >= IMPL_MAX_CLIP_PLANES) { D3DGlobal.lastError = E_INVALIDARG; return; } D3DXPLANE d3dxPlane((GLfloat)equation[0], (GLfloat)equation[1], (GLfloat)equation[2], (GLfloat)equation[3]); D3DXPLANE d3dxTPlane; D3DXPlaneTransform( &d3dxTPlane, &d3dxPlane, D3DGlobal.modelviewMatrixStack->top().invtrans() ); memcpy( D3DState.TransformState.clipPlane[planeIndex], &d3dxTPlane, sizeof(D3DXPLANE)); D3DState.TransformState.clipPlaneModified[planeIndex] = TRUE; if (D3DState.EnableState.clipPlaneEnableMask & (1 << planeIndex)) D3DState.TransformState.clippingModified = TRUE; }
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); }
void Render(float alpha, float elapsedtime) { static float time = 0; LPDIRECT3DSURFACE9 backbuffer = 0; D3DXMATRIX view, proj, viewproj; D3DXMATRIX world, inv; D3DXVECTOR4 texelsize; D3DXVECTOR4 lightpos(-600, 350, 1000, 1); D3DXVECTOR4 refllight; D3DXVECTOR3 eye(0, 0, -5.0f); D3DXVECTOR3 look(0, 1.2f, 0); D3DXVECTOR3 refleye, refllook; D3DXVECTOR3 up(0, 1, 0); D3DXVECTOR2 orient = cameraangle.smooth(alpha); D3DXMatrixRotationYawPitchRoll(&view, orient.x, orient.y, 0); D3DXVec3TransformCoord(&eye, &eye, &view); eye.y += 1.2f; D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 2, (float)screenwidth / (float)screenheight, 0.1f, 30); time += elapsedtime; if( SUCCEEDED(device->BeginScene()) ) { device->GetRenderTarget(0, &backbuffer); // STEP 1: render reflection texture device->SetRenderTarget(0, reflectsurf); device->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0xff6694ed, 1.0f, 0); D3DXPLANE plane(0, 1, 0, 1); refleye = eye - 2 * D3DXPlaneDotCoord(&plane, &eye) * (D3DXVECTOR3&)plane; refllook = look - 2 * D3DXPlaneDotCoord(&plane, &look) * (D3DXVECTOR3&)plane; refllight = lightpos - 2 * D3DXPlaneDot(&plane, &lightpos) * (D3DXVECTOR4&)plane; refllight.w = 1; D3DXMatrixLookAtLH(&view, &refleye, &refllook, &up); D3DXMatrixMultiply(&viewproj, &view, &proj); D3DXMatrixInverse(&inv, 0, &viewproj); D3DXMatrixTranspose(&inv, &inv); D3DXPlaneTransform(&plane, &plane, &inv); device->SetClipPlane(0, &plane.a); RenderScene(viewproj, refleye, refllight, true); // STEP 2: render scene (later used for refraction) D3DXMatrixLookAtLH(&view, &eye, &look, &up); D3DXMatrixMultiply(&viewproj, &view, &proj); device->SetRenderTarget(0, refractsurf); device->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0xff6694ed, 1.0f, 0); RenderScene(viewproj, eye, lightpos, false); // render water surface into alpha channel for masking device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); D3DXMatrixTranslation(&world, 0, -1, 0); device->SetTransform(D3DTS_WORLD, &world); device->SetTransform(D3DTS_VIEW, &view); device->SetTransform(D3DTS_PROJECTION, &proj); waterplane->DrawSubset(0, DXObject::Opaque); device->SetRenderState(D3DRS_COLORWRITEENABLE, 0x0f); // STEP 3: light shafts quadvertices[6] = quadvertices[24] = quadvertices[30] = (float)screenwidth - 0.5f; quadvertices[13] = quadvertices[19] = quadvertices[31] = (float)screenheight - 0.5f; RenderLightShafts(view, proj, eye, lightpos); // STEP 4: gamma correct device->SetRenderTarget(0, sceneldrsurf); device->SetRenderState(D3DRS_ZENABLE, FALSE); device->SetVertexDeclaration(quaddecl); bloom->SetTechnique("gammacorrect"); bloom->Begin(0, 0); bloom->BeginPass(0); { device->SetTexture(0, refraction); device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, quadvertices, 6 * sizeof(float)); } bloom->EndPass(); bloom->End(); device->SetRenderState(D3DRS_ZENABLE, TRUE); // STEP 5: water surface device->SetRenderState(D3DRS_SRGBWRITEENABLE, TRUE); D3DXMatrixTranslation(&world, 0, -1, 0); D3DXMatrixIdentity(&inv); water->SetMatrix("matViewProj", &viewproj); water->SetMatrix("matWorld", &world); water->SetMatrix("matWorldInv", &inv); water->SetVector("eyePos", (D3DXVECTOR4*)&eye); water->SetVector("lightPos", &lightpos); water->SetVector("lightColor", &lightcolor); water->SetFloat("time", time); water->Begin(0, 0); water->BeginPass(0); { device->SetTexture(0, refraction); device->SetTexture(1, reflection); device->SetTexture(2, waves); waterplane->DrawSubset(0, DXObject::Opaque); } water->EndPass(); water->End(); device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); // STEP 6: downsample & blur quadvertices[6] = quadvertices[24] = quadvertices[30] = (float)screenwidth * 0.5f - 0.5f; quadvertices[13] = quadvertices[19] = quadvertices[31] = (float)screenheight * 0.5f - 0.5f; device->SetRenderTarget(0, bloomsurf1); device->SetRenderState(D3DRS_ZENABLE, FALSE); device->SetVertexDeclaration(quaddecl); texelsize.x = 1.0f / screenwidth; texelsize.y = 1.0f / screenheight; bloom->SetTechnique("downsample"); bloom->SetVector("texelSize", &texelsize); bloom->Begin(0, 0); bloom->BeginPass(0); { device->SetTexture(0, sceneldr); device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, quadvertices, 6 * sizeof(float)); } bloom->EndPass(); bloom->End(); device->SetRenderTarget(0, bloomsurf2); texelsize.x = 2.0f / screenwidth; texelsize.y = 2.0f / screenheight; bloom->SetTechnique("blur"); bloom->SetVector("texelSize", &texelsize); bloom->Begin(0, 0); bloom->BeginPass(0); { device->SetTexture(0, bloomtex1); device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, quadvertices, 6 * sizeof(float)); } bloom->EndPass(); bloom->End(); // STEP 7: add light shafts quadvertices[6] = quadvertices[24] = quadvertices[30] = (float)screenwidth - 0.5f; quadvertices[13] = quadvertices[19] = quadvertices[31] = (float)screenheight - 0.5f; device->SetRenderTarget(0, backbuffer); godray->SetTechnique("final"); godray->Begin(0, 0); godray->BeginPass(0); { device->SetTexture(0, sceneldr); device->SetTexture(1, occluders); device->SetTexture(2, bloomtex2); device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, quadvertices, 6 * sizeof(float)); } godray->EndPass(); godray->End(); backbuffer->Release(); device->SetRenderState(D3DRS_ZENABLE, TRUE); device->EndScene(); } device->Present(NULL, NULL, NULL, NULL); }