插件市场或者github上大多是threejs或者web-view方式.

但是threejs太大了,web-view不符要求,需要嵌入页面中,只能canvas+webgl实现.

找到一个库 GitHub - alibaba/G3D: A pure 3D render engine compatible with webgl, running both in browser and gcanvas. 虽然早就不更新了,但是用到微信小程序的webgl1.0还是可以的.

他的源码中就有skybox的示例,整个库打包后 101k

下面是components/bui-vr-preview 目录下的文件

bui-vr-preview.vue

g3d.min.js   //下载源码自己打包吧

Image360.js

<template>
	<view class="bui-vr-preview" style="background-color: aliceblue;">
		<canvas type="webgl" :id="id" :canvas-id="id" :style="{width: width, height:height}" 
		 :disable-scroll="true"
		  @touchmove.prevent.stop="touchmove"
		  @touchstart.prevent.stop="touchstart"
		  @touchend.prevent.stop="touchend"
		@error="canvasIdErrorCallback"></canvas>
	</view>
</template>

<script>
	// fbudlr  
	 import Image360 from "./Image360.js";
	 
	 let images = [
		 "https://yourhost****/dist/00/manager/buick/pano_f.jpeg?imageMogr2/auto-orient/strip/rotate/180/thumbnail/!1024x1024r/quality/70/interlace/1/gravity/center", 
		 "https://yourhost****/dist/00/manager/buick/pano_b.jpeg?imageMogr2/auto-orient/strip/rotate/180/thumbnail/!1024x1024r/quality/70/interlace/1/gravity/center", 
		 "https://yourhost****/dist/00/manager/buick/pano_u.jpeg?imageMogr2/auto-orient/strip/rotate/180/thumbnail/!1024x1024r/quality/70/interlace/1/gravity/center",
		 "https://yourhost****/dist/00/manager/buick/pano_d.jpeg?imageMogr2/auto-orient/strip/rotate/360/thumbnail/!1024x1024r/quality/70/interlace/1/gravity/center",
		  "https://yourhost****/dist/00/manager/buick/pano_l.jpeg?imageMogr2/auto-orient/strip/rotate/180/thumbnail/!1024x1024r/quality/70/interlace/1/gravity/center",
		"https://yourhost****/dist/00/manager/buick/pano_r.jpeg?imageMogr2/auto-orient/strip/rotate/180/thumbnail/!1024x1024r/quality/70/interlace/1/gravity/center", 
	 ]
	 
	export default {
		name: "bui-vr-preview",
		props: {
			/* canvas id, 同一页面多次引用,不可重名 */
			id:{
					type:String,
					default: "canvas_" + Math.round(Math.random()*9999)
			},
			/**
			 * 高度 默认450rpx
			 */
			height: {
				type: String,
				default: "450rpx"
			},
			/**
			 * 宽度 默认 100%
			 */
			width: {
				type: String,
				default: "100%"
			}
		},
		data() {
			return {
				  imagebox:null,
				  inited: false,
			};
		},
		onLoad() { 
			this.init()
		},
		methods: {
			canvasIdErrorCallback: function (e) {
						console.error("canvas 操作异常",e.detail.errMsg ,e)
					},
			init() {
				let self = this;
				let selector= this.$$('#'+this.id)
 
				selector.node()
					.exec((res) => {
						const canvas = res[0].node
						 console.log(res)
						 this.imagebox = new Image360(canvas,images,{
							 textureComplete:()=>{
								 self.inited = true;
							 }
						 }); 
					})
			},
			touchmove(e) {
				let self = this;
				 
				if(!self.inited)return;
				this.imagebox.touchmove(e) 
			},
			touchstart(e){
				let self = this;
				 
				  this.imagebox.touchstart(e) 
				 
				
			},
			touchend(e){
				let self = this;
				if(!self.inited)return;
				this.imagebox.touchend(e) 
			},



		}
	}
</script>

<style lang="scss" scoped>

</style>
let {
	Engine,
	Scene,
	RotatePerspectiveCamera,
	Skybox,
	Geometry
} = require("./g3d.min.js") 

let lx = null,
	ly = null;
/**
 *  
 * 由于 threejs 太大了...
 * 先天不足: 由于 wxs不能操作, 微信小程序默认采用前后端分离,消息模式,所以性能和效率上都有损耗,可能不会太流畅
 * 注意: 微信小程序不支持2048图片  见 https://github.com/deepkolos/three-platformize
 * 
	注意 skybox 从立方体内部看纹理,是反的, 目前是用cdn把图片转了180度解决.  后面如果遇到不支持cdn的,要考虑用canvas进行镜像转换
	貌似可以直接用webgl 把贴图直接镜像..... 没成功
  
	@mail 35802713@qq.com 
 */
class Image360 {

	/**
	 * @param {Object} selector
	 * @param {Object} canvas
	 * @param {Object} images
	 * @param {Object} opt
	 */
	constructor(canvas, images, opt) {
		this.canvas = canvas;
		// this.gl = canvas.getContext('webgl');
		this.images = images;
		this.opt = opt || {
			//贴图全部加载完成的回调事件
			textureComplete: (image360) => {}
		}
		this.init();
	}

	/** 
	 * 初始化 
	 */
	init() {
		let self = this;
		this.engine = new Engine(self.canvas);

		this.scene = new Scene(this.engine);

		this.camera = new RotatePerspectiveCamera(this.scene);
		 //横向角度
		this.camera.alpha = 0;
		//纵向角度
		this.camera.beta = 0;
		this.camera.radius =10;// 不用改,大了看起来像镜中地球
		this.camera.near = 0.001;
		this.camera.far = 2000;
// console.log(this.camera,this.scene)
		let cnt = 0; 
		// fbudlr 
		let imageListPOsi = [ "back","front", "top","bottom", "left", "right"];

		let pos = {}
		for (let i = 0; i < this.images.length; i++) {
			let image = this.canvas.createImage(); //和h5区别 小程序这里没有 new Image
			pos[imageListPOsi[i]] = image;
			image.onload = () => {
				cnt++;
				if (cnt >= 6) { //pano形式最多6张,也就是正方体的6个面 
					let skybox = new Skybox(self.scene, pos,100,true);
					console.log(skybox)
					function render() {
						self.scene.render();
						self.requestAnimationFrame(render);
					}

					render();

					//贴图全部加载完成后的回调,外部调用
					self.opt.textureComplete && self.opt.textureComplete(self);
				}
			}
			image.src = this.images[i];
		}


	}




	touchmove(e) {
		let self = this;
		//console.log(e)
		let x = e.touches[0].clientX;
		let y = e.touches[0].clientY;

		self.camera.alpha += (x - lx) / 5;
		this.camera.beta = self.clamp(-90, 90, this.camera.beta - (y - ly) / 5); 
		lx = x;
		ly = y;
	}

	touchstart(e) {
		let self = this;
		//console.log(e)
		let x = e.touches[0].clientX;
		let y = e.touches[0].clientY;
		lx = x;
		ly = y;
	}

	touchend(e) {

	}

	/**
	 * 重绘界面 就认为是动画呈现吧
	 * 见 https://developers.weixin.qq.com/miniprogram/dev/api/canvas/Canvas.requestAnimationFrame.html
	 */
	requestAnimationFrame(cb) {
		this.canvas.requestAnimationFrame(cb);
	}

	clamp(min, max, v) {
		return v < min ? min : v > max ? max : v;
	}
}


export default Image360

外部调用方式:

 <bui-vr-preview></bui-vr-preview>

只是第一版,没有增加外部传入图片的prop.

非H5嵌入.

遇到的问题: 

由于在立方体内部向外看, 纹理贴图就是反的,现在是用七牛的翻转图片的方式达到正向的效果.

希望有熟悉webgl的达人弄出完美的 

 网上还看到有用css3弄出来的cubemap的例子....

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐