Ejemplo n.º 1
0
// 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();
}
Ejemplo n.º 2
0
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;
}