【Android App】实战项目之虚拟现实(VR)的全景相册(附源码和演示视频 可用于学习和大作业)

简介: 【Android App】实战项目之虚拟现实(VR)的全景相册(附源码和演示视频 可用于学习和大作业)

需要源码请点赞关注收藏后评论区留言私信~~~

不管是绘画还是摄影,都是把三维的物体投影到平面上,其实仍旧呈现二维的模拟画面。 随着科技的发展,传统的成像手段越来越凸显出局限性,缘由在于人们需要一种更逼真更接近现实的技术,从而更好地显示三维世界的环境信息,这便催生了增强现实AR和虚拟现实VR。 传统的摄影只能拍摄90度左右的风景,而新型的全景相机能够拍摄360度乃至720度(连同头顶和脚底在内)的场景,这种360/720度的相片即为全景照片。

一、需求描述

传统的照片只是某个视角观测到的平面截图,无法看到视角以外的场景。 现在有了VR技术,只要把全景相机拍摄的全景照片发到手机上,无论在哪里都能及时通过手机浏览全景照片,从而方便掌握最新的现场情况。 全景照片看似一张矩形图片,其实前后左右上下的景色全都囊括在内,但用户每次只能观看某个角度的截图。要想观看其它方向上的图画,就得想办法让全景照片转起来。

二、功能分析

全景照片之于观察者,便是将全景图贴在球体内侧,由此可见,二者的不同之处在于人是在球外还是球内

浏览全景照片用到的技术

(1)通过手势的触摸与滑动,把全景照片相应地挪动观测角度。

(2)利用OpenGL ES 库,把平面的全景照片转换为曲面的实景快照。

(3)根据手势滑动在水平方向和垂直方向分别产生的角度变化,实时调整全景图的快照范围。

下面介绍主要代码模块之间的关系

(1)PanoramaActivity.java:这是全景相册的浏览器页面。

(2)PanoramaView.java:这是自定义全景视图的实现代码。

(3)PanoramaRender.java:这是全景图形的三维渲染器代码。

(4)PanoramaUtil.java:这是全景图片的顶点坐标工具类,用于计算全景图片的顶点列表,以及全景图片的纹理列表。

具体到编码过程,主要有以下三项处理

1:实现全景照片的渲染器

2:计算手势触摸引发的角度变更

3:在活动页面加载全景照片的渲染器

三、效果展示

演示视频如下 可以在下拉框中选择不同的相册进行展示,可以放缩或旋转 真正实现了身临其境的感觉

虚拟现实的全景相册

效果图如下

四、代码

部分代码如下 全部源码请点赞关注收藏后评论区留言~

package com.example.threed;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import androidx.appcompat.app.AppCompatActivity;
import com.example.threed.panorama.PanoramaView;
public class PanoramaActivity extends AppCompatActivity {
    private final static String TAG = "PanoramaActivity";
    private PanoramaView pv_content; // 声明一个全景视图对象
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_panorama);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 保持屏幕常亮
        pv_content = findViewById(R.id.pv_content);
        pv_content.initRender(resArray[0]); // 设置全景视图的全景图片
        initExampleSpinner(); // 初始化样例下拉框
    }
    // 初始化样例下拉框
    private void initExampleSpinner() {
        ArrayAdapter<String> exampleAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, exampleArray);
        Spinner sp_example = findViewById(R.id.sp_example);
        sp_example.setPrompt("请选择全景照片例子");
        sp_example.setAdapter(exampleAdapter);
        sp_example.setOnItemSelectedListener(new ExampleSelectedListener());
        sp_example.setSelection(0);
    }
    private String[] exampleArray = {"现代客厅", "中式客厅", "故宫风光", "城市街景",
            "鸟瞰城市", "俯拍高校", "私人会所", "酒店大堂"};
    private int[] resArray = {R.drawable.panorama01, R.drawable.panorama02, R.drawable.panorama03, R.drawable.panorama04,
            R.drawable.panorama05, R.drawable.panorama06, R.drawable.panorama07, R.drawable.panorama08};
    class ExampleSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, final int arg2, long arg3) {
            pv_content.setDrawableId(resArray[arg2]); // 传入全景图片的资源编号
        }
        public void onNothingSelected(AdapterView<?> arg0) {}
    }
}

util类

package com.example.threed.util;
import java.util.ArrayList;
import java.util.List;
public class PanoramaUtil {
    // 获取全景图片的顶点列表
    public static List<Float> getPanoramaVertexList(int perVertex, double perRadius) {
        List<Float> vertexList = new ArrayList<>();
        for (int i = 0; i < perVertex; i++) {
            for (int j = 0; j < perVertex; j++) {
                float x1 = (float) (Math.sin(i * perRadius / 2) * Math.cos(j * perRadius));
                float z1 = (float) (Math.sin(i * perRadius / 2) * Math.sin(j * perRadius));
                float y1 = (float) Math.cos(i * perRadius / 2);
                float x2 = (float) (Math.sin((i + 1) * perRadius / 2) * Math.cos(j * perRadius));
                float z2 = (float) (Math.sin((i + 1) * perRadius / 2) * Math.sin(j * perRadius));
                float y2 = (float) Math.cos((i + 1) * perRadius / 2);
                float x3 = (float) (Math.sin((i + 1) * perRadius / 2) * Math.cos((j + 1) * perRadius));
                float z3 = (float) (Math.sin((i + 1) * perRadius / 2) * Math.sin((j + 1) * perRadius));
                float y3 = (float) Math.cos((i + 1) * perRadius / 2);
                float x4 = (float) (Math.sin(i * perRadius / 2) * Math.cos((j + 1) * perRadius));
                float z4 = (float) (Math.sin(i * perRadius / 2) * Math.sin((j + 1) * perRadius));
                float y4 = (float) Math.cos(i * perRadius / 2);
                vertexList.add(x1);
                vertexList.add(y1);
                vertexList.add(z1);
                vertexList.add(x2);
                vertexList.add(y2);
                vertexList.add(z2);
                vertexList.add(x3);
                vertexList.add(y3);
                vertexList.add(z3);
                vertexList.add(x3);
                vertexList.add(y3);
                vertexList.add(z3);
                vertexList.add(x4);
                vertexList.add(y4);
                vertexList.add(z4);
                vertexList.add(x1);
                vertexList.add(y1);
                vertexList.add(z1);
            }
        }
        return vertexList;
    }
    // 获取全景图片的纹理列表
    public static List<Float> getPanoramaTextureList(int perVertex) {
        List<Float> textureList = new ArrayList<>();
        double perW = 1 / (float) perVertex;
        double perH = 1 / (float) (perVertex);
        for (int i = 0; i < perVertex; i++) {
            for (int j = 0; j < perVertex; j++) {
                float w1 = (float) (i * perH);
                float h1 = (float) (j * perW);
                float w2 = (float) ((i + 1) * perH);
                float h2 = (float) (j * perW);
                float w3 = (float) ((i + 1) * perH);
                float h3 = (float) ((j + 1) * perW);
                float w4 = (float) (i * perH);
                float h4 = (float) ((j + 1) * perW);
                textureList.add(h1);
                textureList.add(w1);
                textureList.add(h2);
                textureList.add(w2);
                textureList.add(h3);
                textureList.add(w3);
                textureList.add(h3);
                textureList.add(w3);
                textureList.add(h4);
                textureList.add(w4);
                textureList.add(h1);
                textureList.add(w1);
            }
        }
        return textureList;
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="right"
            android:text="全景照片例子:"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <Spinner
            android:id="@+id/sp_example"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:spinnerMode="dialog" />
    </LinearLayout>
    <com.example.threed.panorama.PanoramaView
        android:id="@+id/pv_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~

相关文章
|
3月前
|
Java
照片一键生成眨眼视频app,手机照片一键生成眨眼动图,通过JAR代码实现效果
这是一个自动生成眨眼GIF动画的Java程序,包含主程序处理、图像变形和GIF生成三个模块。输入照片路径,自动识别人脸眼睛位置,生成闭眼、半闭眼等多帧图像,并合成为眨眼动效GIF文件。
|
4月前
|
Android开发 数据安全/隐私保护 开发者
Android自定义view之模仿登录界面文本输入框(华为云APP)
本文介绍了一款自定义输入框的实现,包含静态效果、hint值浮动动画及功能扩展。通过组合多个控件完成界面布局,使用TranslateAnimation与AlphaAnimation实现hint文字上下浮动效果,支持密码加密解密显示、去除键盘回车空格输入、光标定位等功能。代码基于Android平台,提供完整源码与attrs配置,方便复用与定制。希望对开发者有所帮助。
|
7月前
|
JavaScript 前端开发 Android开发
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
208 13
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
8月前
|
编解码 安全 Android开发
如何修复 Android 和 Windows 不支持视频编解码器的问题?
视频播放时遇到“编解码器不支持”错误(如0xc00d36c4或0xc00d5212)是常见问题,即使文件格式为MP4或MKV。编解码器是编码和解码数据的工具,不同设备和版本支持不同的编解码器。解决方法包括:1) 安装所需编解码器,如K-Lite Codec Pack;2) 使用自带编解码器的第三方播放器,如VLC、KMPlayer等。这些方法能帮助你顺利播放视频。
|
6月前
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
1224 77
|
4月前
|
Android开发 开发者
Android企业级实战-界面篇-3
本文是《Android企业级实战-界面篇》系列的第三篇,主要介绍分割线和条形跳转框的实现方法,二者常用于设置和个人中心界面。文章通过具体代码示例展示了如何实现这两种UI组件,并提供了效果图。实现前需准备`dimens.xml`、`ids.xml`、`colors.xml`等文件,部分资源可参考系列第一、二篇文章。代码中详细说明了布局文件的配置,如分割线的样式定义和条形跳转框的组件组合,帮助开发者快速上手并应用于实际项目中。
|
4月前
|
XML Android开发 数据格式
Android企业级实战-界面篇-2
本文为《Android企业级实战-界面篇》系列第二篇,主要介绍三个UI模块的实现:用户资料模块、关注与粉丝统计模块以及喜欢和收藏功能模块。通过详细的XML代码展示布局设计,包括dimens、ids、colors配置文件的使用,帮助开发者快速构建美观且功能齐全的界面。文章结合实际效果图,便于理解和应用。建议配合第一篇文章内容学习,以获取完整工具类支持。
|
4月前
|
算法 Java Android开发
Android企业级实战-界面篇-1
本文详细介绍了Android企业级开发中界面实现的过程,涵盖效果展示、实现前准备及代码实现。作者通过自身经历分享了Android开发经验,并提供了`dimens.xml`、`ids.xml`、`colors.xml`和`strings.xml`等配置文件内容,帮助开发者快速构建规范化的UI布局。文章以一个具体的用户消息界面为例,展示了如何使用线性布局(LinearLayout)和相对布局(RelativeLayout)实现功能模块排列,并附带注意事项及使用方法,适合初学者和进阶开发者参考学习。
|
6月前
|
小程序
【04】微信支付商户申请下户到配置完整流程-微信开放平台移动APP应用通过-微信商户继续申请-微信开户函-视频声明-以及对公打款验证-申请+配置完整流程-优雅草卓伊凡
【04】微信支付商户申请下户到配置完整流程-微信开放平台移动APP应用通过-微信商户继续申请-微信开户函-视频声明-以及对公打款验证-申请+配置完整流程-优雅草卓伊凡
428 1
【04】微信支付商户申请下户到配置完整流程-微信开放平台移动APP应用通过-微信商户继续申请-微信开户函-视频声明-以及对公打款验证-申请+配置完整流程-优雅草卓伊凡
|
7月前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
214 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡

热门文章

最新文章