// update graphics void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) { bool override_camera; RAS_Rect viewport, area; float nearfrust, farfrust, focallength; // KX_Camera* cam = scene->GetActiveCamera(); if (!cam) return; GetSceneViewport(scene, cam, area, viewport); // store the computed viewport in the scene scene->SetSceneViewport(viewport); // set the viewport for this frame and scene m_canvas->SetViewPort(viewport.GetLeft(), viewport.GetBottom(), viewport.GetRight(), viewport.GetTop()); // see KX_BlenderMaterial::Activate //m_rasterizer->SetAmbient(); m_rasterizer->DisplayFog(); override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName); override_camera = override_camera && (cam->GetName() == "__default__cam__"); if (override_camera && m_overrideCamUseOrtho) { m_rasterizer->SetProjectionMatrix(m_overrideCamProjMat); if (!cam->hasValidProjectionMatrix()) { // needed to get frustrum planes for culling MT_Matrix4x4 projmat; projmat.setValue(m_overrideCamProjMat.getPointer()); cam->SetProjectionMatrix(projmat); } } else if (cam->hasValidProjectionMatrix() && !cam->GetViewport() ) { m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix()); } else { RAS_FrameFrustum frustum; bool orthographic = !cam->GetCameraData()->m_perspective; nearfrust = cam->GetCameraNear(); farfrust = cam->GetCameraFar(); focallength = cam->GetFocalLength(); MT_Matrix4x4 projmat; if(override_camera) { nearfrust = m_overrideCamNear; farfrust = m_overrideCamFar; } if (orthographic) { RAS_FramingManager::ComputeOrtho( scene->GetFramingType(), area, viewport, cam->GetScale(), nearfrust, farfrust, frustum ); if (!cam->GetViewport()) { frustum.x1 *= m_cameraZoom; frustum.x2 *= m_cameraZoom; frustum.y1 *= m_cameraZoom; frustum.y2 *= m_cameraZoom; } projmat = m_rasterizer->GetOrthoMatrix( frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); } else { RAS_FramingManager::ComputeFrustum( scene->GetFramingType(), area, viewport, cam->GetLens(), nearfrust, farfrust, frustum ); if (!cam->GetViewport()) { frustum.x1 *= m_cameraZoom; frustum.x2 *= m_cameraZoom; frustum.y1 *= m_cameraZoom; frustum.y2 *= m_cameraZoom; } projmat = m_rasterizer->GetFrustumMatrix( frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar, focallength); } cam->SetProjectionMatrix(projmat); // Otherwise the projection matrix for each eye will be the same... if (!orthographic && m_rasterizer->Stereo()) cam->InvalidateProjectionMatrix(); } MT_Transform camtrans(cam->GetWorldToCamera()); MT_Matrix4x4 viewmat(camtrans); m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); cam->SetModelviewMatrix(viewmat); // The following actually reschedules all vertices to be // redrawn. There is a cache between the actual rescheduling // and this call though. Visibility is imparted when this call // runs through the individual objects. m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_CULLING); scene->CalculateVisibleMeshes(m_rasterizer,cam); m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_RENDER); scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); if (scene->GetPhysicsEnvironment()) scene->GetPhysicsEnvironment()->debugDrawWorld(); m_rasterizer->FlushDebugLines(); //it's running once for every scene (i.e. overlay scenes have it running twice). That's not the ideal. PostRenderFrame(); }
void ImageRender::Render() { RAS_FrameFrustum frustrum; if (!m_render) return; if (m_mirror) { // mirror mode, compute camera frustrum, position and orientation // convert mirror position and normal in world space const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation(); const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition(); const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling(); MT_Point3 mirrorWorldPos = mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos); MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ; // get observer world position const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition(); // get plane D term = mirrorPos . normal MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ); // compute distance of observer to mirror = D - observerPos . normal MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ); // if distance < 0.01 => observer is on wrong side of mirror, don't render if (observerDistance < 0.01) return; // set camera world position = observerPos + normal * 2 * distance MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ; m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos); // set camera orientation: z=normal, y=mirror_up in world space, x= y x z MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY; MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX; MT_Matrix3x3 cameraWorldOri( mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0], mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1], mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]); m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri); m_camera->GetSGNode()->UpdateWorldData(0.0); // compute camera frustrum: // get position of mirror relative to camera: offset = mirrorPos-cameraPos MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos; // convert to camera orientation mirrorOffset = mirrorOffset * cameraWorldOri; // scale mirror size to world scale: // get closest local axis for mirror Y and X axis and scale height and width by local axis scale MT_Scalar x, y; x = fabs(m_mirrorY[0]); y = fabs(m_mirrorY[1]); float height = (x > y) ? ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); x = fabs(m_mirrorX[0]); y = fabs(m_mirrorX[1]); float width = (x > y) ? ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); width *= m_mirrorHalfWidth; height *= m_mirrorHalfHeight; // left = offsetx-width // right = offsetx+width // top = offsety+height // bottom = offsety-height // near = -offsetz // far = near+100 frustrum.x1 = mirrorOffset[0]-width; frustrum.x2 = mirrorOffset[0]+width; frustrum.y1 = mirrorOffset[1]-height; frustrum.y2 = mirrorOffset[1]+height; frustrum.camnear = -mirrorOffset[2]; frustrum.camfar = -mirrorOffset[2]+m_clip; } // Store settings to be restored later const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); RAS_Rect area = m_canvas->GetWindowArea(); // The screen area that ImageViewport will copy is also the rendering zone m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1); m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]); m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); m_rasterizer->BeginFrame(m_engine->GetClockTime()); m_scene->GetWorldInfo()->UpdateWorldSettings(); m_rasterizer->SetAuxilaryClientInfo(m_scene); m_rasterizer->DisplayFog(); // matrix calculation, don't apply any of the stereo mode m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO); if (m_mirror) { // frustrum was computed above // get frustrum matrix and set projection matrix MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); m_camera->SetProjectionMatrix(projmat); } else if (m_camera->hasValidProjectionMatrix()) { m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix()); } else { float lens = m_camera->GetLens(); float sensor_x = m_camera->GetSensorWidth(); float sensor_y = m_camera->GetSensorHeight(); float shift_x = m_camera->GetShiftHorizontal(); float shift_y = m_camera->GetShiftVertical(); bool orthographic = !m_camera->GetCameraData()->m_perspective; float nearfrust = m_camera->GetCameraNear(); float farfrust = m_camera->GetCameraFar(); float aspect_ratio = 1.0f; Scene *blenderScene = m_scene->GetBlenderScene(); MT_Matrix4x4 projmat; // compute the aspect ratio from frame blender scene settings so that render to texture // works the same in Blender and in Blender player if (blenderScene->r.ysch != 0) aspect_ratio = float(blenderScene->r.xsch*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp); if (orthographic) { RAS_FramingManager::ComputeDefaultOrtho( nearfrust, farfrust, m_camera->GetScale(), aspect_ratio, m_camera->GetSensorFit(), shift_x, shift_y, frustrum ); projmat = m_rasterizer->GetOrthoMatrix( frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); } else { RAS_FramingManager::ComputeDefaultFrustum( nearfrust, farfrust, lens, sensor_x, sensor_y, RAS_SENSORFIT_AUTO, shift_x, shift_y, aspect_ratio, frustrum); projmat = m_rasterizer->GetFrustumMatrix( frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); } m_camera->SetProjectionMatrix(projmat); } MT_Transform camtrans(m_camera->GetWorldToCamera()); MT_Matrix4x4 viewmat(camtrans); m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective); m_camera->SetModelviewMatrix(viewmat); // restore the stereo mode now that the matrix is computed m_rasterizer->SetStereoMode(stereomode); if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) { // In QUAD buffer stereo mode, the GE render pass ends with the right eye on the right buffer // but we need to draw on the left buffer to capture the render // TODO: implement an explicit function in rasterizer to restore the left buffer. m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE); } m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); m_engine->UpdateAnimations(m_scene); m_scene->RenderBuckets(camtrans, m_rasterizer); m_scene->RenderFonts(); // restore the canvas area now that the render is completed m_canvas->GetWindowArea() = area; }