在上一章节中,我们实现了一个简单的三维场景,在此基础上,我们进行一些小小的改造。
我们了解一个网格模型由几何体和材质模型组成,我们可以对材质进行贴图处理,用我们想要的图片作为几何体材质覆盖到几何体中。
下面是一个简单示例
import React, { Component } from 'react'
import Earth from './Earth.png'
import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'
export default class index extends Component {
componentDidMount(){
/**
*
* 创建场景对象Scene
*/
const scene = new THREE.Scene();
/**
* 创建网格模型
*/
const geometry = new THREE.SphereGeometry(60, 100, 100); //球体
// TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理
const textureLoader = new THREE.TextureLoader();
// 执行load方法,加载纹理贴图成功后,返回一个纹理对象Texture
const texture= textureLoader.load(Earth)
const material = new THREE.MeshLambertMaterial({
// color: 0x0000ff,
// 设置纹理贴图:Texture对象作为材质map属性的属性值
map: texture,
// wireframe:true//线框渲染方式
}); //材质对象Material
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
//纹理贴图加载成功后,调用渲染函数执行渲染操作
/**
* 光源设置
*/
//点光源
const point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
const ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
/**
* 相机设置
*/
const width = window.innerWidth; //窗口宽度
const height = window.innerHeight; //窗口高度
const k = width / height; //窗口宽高比
const s = 150; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
/**
* 创建渲染器对象
*/
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置渲染区域尺寸
renderer.setClearColor(0x000000, 1); //设置背景颜色
document.getElementById("Earth").appendChild(renderer.domElement); //body元素中插入canvas对象
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
mesh.rotation.y+=0.01;//转动方向
requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
render();
//创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性
const controls = new OrbitControls(camera,renderer.domElement);
//controls.addEventListener('change',render);
}
render() {
return (
<div>
<div id="Earth"/>
</div>
)
}
}
这个代码中的重点代码是下面这段
// TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理
const textureLoader = new THREE.TextureLoader();
// 执行load方法,加载纹理贴图成功后,返回一个纹理对象Texture
const texture= textureLoader.load(Earth)
const material = new THREE.MeshLambertMaterial({
// color: 0x0000ff,
// 设置纹理贴图:Texture对象作为材质map属性的属性值
map: texture,
// wireframe:true//线框渲染方式
}); //材质对象Material
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
效果如下
第二个例子,这次我们以正方体为例,正方体六个面。
按照上面的方法,我们会发现,正方体六个面都会被同一张图片覆盖,此时,我们可以进行材质数组的创建,为正方体的六个面分别创建不同的材质数组
我们将上述的代码进行一些小小的改动
//声明一个正方体
const geometry = new THREE.BoxGeometry(100,100,100);
//声明材质数组
const material_1 = new THREE.MeshPhongMaterial({
color:0xffff3f
});
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load(Earth);
const material_2 = new THREE.MeshLambertMaterial({
map:texture
});
const materialArr = [material_1, material_1, material_1, material_1, material_2, material_1];
const mesh = new THREE.Mesh(geometry,materialArr);
console.log("数组详情",geometry.groups)
scene.add(mesh);
效果如下
经过上面的铺垫,我们开始实现一个简单的vr看房,实现思路如下,
1.以正方形为例
我们选取一个室内的前后左右,上下的六张图片分别赋值给材质数组,大家可以自行搜索贴图资源,具体效果如下
但此时我们只是成功了一半,我们要实现想要的效果还差一点,首先,图片向内翻转180度,然后将摄像机的位置放在内部的中心点中。
只需要一个小小的改动,将网格模型的gemoetry对象进行缩放,当为负数的时候,就会进行翻转,然后设置相机坐标就大功告成了
mesh.geometry.scale(1, 1, -1);
圆形的几何体也可以,而且只需要加载一张图片,不过需要特殊的全景图片,这里给出一个效果图片