camera info managermanager怎么获取camera info manager对象

Android5.0 Camera2 API 如何获取图像数据???
[问题点数:40分]
Android5.0 Camera2 API 如何获取图像数据???
[问题点数:40分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
匿名用户不能发表回复!|Camera APP层分析之对camera framework层封装解析_百度文库
赠送免券下载特权
10W篇文档免费专享
部分付费文档8折起
每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
Camera APP层分析之对camera framework层封装解析
&&android4.4 camera
阅读已结束,下载本文需要
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩7页未读,
定制HR最喜欢的简历
你可能喜欢查看:62009|回复:38
资深技术经理
最近看Camera的api,觉得写的真的不错。现在翻译过来,给大家分享分享,译文可能不太好,大家将就着看哈。
Camera是Android framework里面支持的,允许你拍照和拍摄视频的设备,那么,本文在接下来就会讨论如何为你的用户提供快速,简单的图片和视频拍摄方法。
2. 注意事项
a. 在确定你的程序使用Camera之前,你应该问自己几个问题:
i. Camera Requirement -- 使用照相机是不是对你的程序真的如此重要?如果确定如此,那么请在AndroidMainfest.xml文件中申明要使用照相机。
ii. Quick Picture or Customized Camera -- 快速拍照还是自定义照相机。你只是简单对拍照或者拍摄视频感兴趣还是你的程序要定义一套全新的照相机使用方法?如果只是简单的拍照或者录制视频,我们可以用一种非常简单的方法,如果想自定义照相机,那么请阅读自定义照相机片段。
iii. Storage -- 你的照片或者视频只想让你自己的程序看见,还是想和应用程序共享?比如Gallery,或者其他的多媒体和社交应用。 你是想让你的照片或者视频,即使你的应用已经被用户卸载,还仍然保持可见吗?那么请参考Saving Media Files章节。
ok.. 那么接下来,我们一个个讲解。
3. 在AndroidMainfest.xml中声明使用照相机.
a. Camera权限, 你必须在AndroidMainfest.xml中声明使用照相机的权限,例如
&uses-permission android:name=&android.permission.CAMERA& /&
注:如果你是调用系统Camera程序的话,就不必声明
b. Camera特性,你必须在AndroidMainfest.xml中声明照相机特性,例如:
&uses-feature android:name=&android.hardware.camera& /&
如果你的程序可能需要使用照相机,但并不是一定的,那么可以设置android:required属性,比如:
&uses-feature android:name=&android.hardware.camera& android:required=&false& /&
c. 存储权限,如果你的程序想在扩展存储设备上(如sd卡)存储你的照片或者拍摄的视频,那么必须声明如下权限:
&uses-permission android:name=&android.permission.WRITE_EXTERNAL_STORAGE& /&
d. 音频录制权限, 为了录制音频或者视频,你必须在AndroidMainfest.xml文件中设置如下权限:
&uses-permission android:name=&android.permission.RECORD_AUDIO& /&
4. 使用系统Camera程序
a. 这是一种可以让你的程序以最少的编码,然后可以快速使用照相机的方法,它通过一个Intent来调用系统的Camera程序。一个Camera的intent可以发起一个请求,来让系统的Camera应用程序去拍摄照片或者录制视频,而且可以返回拍摄或者录制的结果给你自己的应用程序,那么接下来,我们将讨论如何使用这种方法。
i. 构造一个Camera Intent -- 创建一个拍摄照片或者视频的Intent, 我们可以使用如下两种方法:
& &MediaStore.ACTION_IMAGE_CAPTURE -- 一个intent action,用来向系统Camera程序请求拍摄图片。
& &MediaStore.ACTION_VIDEO_CAPTURE -- 一个intent action, 用来向系统Camera程序请求录制视频。
ii. 开启Camera intent -- 通过调用startActivityForResult()来执行Camera intent, 在你调用这个方法之后,系统Camera程序就是出现在用户界面,然后用户就可以拍摄照片或者视频了。
iii. 接收Intent 结果 -- 在你的应用程序里面建立一个onActivityResult()方法来接收来自系统Camera程序的执行结果。当用户拍摄了照片或者视频(也许取消了拍摄操作),系统就会调用这个方法。
b. 图片拍摄Intent
使用系统Camera来拍摄图片,是一种以最快的速度,最少的代码,让你的程序能够拍照的方法。一个图片拍摄的intent可以包含如下扩展信息:
i. MediaStore.EXTRA_OUTPUT -- 指定一个Uri对象,系统Camera程序会把拍摄的图片存储到指定位置。这个设置一般是强烈推荐的。如果你不指定这个Uri路径,那么系统Camera程序会把图片以一个默认的名字,存储在一个默认的位置。我们可以通过返回的intent,然后用Intent.getData()方法来获取这个值。
ii. 下面这个例子可以告诉大家怎么构造一个拍摄图片的intent,并且执行它。private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
private Uri fileU
public void onCreate(Bundle savedInstanceState) {
& & super.onCreate(savedInstanceState);
& & setContentView(R.layout.main);
& & // create Intent to take a picture and return control to the calling application
& & Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
& & fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
& & intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
& & // start the image capture Intent
& & startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}当startActivityForResult()方法执行之后,用户就会看到系统的Camera界面。当用户完成拍摄照片(或者取消拍摄)之后,用户界面就会返回你自己的应用程序。那么你必须拦截onActivityResult方法,以便接收执行结果和继续你自己代码的逻辑。
c. 视频录制intent
使用系统Camera来录制视频,是一种以最快的速度,最少的代码,让你的程序能够录制视频的方法。一个视频录制的intent可以包含如下扩展信息:
MediaStore.EXTRA_OUTPUT -- 指定一个Uri对象,系统Camera程序会把录制的视频存储到指定位置。这个设置一般是强烈推荐的。如果你不指定这个Uri路径,那么系统Camera程序会把视频以一个默认的名字,存储在一个默认的位置。我们可以通过返回的intent,然后用Intent.getData()方法来获取这个值。
MediaStore.EXTRA_VIDEO_QUALITY -- 视频质量,0(低质量,比较小的文件来存储视频), 1(高质量,比较大的文件来存储视频)
MediaStore.EXTRA_DURATION_LIMIT&&-- 设置一个值来限制视频时间长度,秒为单位。
MediaStore.EXTRA_SIZE_LIMIT -- 设置一个值来限制视频大小,byte为单位。
下面这个例子可以告诉大家怎么构造一个录制视频的intent,并且执行它。private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;
private Uri fileU
public void onCreate(Bundle savedInstanceState) {
& & super.onCreate(savedInstanceState);
& & setContentView(R.layout.main);
& & //create new Intent
& & Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
& & fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);&&// create a file to save the video
& & intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);&&// set the image file name
& & intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high
& & // start the Video Capture Intent
& & startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
}当startActivityForResult()方法执行之后,用户就会看到系统的Camera界面。当用户完成录制视频(或者取消拍摄)之后,用户界面就会返回你自己的应用程序。那么你必须拦截onActivityResult方法,以便接收执行结果和继续你自己代码的逻辑。
d. 接受Camera返回的结果
一旦你执行了拍摄图片或者视频的intent之后,那么你必须去接收执行结果。那么,下面的内容就是告诉你怎么去接收执行结果,以及进一步处理Camera拍摄的图片或者视频。
为了接受Camera拍摄的结果,你必须重写onActivityResult()方法,如下:private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
& & if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
& && &&&if (resultCode == RESULT_OK) {
& && && && &// Image captured and saved to fileUri specified in the Intent
& && && && &Toast.makeText(this, &Image saved to:\n& +
& && && && && && && &data.getData(), Toast.LENGTH_LONG).show();
& && &&&} else if (resultCode == RESULT_CANCELED) {
& && && && &// User cancelled the image capture
& && &&&} else {
& && && && &// Image capture failed, advise user
& & if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
& && &&&if (resultCode == RESULT_OK) {
& && && && &// Video captured and saved to fileUri specified in the Intent
& && && && &Toast.makeText(this, &Video saved to:\n& +
& && && && && && && &data.getData(), Toast.LENGTH_LONG).show();
& && &&&} else if (resultCode == RESULT_CANCELED) {
& && && && &// User cancelled the video capture
& && &&&} else {
& && && && &// Video capture failed, advise user
}一旦你的Activity接收到成功执行拍摄的结果,那么存储在指定位置的图片或者视频,就能被我们的程序使用了。
5. 构造自己的Camera程序
一些开发者可能需要自己定制Camera应用程序,定制自定义的Camera程序可能比调用系统的Camera需要更多的代码,但是这真的能给你的用户带来不一样的用户体验。。
下面是开发自定义Camera的一般步骤:
a. 检测Camera设备的可访问性 -- 书写代码确认Camera设备是否存在并且请求访问。
b. 创建一个预览窗口 -- 创建一个预览窗口,一般继承SurfaceView并且实现SurfaceHolder接口,这个预览窗口可以通过Camera动态预览图片。
c. 创建一个预览布局 --&&一旦你拥有了预览窗口,那么创建一个视频Layout来封装预览窗口。
d. 设置拍摄监听器 -- 设置图片或者视频拍摄的监听器,比如按下一个Button
e. 拍摄和保存文件
d. 释放Camera设备 -- 拍摄完毕之后,你的程序必须释放Camera设备,以便其他程序使用Camera。
Camera是一个共享的硬件资源,所以你的程序必须非常小心的管理它,以便不能和其他程序发生冲突。下面的内容就是告诉大家怎么去检测Camera设备,怎么去请求访问Camera,以及当你的程序关闭的时候怎么释放Camera。
6. 检测Camera硬件设备
如果你的程序没有在AndroidMainfest.xml中申明请求使用Camera,那么你应该在运行期去检查Camera是否可用。使用PackageManager.hasSystemFeature() 方法,比如:/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
& & if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
& && &&&// this device has a camera
& & } else {
& && &&&// no camera on this device
}注: 一个Android设备可能含有多个Camera设备,比如背部摄像头用来拍照,前部摄像头用来拨打视频电话,那么,Android2.3(API Level 9) 以及以后的版本将允许你检查设备上可以用的Camera设备,通过调用Camera.getNumberOfCameras()方法。
7. 访问Camera设备
为了打开主Camera设备,我们可以调用Camera.open() 方法,如下:/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
& & Camera c =
& && &&&c = Camera.open(); // attempt to get a Camera instance
& & catch (Exception e){
& && &&&// Camera is not available (in use or does not exist)
& & // returns null if camera is unavailable
}注: 当使用Camera.open()方法的时候,无论如何都需要检查是否发生了异常。如果忘记检查异常的话,有可能会因为Camera设备不存在而导致你的应用程序崩溃。
在Android2.3(API Level 9)或者更高版本,你可以通过Camera.open(int)方法来访问指定的Camera设备,
8. 检查Camera属性
一旦你可以访问Camera设备之后,你可以调用Camera.getParameters()方法来获取更多的Camera信息,当使用API Level 9或者更高版本时,可以使用Camera.getCameraInfo()方法来检测Camera设备是前端设备还是背部设备。
9. 创建预览窗口/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
& & private SurfaceHolder mH
& & private Camera mC
& & public CameraPreview(Context context, Camera camera) {
& && &&&super(context);
& && &&&mCamera =
& && &&&// Install a SurfaceHolder.Callback so we get notified when the
& && &&&// underlying surface is created and destroyed.
& && &&&mHolder = getHolder();
& && &&&mHolder.addCallback(this);
& && &&&// deprecated setting, but required on Android versions prior to 3.0
& && &&&mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
& & public void surfaceCreated(SurfaceHolder holder) {
& && &&&// The Surface has been created, now tell the camera where to draw the preview.
& && &&&try {
& && && && &mCamera.setPreviewDisplay(holder);
& && && && &mCamera.startPreview();
& && &&&} catch (IOException e) {
& && && && &Log.d(TAG, &Error setting camera preview: & + e.getMessage());
& & public void surfaceDestroyed(SurfaceHolder holder) {
& && &&&// empty. Take care of releasing the Camera preview in your activity.
& & public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
& && &&&// If your preview can change or rotate, take care of those events here.
& && &&&// Make sure to stop the preview before resizing or reformatting it.
& && &&&if (mHolder.getSurface() == null){
& && && & // preview surface does not exist
& && &&&// stop preview before making changes
& && &&&try {
& && && && &mCamera.stopPreview();
& && &&&} catch (Exception e){
& && && & // ignore: tried to stop a non-existent preview
& && &&&// make any resize, rotate or reformatting changes here
& && &&&// start preview with new settings
& && &&&try {
& && && && &mCamera.setPreviewDisplay(mHolder);
& && && && &mCamera.startPreview();
& && &&&} catch (Exception e){
& && && && &Log.d(TAG, &Error starting camera preview: & + e.getMessage());
}10. 把预览窗口设置到一个Layout里面
定义Activity配置文件,&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout xmlns:android=&http://schemas.android.com/apk/res/android&
& & android:orientation=&horizontal&
& & android:layout_width=&fill_parent&
& & android:layout_height=&fill_parent&
&&&FrameLayout
& & android:id=&@+id/camera_preview&
& & android:layout_width=&fill_parent&
& & android:layout_height=&fill_parent&
& & android:layout_weight=&1&
& & android:id=&@+id/button_capture&
& & android:text=&Capture&
& & android:layout_width=&wrap_content&
& & android:layout_height=&wrap_content&
& & android:layout_gravity=&center&
&/LinearLayout&在大多数设备上,拍摄照片一般是横屏的,所以,你需要添加如下代码:&activity android:name=&.CameraActivity&
& && && & android:label=&@string/app_name&
& && && & android:screenOrientation=&landscape&&
& && && & &!-- configure this activity to use landscape orientation --&
& && && & &intent-filter&
& && &&&&action android:name=&android.intent.action.MAIN& /&
& && &&&&category android:name=&android.intent.category.LAUNCHER& /&
& & &/intent-filter&
&/activity&在Activity中,把预览窗口添加到Layout里面去public class CameraActivity extends Activity {
& & private Camera mC
& & private CameraPreview mP
& & @Override
& & public void onCreate(Bundle savedInstanceState) {
& && &&&super.onCreate(savedInstanceState);
& && &&&setContentView(R.layout.main);
& && &&&// Create an instance of Camera
& && &&&mCamera = getCameraInstance();
& && &&&// Create our Preview view and set it as the content of our activity.
& && &&&mPreview = new CameraPreview(this, mCamera);
& && &&&FrameLayout preview = (FrameLayout) findViewById(id.camera_preview);
& && &&&preview.addView(mPreview);
a. 首先定义一个接口,用来处理拍摄完毕之后的动作。private PictureCallback mPicture = new PictureCallback() {
& & @Override
& & public void onPictureTaken(byte[] data, Camera camera) {
& && &&&File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
& && &&&if (pictureFile == null){
& && && && &Log.d(TAG, &Error creating media file, check storage permissions: & +
& && && && && & e.getMessage());
& && && && &
& && &&&try {
& && && && &FileOutputStream fos = new FileOutputStream(pictureFile);
& && && && &fos.write(data);
& && && && &fos.close();
& && &&&} catch (FileNotFoundException e) {
& && && && &Log.d(TAG, &File not found: & + e.getMessage());
& && &&&} catch (IOException e) {
& && && && &Log.d(TAG, &Error accessing file: & + e.getMessage());
};getOutputMediaFile(int) 方法的实现public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
& && &return Uri.fromFile(getOutputMediaFile(type));
/** Create a File for saving an image or video */
private static Uri getOutputMediaFile(int type){
& & // To be safe, you should check that the SDCard is mounted
& & // using Environment.getExternalStorageState() before doing this.
& & File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
& && && && &&&Environment.DIRECTORY_PICTURES), &MyCameraApp&);
& & // This location works best if you want the created images to be shared
& & // between applications and persist after your app has been uninstalled.
& & // Create the storage directory if it does not exist
& & if (! mediaStorageDir.exists()){
& && &&&if (! mediaStorageDir.mkdirs()){
& && && && &Log.d(&MyCameraApp&, &failed to create directory&);
& && && && &
& & // Create a media file name
& & String timeStamp = new SimpleDateFormat(&yyyyMMdd_HHmmss&).format(new Date());
& & File mediaF
& & if (type == MEDIA_TYPE_IMAGE){
& && &&&mediaFile = new File(mediaStorageDir.getPath() + File.separator +
& && &&&&IMG_&+ timeStamp + &.jpg&);
& & } else if(type == MEDIA_TYPE_VIDEO) {
& && &&&mediaFile = new File(mediaStorageDir.getPath() + File.separator +
& && &&&&VID_&+ timeStamp + &.mp4&);
& & } else {
& & return mediaF
}设置我们刚才的监听器// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
& & captureButton.setOnClickListener(
& && &&&new View.OnClickListener() {
& && &&&@Override
& && &&&public void onClick(View v) {
& && && && &// get an image from the camera
& && && && &mCamera.takePicture(null, null, mPicture);
);好多。。 翻译的我头都晕了,真心觉得api是不错的阅读文档~~
资深技术经理
写的我是眼冒金星。。 :funk:
中级工程师
引用:原帖由 rongwei84n 于
20:05 发表
写的我是眼冒金星。。 :funk: 哈哈,我最近也在看camera 呵呵!
中级工程师
引用:原帖由 四海轩 于
23:44 发表
哈哈,我最近也在看camera 呵呵! 不过,我在用Camera做实时视频方面的东西,伤不起,啥不懂
资深技术经理
引用:原帖由 四海轩 于
23:44 发表
哈哈,我最近也在看camera 呵呵! 我是在看api的时候,看到它有关Camera的描述,觉得写的真不错。。一时没忍住,就想翻译过来,给大家分享下。
后来才知道错了,好多好多内容,到最后,我已经眼冒金星了。:Q
中级工程师
引用:原帖由 rongwei84n 于
09:16 发表
我是在看api的时候,看到它有关Camera的描述,觉得写的真不错。。一时没忍住,就想翻译过来,给大家分享下。
后来才知道错了,好多好多内容,到最后,我已经眼冒金星了。:Q ... 哈哈
提示: 作者被禁止或删除 内容自动屏蔽
支持楼主的分享精神
最有价值午饭
写的真多啊!厉害厉害
资深技术经理
引用:原帖由 xuzw13 于
11:12 发表
写的真多啊!厉害厉害 当时就只觉得头晕目眩 , 眼冒金星 :Q
不错的心得,向你学习了,估计一定也可以学好
资深技术经理
引用:原帖由 变现王 于
12:16 发表
不错的心得,向你学习了,估计一定也可以学好 加油哈~~
刚刚开始学,看不明白啊
额,看着怎么那么像.NET的代码
回忆之叶,粪土人生,我敢固执!
资深技术经理
引用:原帖由 _碎念 于
13:33 发表
额,看着怎么那么像.NET的代码 其实java和c#语法,真的挺像的。。
引用:原帖由 rongwei84n 于
14:57 发表
其实java和c#语法,真的挺像的。。 好把,凌乱了。。。。。。。。。
回忆之叶,粪土人生,我敢固执!
sadfadfasdf
提示: 作者被禁止或删除 内容自动屏蔽
看明白一些,看完了就晕了
中级工程师
你知不知道怎么静默拍照??
就是偷偷的启动前摄像头,拍照,不让别人知道,也不发出声音。。。发现了这个函数,可以直接获得摄像机的位置和旋转。
Controller-&GetPlayerViewPoint(CamLoc, CamRot);
最近看了几天PlayerCameraManager的代码,大致看明白了,本着分享的原则,在此分享一些经验。
PlayerCameraManager,顾名思义就是管理角色摄像仪与视角的,你可以通过继承的方式,编写自己的PlayerCameraManager,之后在你角色的控制类中指定即可。
下面说一下主要的运行过程:
这里可以参考一下ShooterGame(ShooterPlayerCameraManager),从函数UpdateCamera开始看
void AShooterPlayerCameraManager::UpdateCamera(float DeltaTime)
{  //尝试获取角色类指针,如果成功就执行一些第一人称视角相关的修正
AShooterCharacter* MyPawn = PCOwner ? Cast&AShooterCharacter&(PCOwner-&GetPawn()) : NULL;
if (MyPawn && MyPawn-&IsFirstPerson())
{    //Fov切换的相关逻辑,(右键的微瞄切换)
const float TargetFOV = MyPawn-&IsTargeting() ? TargetingFOV : NormalFOV;
DefaultFOV = FMath::FInterpTo(DefaultFOV, TargetFOV, DeltaTime, 20.0f);
  //执行父类函数
Super::UpdateCamera(DeltaTime);
  //对角色类的模型进行变换
if (MyPawn && MyPawn-&IsFirstPerson())
MyPawn-&OnCameraUpdate(GetCameraLocation(), GetCameraRotation());
  这里并没有视角的相关逻辑,所以进一步看父类的UpdateCamera函数。
void APlayerCameraManager::UpdateCamera(float DeltaTime)
if ((PCOwner-&Player && PCOwner-&IsLocalPlayerController()) || !bUseClientSideCameraUpdates || bDebugClientSideCamera)
DoUpdateCamera(DeltaTime);
if (GetNetMode() == NM_Client && bShouldSendClientSideCameraUpdate)
// compress the rotation down to 4 bytes
int32 const ShortYaw = FRotator::CompressAxisToShort(CameraCache.POV.Rotation.Yaw);
int32 const ShortPitch = FRotator::CompressAxisToShort(CameraCache.POV.Rotation.Pitch);
int32 const CompressedRotation = (ShortYaw && 16) | ShortP
PCOwner-&ServerUpdateCamera(CameraCache.POV.Location, CompressedRotation);
bShouldSendClientSideCameraUpdate = false;
  这里是一些网络的逻辑,继续看DoUpdateCamera函数
void APlayerCameraManager::DoUpdateCamera(float DeltaTime)
{  //一些后期效果融合
// update color scale interpolation
if (bEnableColorScaleInterp)
float BlendPct = FMath::Clamp((GetWorld()-&TimeSeconds - ColorScaleInterpStartTime) / ColorScaleInterpDuration, 0.f, 1.0f);
ColorScale = FMath::Lerp(OriginalColorScale, DesiredColorScale, BlendPct);
// if we've maxed
if (BlendPct == 1.0f)
// disable further interpolation
bEnableColorScaleInterp = false;
      //是否停止工作,不然就执行UpdateViewTarget
// Don't update outgoing viewtarget during an interpolation when bLockOutgoing is set.
if ((PendingViewTarget.Target == NULL) || !BlendParams.bLockOutgoing)
// Update current view target
ViewTarget.CheckViewTarget(PCOwner);
UpdateViewTarget(ViewTarget, DeltaTime);
  //下面都是一些视角更新的循环逻辑,看到最后你会发现他们一直都是用的引用,设置新的视角的逻辑并不在这
// our camera is now viewing there
FMinimalViewInfo NewPOV = ViewTarget.POV;
// if we have a pending view target, perform transition from one to another.
if (PendingViewTarget.Target != NULL)
BlendTimeToGo -= DeltaT
// Update pending view target
PendingViewTarget.CheckViewTarget(PCOwner);
UpdateViewTarget(PendingViewTarget, DeltaTime);
// blend....
if (BlendTimeToGo & 0)
float DurationPct = (BlendParams.BlendTime - BlendTimeToGo) / BlendParams.BlendT
float BlendPct = 0.f;
switch (BlendParams.BlendFunction)
case VTBlend_Linear:
BlendPct = FMath::Lerp(0.f, 1.f, DurationPct);
case VTBlend_Cubic:
BlendPct = FMath::CubicInterp(0.f, 0.f, 1.f, 0.f, DurationPct);
case VTBlend_EaseIn:
BlendPct = FMath::Lerp(0.f, 1.f, FMath::Pow(DurationPct, BlendParams.BlendExp));
case VTBlend_EaseOut:
BlendPct = FMath::Lerp(0.f, 1.f, FMath::Pow(DurationPct, 1.f / BlendParams.BlendExp));
case VTBlend_EaseInOut:
BlendPct = FMath::InterpEaseInOut(0.f, 1.f, DurationPct, BlendParams.BlendExp);
// Update pending view target blend
NewPOV = ViewTarget.POV;
NewPOV.BlendViewInfo(PendingViewTarget.POV, BlendPct);//@TODO: CAMERA: Make sure the sense is correct!
BlendViewTargets(ViewTarget, PendingViewTarget, BlendPct);
// we're done blending, set new view target
ViewTarget = PendingViewT
// clear pending view target
PendingViewTarget.Target = NULL;
BlendTimeToGo = 0;
// our camera is now viewing there
NewPOV = PendingViewTarget.POV;
// Cache results
FillCameraCache(NewPOV);
if (bEnableFading)
if (bAutoAnimateFade)
FadeTimeRemaining = FMath::Max(FadeTimeRemaining - DeltaTime, 0.0f);
if (FadeTime & 0.0f)
FadeAmount = FadeAlpha.X + ((1.f - FadeTimeRemaining / FadeTime) * (FadeAlpha.Y - FadeAlpha.X));
if ((bHoldFadeWhenFinished == false) && (FadeTimeRemaining &= 0.f))
StopCameraFade();
if (bFadeAudio)
ApplyAudioFade();
  接下来看UpdateViewTarget函数,计算视角的逻辑都在里面
void APlayerCameraManager::UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime)
// Don't update outgoing viewtarget during an interpolation
if ((PendingViewTarget.Target != NULL) && BlendParams.bLockOutgoing && OutVT.Equal(ViewTarget))
  //设置默认属性的摄像机
// store previous POV, in case we need it later
FMinimalViewInfo OrigPOV = OutVT.POV;
//@TODO: CAMERA: Should probably reset the view target POV fully here
OutVT.POV.FOV = DefaultFOV;
OutVT.POV.OrthoWidth = DefaultOrthoW
OutVT.POV.bConstrainAspectRatio = false;
OutVT.POV.bUseFieldOfViewForLOD = true;
OutVT.POV.ProjectionMode = bIsOrthographic ? ECameraProjectionMode::Orthographic : ECameraProjectionMode::P
OutVT.POV.PostProcessSettings.SetBaseValues();
OutVT.POV.PostProcessBlendWeight = 1.0f;
bool bDoNotApplyModifiers = false;
  //如果ViewTarget是个摄像机的话,就直接获取摄像机的视角
if (ACameraActor* CamActor = Cast&ACameraActor&(OutVT.Target))
// Viewing through a camera actor.
CamActor-&GetCameraComponent()-&GetCameraView(DeltaTime, OutVT.POV);
    //下面都是一些不同模式的摄像机的逻辑,你可以在游戏中按下~,输入Camera XXXX的方式切换这个摄像机    //默认的摄像机是Default
static const FName NAME_Fixed = FName(TEXT("Fixed"));
static const FName NAME_ThirdPerson = FName(TEXT("ThirdPerson"));
static const FName NAME_FreeCam = FName(TEXT("FreeCam"));
static const FName NAME_FreeCam_Default = FName(TEXT("FreeCam_Default"));
static const FName NAME_FirstPerson = FName(TEXT("FirstPerson"));
if (CameraStyle == NAME_Fixed)
// do not update, keep previous camera position by restoring
// saved POV, in case CalcCamera changes it but still returns false
OutVT.POV = OrigPOV;
// don't apply modifiers when using this debug camera mode
bDoNotApplyModifiers = true;
else if (CameraStyle == NAME_ThirdPerson || CameraStyle == NAME_FreeCam || CameraStyle == NAME_FreeCam_Default)
// Simple third person view implementation
FVector Loc = OutVT.Target-&GetActorLocation();
FRotator Rotator = OutVT.Target-&GetActorRotation();
if (OutVT.Target == PCOwner)
Loc = PCOwner-&GetFocalLocation();
// Take into account Mesh Translation so it takes into account the PostProcessing we do there.
// @fixme, can crash in certain BP cases where default mesh is null
APawn* TPawn = Cast&APawn&(OutVT.Target);
if ((TPawn != NULL) && (TPawn-&Mesh != NULL))
Loc += FQuatRotationMatrix(OutVT.Target-&GetActorQuat()).TransformVector(TPawn-&Mesh-&RelativeLocation - GetDefault&APawn&(TPawn-&GetClass())-&Mesh-&RelativeLocation);
//OutVT.Target.GetActorEyesViewPoint(Loc, Rot);
if( CameraStyle == NAME_FreeCam || CameraStyle == NAME_FreeCam_Default )
Rotator = PCOwner-&GetControlRotation();
FVector Pos = Loc + ViewTargetOffset + FRotationMatrix(Rotator).TransformVector(FreeCamOffset) - Rotator.Vector() * FreeCamD
FCollisionQueryParams BoxParams(NAME_FreeCam, false, this);
BoxParams.AddIgnoredActor(OutVT.Target);
FHitResult R
GetWorld()-&SweepSingleByChannel(Result, Loc, Pos, FQuat::Identity, ECC_Camera, FCollisionShape::MakeBox(FVector(12.f)), BoxParams);
OutVT.POV.Location = !Result.bBlockingHit ? Pos : Result.L
OutVT.POV.Rotation = R
// don't apply modifiers when using this debug camera mode
bDoNotApplyModifiers = true;
else if (CameraStyle == NAME_FirstPerson)
// Simple first person, view through viewtarget's 'eyes'
OutVT.Target-&GetActorEyesViewPoint(OutVT.POV.Location, OutVT.POV.Rotation);
// don't apply modifiers when using this debug camera mode
bDoNotApplyModifiers = true;
{       //默认摄像机会执行这个函数
UpdateViewTargetInternal(OutVT, DeltaTime);
  //这个应该是执行CameraShakes的逻辑
if (!bDoNotApplyModifiers || bAlwaysApplyModifiers)
// Apply camera modifiers at the end (view shakes for example)
ApplyCameraModifiers(DeltaTime, OutVT.POV);
  //头戴设备的视角逻辑
if (bFollowHmdOrientation)
if (GEngine-&HMDDevice.IsValid() && GEngine-&HMDDevice-&IsHeadTrackingAllowed())
GEngine-&HMDDevice-&UpdatePlayerCameraRotation(this, OutVT.POV);
// Synchronize the actor with the view target results
SetActorLocationAndRotation(OutVT.POV.Location, OutVT.POV.Rotation, false);
UpdateCameraLensEffects(OutVT);
  综上所述,你应该把摄像机逻辑写在这,如果想了解得更加清楚,可以继续从UpdateViewTargetInternal函数看下去,一直看到CalcCamera为止。
下面大致说一下编写思路:
在使用编辑器新建完自己的CameraManager后,在控制类中制定,例如:
PlayerCameraManagerClass&= ADemoCameraManager::StaticClass();
然后我贴一下自己写的代码,这里我实现了一个固定视角:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Camera/PlayerCameraManager.h"
#include "DemoCameraManager.generated.h"
class DEMO_API ADemoCameraManager : public APlayerCameraManager
GENERATED_BODY()
protected:
virtual void UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime) override;
//UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = TViewTarget)
//struct FMinimalViewInfo SceneFixedPOV;
// Fill out your copyright notice in the Description page of Project Settings.
#include "Demo.h"
#include "DemoCameraManager.h"
#include "DemoCharacter.h"
void ADemoCameraManager::UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime)
if (bFollowHmdOrientation)
//如果有VR设备就直接运行引擎原始函数
Super::UpdateViewTarget(OutVT, DeltaTime);
// Don't update outgoing viewtarget during an interpolation
if ((PendingViewTarget.Target != NULL) && BlendParams.bLockOutgoing && OutVT.Equal(ViewTarget))
bool bDoNotApplyModifiers = false;
if (ACameraActor* CamActor = Cast&ACameraActor&(OutVT.Target))
// Viewing through a camera actor.
CamActor-&GetCameraComponent()-&GetCameraView(DeltaTime, OutVT.POV);
if (CameraStyle == FName("SceneFixed"))
{       //这里我感觉可能用PendingViewTarget来传递摄像机坐标和旋转比较好,但是还没测试过
//自己定义一个场景固定视角
ADemoCharacter *Character = Cast&ADemoCharacter&(GetOwningPlayerController()-&GetPawn());
OutVT.POV.Location = Character-&ViewTargetL
OutVT.POV.Rotation = Character-&ViewTargetR
//DesiredView.FOV = FieldOfV
//DesiredView.AspectRatio = AspectR
// don't apply modifiers when using this debug camera mode
bDoNotApplyModifiers = true;
}else if (CameraStyle==FName("Default"))
//默认方式是直接取得摄像机的参数来设置FTViewTarget.pov,而摄像机被控制类、SpringArm控制。
UpdateViewTargetInternal(OutVT, DeltaTime);
Super::UpdateViewTarget(OutVT, DeltaTime);
if (!bDoNotApplyModifiers || bAlwaysApplyModifiers)
// Apply camera modifiers at the end (view shakes for example)
ApplyCameraModifiers(DeltaTime, OutVT.POV);
// Synchronize the actor with the view target results
SetActorLocationAndRotation(OutVT.POV.Location, OutVT.POV.Rotation, false);
UpdateCameraLensEffects(OutVT);
后面是固定视角VolumeActor的代码:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameFramework/Actor.h"
#include "Character/DemoCharacter.h"
#include "Character/DemoCameraManager.h"
#include "Character/DemoPlayerController.h"
#include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h"
#include "BaseSceneFixedViewVolume.generated.h"
class DEMO_API ABaseSceneFixedViewVolume : public AActor
GENERATED_BODY()
// Sets default values for this actor's properties
ABaseSceneFixedViewVolume();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
FRotator R
UPROPERTY(EditDefaultsOnly, Category = "SceneFixedView", meta = (AllowPrivateAccess = "true"))
UBoxComponent* T
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "SceneFixedView", meta = (AllowPrivateAccess = "true"))
UCameraComponent* C
UFUNCTION()
virtual void OnBeginOverlap(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweeoResult);
UFUNCTION()
virtual void OnEndOverlap(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "SceneFixedView")
bool bCalView=false;
UPROPERTY(EditDefaultsOnly,Category="SceneFixedView")
FVector VolumeSize = FVector(500, 500, 200);
ADemoCharacter* C
ADemoCameraManager* CameraM
FName OriginM
// Fill out your copyright notice in the Description page of Project Settings.
#include "Demo.h"
#include "BaseSceneFixedViewVolume.h"
// Sets default values
ABaseSceneFixedViewVolume::ABaseSceneFixedViewVolume()
// Set this actor to call Tick() every frame.
You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
Triggers = CreateDefaultSubobject&UBoxComponent&(TEXT("Triggers"));
Triggers-&SetBoxExtent(VolumeSize);
Triggers-&SetRelativeLocation(FVector(0,0,VolumeSize.Z/2));
RootComponent = T
Camera= CreateDefaultSubobject&UCameraComponent&(TEXT("Camera"));
Camera-&SetRelativeLocation(FVector(VolumeSize.X,VolumeSize.Y,VolumeSize.Z));
Camera-&AttachTo(RootComponent);
//FollowCamera = CreateDefaultSubobject&UCameraComponent&(TEXT("FollowCamera"));
//FollowCamera-&AttachTo(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
//FollowCamera-&bUsePawnControlRotation = // Camera does not rotate relative to arm
Triggers-&OnComponentBeginOverlap.AddDynamic(this, &ABaseSceneFixedViewVolume::OnBeginOverlap);
Triggers-&OnComponentEndOverlap.AddDynamic(this, &ABaseSceneFixedViewVolume::OnEndOverlap);
// Called when the game starts or when spawned
void ABaseSceneFixedViewVolume::BeginPlay()
Super::BeginPlay();
// Called every frame
void ABaseSceneFixedViewVolume::Tick( float DeltaTime )
Super::Tick( DeltaTime );
if (bCalView)
if (Character)
Character-&ViewTargetLocation = Camera-&K2_GetComponentLocation();
Character-&ViewTargetRotator = UKismetMathLibrary::FindLookAtRotation(Camera-&K2_GetComponentLocation(), Character-&GetActorLocation());
void ABaseSceneFixedViewVolume::OnBeginOverlap(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweeoResult)
Character = Cast&ADemoCharacter&(OtherActor);
if (Character)
bCalView = true;
ADemoPlayerController* Controller = Cast&ADemoPlayerController&(Character-&GetController());
if (Controller)
OriginMode=Controller-&PlayerCameraManager-&CameraS
Controller-&SetCameraMode(FName("SceneFixed"));
//因为我使用控制类来管理视角,为了解决一些视角问题,所以在进入时,必须重新设置视角,屏蔽鼠标修改视角
Controller-&SetControlRotation(FRotator(0.0f,90.0f,0.0f));
Controller-&SetIgnoreLookInput(true);
void ABaseSceneFixedViewVolume::OnEndOverlap(class AActor* OtherActor ,class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
if (OtherActor==Character)
bCalView = false;
ADemoPlayerController* Controller = Cast&ADemoPlayerController&(Character-&GetController());
if (Controller)
if (OriginMode!=FName(""))
Controller-&SetCameraMode(OriginMode);
Controller-&SetCameraMode(FName("Default"));
Controller-&SetIgnoreLookInput(false);
Character=
阅读(...) 评论()

我要回帖

更多关于 cameramanager 的文章

 

随机推荐