unity 启动相机_Unity3D研究院之打开照相机与本地相册进行裁剪显示(三十三)...-程序员宅基地

技术标签: unity 启动相机  

最近做项目需要用到这个功能,就是在Unity中调用Android本地相册或直接打开摄像机拍照并且裁剪一部分用于用户头像,今天研究了一下,那么研究出成果了MOMO一定要分享给大家。Unity与Android的交互还有谁不会?? 如果有不会的朋友请看MOMO之前的文章喔,Unity3D研究院之打开Activity与调用JAVA代码传递参数(十八)这里有关交互的方式就不详细说明,主要将如何在Unity中打开摄像机、在Unity中打开本地相册,选一个照片后如何进行裁剪,最后将图片转换成Texture显示在U3D的世界当中。

首先看看Eclipse中的Android插件部分,我的包名是com.xys请大家与MOMO保持一致,Unity工程中也需要是这个包名噢。

UnityTestActivity.java 这个类是Unity的插件主类,在这里调用是打开摄像机 还是本地相册的方法。

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

packagecom.xys;

importandroid.content.Context;

importandroid.content.Intent;

importandroid.os.Bundle;

importcom.unity3d.player.UnityPlayerActivity;

publicclassUnityTestActivityextendsUnityPlayerActivity{

//public class UnityTestActivity extends Activity {

ContextmContext=null;

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

mContext=this;

}

//Unity中会调用这个方法,用于区分打开摄像机 开始本地相册

publicvoidTakePhoto(Stringstr)

{

Intentintent=newIntent(mContext,WebViewActivity.class);

intent.putExtra("type",str);

this.startActivity(intent);

}

}

然后是WebViewActivity.java 这里主要处理用户打开摄像机或本地相册后如何进行裁剪图片,并且把裁剪的图片储存在本地文件中。

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

packagecom.xys;

importjava.io.File;

importjava.io.FileNotFoundException;

importjava.io.FileOutputStream;

importjava.io.IOException;

importcom.unity3d.player.UnityPlayer;

importandroid.app.Activity;

importandroid.content.Intent;

importandroid.graphics.Bitmap;

importandroid.net.Uri;

importandroid.os.Bundle;

importandroid.os.Environment;

importandroid.provider.MediaStore;

importandroid.view.KeyEvent;

importandroid.widget.ImageView;

publicclassWebViewActivityextendsActivity

{

ImageViewimageView=null;

publicstaticfinalintNONE=0;

publicstaticfinalintPHOTOHRAPH=1;// 拍照

publicstaticfinalintPHOTOZOOM=2;// 缩放

publicstaticfinalintPHOTORESOULT=3;// 结果

publicstaticfinalStringIMAGE_UNSPECIFIED="image/*";

publicfinalstaticStringFILE_NAME="image.png";

publicfinalstaticStringDATA_URL="/data/data/";

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

imageView=(ImageView)this.findViewById(R.id.imageID);

Stringtype=this.getIntent().getStringExtra("type");

//在这里判断是打开本地相册还是直接照相

if(type.equals("takePhoto"))

{

Intentintent=newIntent(MediaStore.ACTION_IMAGE_CAPTURE);

intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(newFile(Environment.getExternalStorageDirectory(),"temp.jpg")));

startActivityForResult(intent,PHOTOHRAPH);

}else

{

Intentintent=newIntent(Intent.ACTION_PICK,null);

intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,IMAGE_UNSPECIFIED);

startActivityForResult(intent,PHOTOZOOM);

}

}

@Override

protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){

if(resultCode==NONE)

return;

// 拍照

if(requestCode==PHOTOHRAPH){

//设置文件保存路径这里放在跟目录下

Filepicture=newFile(Environment.getExternalStorageDirectory()+"/temp.jpg");

startPhotoZoom(Uri.fromFile(picture));

}

if(data==null)

return;

// 读取相册缩放图片

if(requestCode==PHOTOZOOM){

startPhotoZoom(data.getData());

}

// 处理结果

if(requestCode==PHOTORESOULT){

Bundleextras=data.getExtras();

if(extras!=null){

Bitmapphoto=extras.getParcelable("data");

imageView.setImageBitmap(photo);

try{

SaveBitmap(photo);

}catch(IOExceptione){

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

super.onActivityResult(requestCode,resultCode,data);

}

publicvoidstartPhotoZoom(Uriuri){

Intentintent=newIntent("com.android.camera.action.CROP");

intent.setDataAndType(uri,IMAGE_UNSPECIFIED);

intent.putExtra("crop","true");

// aspectX aspectY 是宽高的比例

intent.putExtra("aspectX",1);

intent.putExtra("aspectY",1);

// outputX outputY 是裁剪图片宽高

intent.putExtra("outputX",300);

intent.putExtra("outputY",300);

intent.putExtra("return-data",true);

startActivityForResult(intent,PHOTORESOULT);

}

publicvoidSaveBitmap(Bitmapbitmap)throwsIOException{

FileOutputStreamfOut=null;

//注解1

Stringpath="/mnt/sdcard/Android/data/com.xys/files";

try{

//查看这个路径是否存在,

//如果并没有这个路径,

//创建这个路径

FiledestDir=newFile(path);

if(!destDir.exists())

{

destDir.mkdirs();

}

fOut=newFileOutputStream(path+"/"+FILE_NAME);

}catch(FileNotFoundExceptione){

e.printStackTrace();

}

//将Bitmap对象写入本地路径中,Unity在去相同的路径来读取这个文件

bitmap.compress(Bitmap.CompressFormat.PNG,100,fOut);

try{

fOut.flush();

}catch(IOExceptione){

e.printStackTrace();

}

try{

fOut.close();

}catch(IOExceptione){

e.printStackTrace();

}

}

@Override

publicbooleanonKeyDown(intkeyCode,KeyEventevent)

{

if(keyCode==KeyEvent.KEYCODE_BACK&&event.getRepeatCount()==0)

{

//当用户点击返回键是 通知Unity开始在"/mnt/sdcard/Android/data/com.xys/files";路径中读取图片资源,并且现在在Unity中

UnityPlayer.UnitySendMessage("Main Camera","message",FILE_NAME);

}

returnsuper.onKeyDown(keyCode,event);

}

}

注解1:主要是路径”/mnt/sdcard/Android/data/com.xys/files”,如下图所示,我们在这里把文件保存在这个路径下。为什么要把图片2进制文件写在这里呢? 还记得以前MOMO给大家说过在Unity中访问Android或IOS本地2进制文件时用到的这个路径,

Application.persistentDataPath   该路径等价于 /mnt/sdcard/Android/data/com.xys/files ,当然后者的包名是对应的工程包名,这样在Unity中可以找到对应裁剪后的图片文件,并且显示在Unity中。

AndroidManifest.xml  这个文件也没什么好说的,大家看看吧。

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

package="com.xys"

android:versionCode="1"

android:versionName="1.0">

android:icon="@drawable/ic_launcher"

android:label="@string/app_name">

android:name=".UnityTestActivity"

android:label="@string/app_name">

android:name=".WebViewActivity">

然后把上面的Android工程打包做成插件放在Unity中。如下图所示,这个我的Unity工程中对应的路径。如果看不懂的朋友请看我之前的文章哈。

然后看Test.cs脚本,它直接挂在摄像机身上。

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

usingUnityEngine;

usingSystem.Collections;

usingSystem.IO;

publicclassTest:MonoBehaviour

{

publicGUISkinskin;

Texturetexture;

voidUpdate()

{

if(Input.GetKeyDown(KeyCode.Escape)||Input.GetKeyDown(KeyCode.Home))

{

Application.Quit();

}

}

voidOnGUI()

{

GUI.skin=skin;

if(GUILayout.Button("打开手机相册"))

{

//调用我们制作的Android插件打开手机相册

AndroidJavaClassjc=newAndroidJavaClass("com.unity3d.player.UnityPlayer");

AndroidJavaObjectjo=jc.GetStatic("currentActivity");

jo.Call("TakePhoto","takeSave");

}

if(GUILayout.Button("打开手机摄像机"))

{

//调用我们制作的Android插件打开手机摄像机

AndroidJavaClassjc=newAndroidJavaClass("com.unity3d.player.UnityPlayer");

AndroidJavaObjectjo=jc.GetStatic("currentActivity");

jo.Call("TakePhoto","takePhoto");

}

if(texture!=null)

{

//注意! 我们在这里绘制Texture对象,该对象是通过

//我们制作的Android插件得到的,当这个对象不等于空的时候

//直接绘制。

GUI.DrawTexture(newRect(100,300,300,300),texture);

}

}

voidmessgae(stringstr)

{

//在Android插件中通知Unity开始去指定路径中找图片资源

StartCoroutine(LoadTexture(str));

}

IEnumeratorLoadTexture(stringname)

{

//注解1

stringpath="file://"+Application.persistentDataPath+"/"+name;

WWWwww=newWWW(path);

while(!www.isDone)

{

}

yieldreturnwww;

//为贴图赋值

texture=www.texture;

}

}

注解1:请大家一定要注意这个路径的写法, 前面一定要加 “File://” 不然无法读取。OK说了这么多我们看看这个项目运行的效果,激动人心的时刻来临啦 嚯嚯嚯嚯!!!

1.首次进入的画面, 这里的图片是我刚刚从相册选择的

2.打开相册我们选择一张图片

3. 选择一张图片,我们进行裁剪

最后我们返回到Unity中界面。新的图片Unity已经完成读取,界面上已经修改成刚刚我裁剪的啦,哇咔咔。 怎么样,还不错啦? 哈哈后。这个做用户头像肯定给力 蛤蛤。

如果点击打开摄像机按钮,拍照完毕后会提示裁剪,裁减完毕返回到Unity界面中同样能看到效果。

最后MOMO将本篇博文的源码放出来,  源码包括Android的工程 与Unity的工程,雨松MOMO祝大家学习愉快,大家互相学习互相进步,加油哇咔咔,啦啦啦。

最后编辑:2015-07-03作者:雨松MOMO

专注移动互联网,Unity3D游戏开发

捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39548541/article/details/112023468

智能推荐

python实现批量替换目录下多个后缀为docx文档内容_python中paragraph.text.replace()-程序员宅基地

文章浏览阅读474次,点赞10次,收藏12次。然后,我们使用python-docx库中的Document类打开每个Word文档,并遍历其中的段落和表格内容,将文本中的“old_text”替换为“new_text”。为了解决这个问题,我们可以使用Python编写一个程序来实现批量替换目录下多个后缀为docx文档内容的功能。通过使用Python的os和glob模块,我们可以轻松地遍历目录下的所有文件,并对每个文件进行操作。接下来,我们可以编写Python程序来实现批量替换目录下多个后缀为docx文档内容的功能。批量替换目录下多个后缀为docx文档内容。_python中paragraph.text.replace()

ProgressDlgUtil.class(ProgressDialog使用的工具类)_android progressdialog转菊花工具类-程序员宅基地

文章浏览阅读165次。import android.app.ProgressDialog;import android.content.Context;public class ProgressDlgUtil {private static ProgressDialog progressDlg = null;/** * 启动进度条 * @param ctx 当前的activity * @param con..._android progressdialog转菊花工具类

股票加杠杆有什么要求?资金、策略与心态的三重考验-程序员宅基地

文章浏览阅读262次。投资者在决定加杠杆之前,应该充分了解自己的资金实力和风险承受能力,制定详细的投资策略和风险控制机制,并保持冷静和理性的心态。同时,投资者还应该不断学习和积累经验,提高自己的投资水平和应对风险的能力,以应对市场的不断变化和挑战。因此,投资者在决定加杠杆之前,应该对自己的资金状况进行充分的评估,确保自己有足够的资金实力和风险承受能力。其次,策略是股票加杠杆的关键。在股票市场中,加杠杆是一种常见的投资策略,它允许投资者通过借入资金来扩大自己的交易规模,以期获得更高的收益。文章来源:配查信-杠杠炒股平台实盘查询。

中国元宵节的习俗至少有12种,你知道多少?_秧歌队拜帖-程序员宅基地

文章浏览阅读849次。十五元宵闹人圆古人云:“千门开锁万灯明,正月中旬动地京”。众所周知,正月十五是元宵节,又称上元节、元夜、春灯节等,是中国民间传统节日。元宵节俗的形成有一个较长的过程,汉武帝正月上辛夜在甘泉宫祭祀“太一”的活动,被后人视作正月十五祭祀天神的先声。不过,正月十五真正作为民俗节日是在汉魏之后。东汉佛教文化的传入,对于形成元宵节俗有着重要的推动意义。关于元宵节的来..._秧歌队拜帖

优秀课件笔记之设备管理-程序员宅基地

文章浏览阅读99次。1、本文所以内容来自 著名高校课件和学生笔记(校园里面经常见到有人高价买笔记)2、任课教师不会提供参考文献,所以只能对作者表示感谢,如果引用了您的作品,可以用回复方式补充参考文献。3、我不对文章无关问题进行解答,文章内容也比较难,我也很难解答您遇到的问题,如果发现BUG可以用回复方式帮我修正。4、本课 计算机操作系统,适用于计算机操作系统课、考研本课其他部分的导航条见页面底部设备管理是操作..._get_buf(type,number)beginp(rs(type));p(s(type));pointer of buffer(number

2020电子设计竞赛G题 - 非接触物体尺寸形态测量_2020ti杯电赛g非接触物体尺寸形态测量接口如何连接-程序员宅基地

文章浏览阅读4.3k次,点赞14次,收藏116次。思路​ 题目上有三种颜色三种形状的物体, 可以先判断物体的颜色二值化后判断物体形状, 这样可以有效降低误差, 但是后来测试的时候经常会发现有误判的现象, 想到可能是因为背景嘈杂并且二值化后的图像信息会有损耗, 我开始思考为什么人类识别这些物体的成功率如此之高, 自我认为是因为我们会聚焦到一个物体并且不断找出这个物体的特征然后根据经验判断出物体是什么, 因此我设计了一个几率模型,或者说是一种擂台法则, 把在一段时间内检测到的数据进行整合得到一个几率表, 根据擂台法则得出物体的准确信息_2020ti杯电赛g非接触物体尺寸形态测量接口如何连接

随便推点

WCF在https类型的网站中,web.config文件的配置方法。_web.config 配置wcf-程序员宅基地

文章浏览阅读8.6k次。关键是加粗的两行。 contract="IBOAutoApprovalWCF">_web.config 配置wcf

负载测试和压力测试有何区别?资深测试老鸟总结,一篇搞定..._负载测试和压力测试的区别-程序员宅基地

文章浏览阅读4.4k次,点赞6次,收藏40次。负载与压力测试1、负载测试:是通过逐步增加系统负载,测试系统性能的变化,并最终确定在满足性能指标的情况下,系统所能承受的最大负载量的测试;2、压力测试:是通过逐步增加系统负载,测试系统性能的变化,并最终确定在什么负载条件下系统性能处于失效状态,并以此来获得系统能提供的最大服务级别的测试。例子分析1:登录接口,我们先10个用户访问,然后100个用户访问,然后1000个用户访问,关注程序的响应时间,所耗资源,直到超时或关键资源耗尽。压力测试:是指程序长时间运行的稳定性。_负载测试和压力测试的区别

使用Xcode HeaderDoc和Doxygen文档化你的Objective-C和Swift代码_ios swift doxygen-程序员宅基地

文章浏览阅读1.1k次。本文由CocoaChina译者YueWang翻译自AppCoda原文:Documenting Your Objective-C and Swift Code in Xcode with HeaderDoc and Doxygen在一个应用的整个开发过程中涉及到了无数的步骤。其中一些是应用的说明,图片的创作,应用的实现,和实现过后的测试阶段。写代码可能组成了这个过程的绝大部分_ios swift doxygen

学习vue源码(10)学习render渲染函数,学web前端开发需要什么基础-程序员宅基地

文章浏览阅读708次,点赞12次,收藏15次。每个模板经过 compile 都会生成一个 render 函数render 作为 渲染三部曲的第二部,主要作用就是 执行 render,生成 Vnode把 template 上绑定的数据,都保存到 vnode 中然后,生成 Vnode,就是为了给 渲染三部曲的 第三部 Diff 提供源动力从而完成 DOM 挂载到这里其实基本就已经结束了render的思路,但是源码中有个静态render,这个 对渲染性能的提高有极大的帮助,所以必须看下。没错,就是 静态 render,看过。

R语言——summarise和mutate函数_r语言 summarise()输出的结果是什么格式-程序员宅基地

文章浏览阅读2w次,点赞12次,收藏52次。summarise()和mutate()是plyr包中的两个函数。summarise()函数用法:summarise(.data, ...)参数:.data the data frame to be summarised... further arguments of the form var = valuemutate()函数用法:mutate..._r语言 summarise()输出的结果是什么格式

java后端session和cookie_java 后端跟session-程序员宅基地

文章浏览阅读1.1k次。前言:http是一种无状态的协议,无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即我们给服务器发送 HTTP 请求之后,服务器根据请求,会给我们发送数据过来,但是,发送完,不会记录任何信息。cookie:由于http无状态这个特点,导致了一些麻烦,比如:你登录csdn(当然是比如),每次都要重新输入用户名和密码,这样就很不方便,你刷新一下页面,又叫你登录。针对这个问..._java 后端跟session