1、THREEJS 官方网址: <u>https://threejs.org/。</u> threejs 通过封装WEBGL API 实现了在网页端直接进行三维3d模型渲染。应用场景包括:小游戏,在线展厅,DIY 互动等现代互联网应用,极具发展前景。
2、官方使用案例https://threejs.org/examples/,可以直接套用。
webglmaterial.png
以 <u>https://github.com/mrdoob/three.js/blob/master/examples/webgl_materials.html</u> 为例,讲解如何使用Threejs构建自己的应用:
步骤一、新建html页面。
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - materials</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl materials
</div>
<script type="module">
import * as THREE from '../build/three.module.js'; //引入threejs 主框架
import Stats from './jsm/libs/stats.module.js'; //引入状态帧计数状态显示
let stats;
let camera, scene, renderer;
let pointLight;
const objects = [], materials = [];
init();
animate();
function init() {
const container = document.createElement( 'div' );//创建3d 场景所在的区域
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );//设置3d场景的镜头参数,45度代表镜头的视角。
camera.position.set( 0, 200, 800 );
scene = new THREE.Scene();//创建场景对象,所有渲染都是根据该对象进行渲染。
// Grid
const helper = new THREE.GridHelper( 1000, 40, 0x303030, 0x303030 );//场景中的方格线,辅助视角
helper.position.y = - 75;
scene.add( helper );
// Materials
const texture = new THREE.Texture( generateTexture() );//创建纹理
texture.needsUpdate = true;
materials.push( new THREE.MeshLambertMaterial( { map: texture, transparent: true } ) );
materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd } ) );
materials.push( new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, flatShading: true } ) );
materials.push( new THREE.MeshNormalMaterial() );
materials.push( new THREE.MeshBasicMaterial( { color: 0xffaa00, transparent: true, blending: THREE.AdditiveBlending } ) );//设置材质参数,包括混合参数,直接影响颜色混合后的效果
materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd } ) );
materials.push( new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, map: texture, transparent: true } ) );//设置材质的反射、透明、高光参数,如金属材质,玻璃材质,木头材质,反射系数,高光系数,粗糙程度都是不一样的。
materials.push( new THREE.MeshNormalMaterial( { flatShading: true } ) );
materials.push( new THREE.MeshBasicMaterial( { color: 0xffaa00, wireframe: true } ) );
materials.push( new THREE.MeshDepthMaterial() );
materials.push( new THREE.MeshLambertMaterial( { color: 0x666666, emissive: 0xff0000 } ) );
materials.push( new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x666666, emissive: 0xff0000, shininess: 10, opacity: 0.9, transparent: true } ) );
materials.push( new THREE.MeshBasicMaterial( { map: texture, transparent: true } ) );
// Spheres geometry
const geometry = new THREE.SphereGeometry( 70, 32, 16 );
for ( let i = 0, l = materials.length; i < l; i ) {
addMesh( geometry, materials[ i ] );
}
// Lights
scene.add( new THREE.AmbientLight( 0x111111 ) );//设置漫反射光源,类似白天没有太阳直晒的房间,有暗光。产生的原有主要是环境物体多次发射后的光线。
const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.125 );//方向光源,仿真太阳光,从很远的距离照射。
directionalLight.position.x = Math.random() - 0.5;
directionalLight.position.y = Math.random() - 0.5;
directionalLight.position.z = Math.random() - 0.5;
directionalLight.position.normalize();//位置参数,主要是控制光从哪个方向照射,类似太阳在东面,还是西面。
scene.add( directionalLight );
pointLight = new THREE.PointLight( 0xffffff, 1 );//点光影,仿真单个灯泡
scene.add( pointLight );
pointLight.add( new THREE.Mesh( new THREE.SphereGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) ) );
//
renderer = new THREE.WebGLRenderer( { antialias: true } );//webgl的渲染引擎
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );//将3d渲染引擎绑定到html页面的div
//
stats = new Stats();
container.appendChild( stats.dom );//状态显示,二维组件,与3d没有直接关系
//
window.addEventListener( 'resize', onWindowResize );
}
function addMesh( geometry, material ) {
const mesh = new THREE.Mesh( geometry, material );
mesh.position.x = ( objects.length % 4 ) * 200 - 400;
mesh.position.z = Math.floor( objects.length / 4 ) * 200 - 200;
mesh.rotation.x = Math.random() * 200 - 100;
mesh.rotation.y = Math.random() * 200 - 100;
mesh.rotation.z = Math.random() * 200 - 100;
objects.push( mesh );
scene.add( mesh );//所有渲染的模型,均需加入值场景对象scene内。3d引擎是通过遍历scene下的子对象,进行渲染的。
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function generateTexture() {//通过canvas 方式画出纹理,也可以直接从图像文件png加载纹理。
const canvas = document.createElement( 'canvas' );
canvas.width = 256;
canvas.height = 256;
const context = canvas.getContext( '2d' );
const image = context.getImageData( 0, 0, 256, 256 );
let x = 0, y = 0;
for ( let i = 0, j = 0, l = image.data.length; i < l; i = 4, j ) {
x = j % 256;
y = ( x === 0 ) ? y 1 : y;
image.data[ i ] = 255;
image.data[ i 1 ] = 255;
image.data[ i 2 ] = 255;
image.data[ i 3 ] = Math.floor( x ^ y );
}
context.putImageData( image, 0, 0 );
return canvas;
}
//
function animate() {
requestAnimationFrame( animate );//这部分是关键,通过设置浏览器的动画循环调用animate函数。保障画面循环渲染。好比cpu的时钟,一直在运转。
render();//场景渲染,webgl 渲染实际工作内容。
stats.update();
}
function render() {
const timer = 0.0001 * Date.now();
camera.position.x = Math.cos( timer ) * 1000;
camera.position.z = Math.sin( timer ) * 1000;
camera.lookAt( scene.position );
for ( let i = 0, l = objects.length; i < l; i ) {
const object = objects[ i ];
object.rotation.x = 0.01;
object.rotation.y = 0.005;
}
materials[ materials.length - 2 ].emissive.setHSL( 0.54, 1, 0.35 * ( 0.5 0.5 * Math.sin( 35 * timer ) ) );
materials[ materials.length - 3 ].emissive.setHSL( 0.04, 1, 0.35 * ( 0.5 0.5 * Math.cos( 35 * timer ) ) );
pointLight.position.x = Math.sin( timer * 7 ) * 300;
pointLight.position.y = Math.cos( timer * 5 ) * 400;
pointLight.position.z = Math.cos( timer * 3 ) * 300;
renderer.render( scene, camera );//调用renderer引擎实际渲染场景scene,camera,后续另外再讲场景渲染的数学模型。
}
</script>
</body>
</html>
3、如何在vue中引入THREEJS
步骤一、新建threejs 组件,ZeusStage.vue
大画家效果图.jpg
<template>
<div ref="container" >
</div>
</template>
<script>
import * as THREE from 'three'
export default {
name: 'ZeusStage',
provide () {
return {
parentObj: null, // avoid "injection not found" warning
_baseUrl: null,
global: this.global
}
},
props: {
size: {
type: Object, // { w, h }
required: false,
default: function(){
return {
w:100,
h:100
}
}
},
scenejson:{
type: Object
},
scene_url:{
type:String
}
},
data () {
return {
g_material_selected:'黄金',
img_blend:'',
popover_active: false,
};
},
watch: {
size(newval, oldval) {
if (newval != oldval) {
this.$refs.container.style.width = this.size.w 'px';
this.$refs.container.style.height = this.size.h 'px';
this.$refs.container.width = this.size.w;
this.$refs.container.height = this.size.h;
this.$emit("resize");
}
}
},
mounted () {
this.extent();
this.container = this.$refs.container;
this.init();
this.parseScene();
},
methods: {
init() {
var _this = this;
var container = this.container;
var dom = container;
this.dom = dom;
this.DrawMode = false; //画布模式
this.initScene();
this.initControl();
this.initRenderer();
// POSTPROCESSING
var clock = new THREE.Clock();
var controls = this.controls;
var scene = this.scene;
var camera = this.camera;
var renderer = this.renderer;
setupEventHandlers();
controls.addEventListener('change', render);
animate();
function setupEventHandlers() {
var onResize = function() {
if (camera instanceof THREE.OrthographicCamera) {
camera.left = dom.offsetWidth / -2;
camera.right = dom.offsetWidth / 2;
camera.top = dom.offsetHeight / 2;
camera.bottom = dom.offsetHeight / -2;
}
if (camera instanceof THREE.PerspectiveCamera) {
camera.aspect = dom.offsetWidth / dom.offsetHeight;
}
camera.updateProjectionMatrix();
renderer.setSize(dom.offsetWidth, dom.offsetHeight);
render();
};
//window.addEventListener('resize', onResize, false);
_this.$on("resize", onResize );
onResize();
}
//
function animate() {
requestAnimationFrame(animate);
controls.update();
render();
}
function render() {
if (renderer) {
renderer.clear();
_this.setLightPosition();
var delta = clock.getDelta();
updateDelta(delta, camera);
renderer.render(scene, camera);
}
}
function updateDelta(delta,camera) {
if (scene) {
scene.traverse(function(_obj) {
if (_obj.updateDelta) {
_obj.updateDelta(delta,camera);
}
});
}
}
},
initControl() {
var camera = this.camera;
var dom = this.dom;
var controls = new ZEUS.THREE_EXT.OrbitControls(camera, dom);
this.controls = controls;
controls.enabled = true;
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 2.0;
controls.panSpeed = 0.0003;
controls.minDistance = 15;
controls.maxDistance = 100;
controls.noZoom = false;
controls.noPan = false;
controls.maxPan = 10;
controls.autoRotate = true;
controls.autoRotateSpeed = -2.5; //TODO
controls.enableDamping = true;
controls.dampingFactor = 0.1;
controls.keys = [65, 83, 68];
hoverDelay({
el:dom,
hoverDuring: 200,
outDuring: 500,
hoverEvent: function() {
controls.autoRotate = false;
//_this.setAutoRotate(false);
},
outEvent: function() {
//controls.autoRotate = true;
//_this.setAutoRotate(true);
}
})
function hoverDelay(option){
var el = option.el;
var timer = null;
var onMouseOver = function(){
if(timer){
clearTimeout(timer);
}
timer = setTimeout(() => {
if(option.hoverEvent){
option.hoverEvent();
}
},option.hoverDuring);
}
var onMouseOut = function (){
if(timer){
clearTimeout(timer);
}
timer = setTimeout(() => {
if(option.outEvent){
option.outEvent();
}
},option.outDuring);
}
el.addEventListener("mouseover",onMouseOver);
el.addEventListener("mouseout",onMouseOut);
el.addEventListener("touchstart",onMouseOver);
el.addEventListener("touchend",onMouseOut)
}
},
initScene() {
this.camera = new THREE.PerspectiveCamera(45, 1, 1, 100000);
this.scene = new THREE.Scene();
this.scene.name = 'Scene';
this.initLight();
this.box = null;
},
initLight() {
// LIGHTS
var key_light = new THREE.DirectionalLight(0xffffff, 1);//new THREE.SpotLight(0xffffff, 1.4); //FFFFE6
key_light.castShadow = true;
key_light.position.x = 1;
key_light.position.y = 1;
key_light.position.z = 1;
this.key_light = key_light;
this.scene.add(this.key_light);
},
initRenderer() {
var clearColor = 0x00000000;
var createRenderer = function(type, antialias) {
var renderer = new THREE[type]({
antialias: antialias,
alpha:true
});
renderer.setClearColor(clearColor,0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.autoClear = false;
renderer.autoUpdateScene = false;
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.physicallyBasedShading = true;
return renderer;
};
var renderer = createRenderer('WebGLRenderer', true);
renderer.autoClear = false;
this.renderer = renderer;
this.dom.appendChild(renderer.domElement);
renderer.setSize(this.size.w, this.size.h);
},
initAxesHelper(){
var helper = new THREE.AxesHelper(200);
this.scene.add( helper );
},
addObject(object) {
this.scene.add(object);
},
moveObject(object, parent, before) {
if (parent === undefined) {
parent = this.scene;
}
parent.add(object);
// sort children array
if (before !== undefined) {
var index = parent.children.indexOf(before);
parent.children.splice(index, 0, object);
parent.children.pop();
}
},
nameObject(object, name) {
object.name = name;
},
getObjectByName(name) {
return this.scene.getObjectByName(name);
},
removeObject(object) {
if (object.parent === undefined) return; // avoid deleting the camera or scene
object.parent.remove(object);
},
setObjectMaterial(material, object_name) {
var object = this.getObjectByName(object_name);
var has_changed = false;
if (object) {
object.traverse(function(_obj) {
if (_obj.material != material) {
has_changed = true;
if (_obj.material instanceof THREE.MultiMaterial) {
var _material = new THREE.MultiMaterial(
[material.clone(), material]
);
for (var i = 0; i < _material.materials.length; i ) {
_material.materials[i].shading = _obj.material.materials[i].shading;
}
_obj.material = _material;
} else {
_obj.material = material;
}
}
});
}
if (has_changed) {
this.$emit('materialChanged');
}
},
setObjectPosition(position, object_name) {
var object = this.getObjectByName(object_name);
object.position.copy(position);
},
setLightPosition() {
var _this = this;
var camera = _this.camera;
var position = new THREE.Vector3().copy(camera.position);
var radius = position.length();
var camera_py = new THREE.Vector3().copy(camera.up);
var camera_pz = new THREE.Vector3(0, 0, 1);
var camera_px = new THREE.Vector3().crossVectors(camera_py, camera_pz);
camera_py.applyQuaternion(camera.quaternion);
camera_pz.applyQuaternion(camera.quaternion);
camera_px.applyQuaternion(camera.quaternion);
var key_light = _this.key_light;
var fill_light = _this.fill_light;
var back_light = _this.back_light;
var bottom_light = _this.bottom_light;
key_light.position.copy(camera_pz);
key_light.position.applyQuaternion(new THREE.Quaternion().setFromAxisAngle(camera_py, -Math.PI / 6));//-Math.PI / 4
key_light.position.applyQuaternion(new THREE.Quaternion().setFromAxisAngle(camera_pz, -Math.PI / 6));//-Math.PI / 4
key_light.position.multiplyScalar(radius);
fill_light.position.copy(camera_pz);
fill_light.position.applyQuaternion(new THREE.Quaternion().setFromAxisAngle(camera_py, Math.PI / 4)); //Math.PI / 4
fill_light.position.applyQuaternion(new THREE.Quaternion().setFromAxisAngle(camera_pz, Math.PI / 4));//Math.PI / 4
fill_light.position.multiplyScalar(radius);
back_light.position.copy(camera_pz);
back_light.position.applyQuaternion(new THREE.Quaternion().setFromAxisAngle(camera_px, -Math.PI / 6));
back_light.position.multiplyScalar(radius);
bottom_light.position.copy(camera_py).multiplyScalar(-radius);
},
async initTextureCube() {
var base_url = this.scene_url "textures/";
var r = base_url "cube/2021/";
await this.setTextureCube(r);
},
async setTextureCube(url) {
var urls = [url "px.jpg", url "nx.jpg",
url "py.jpg", url "ny.jpg",
url "pz.jpg", url "nz.jpg"
];
this.textureCube = await this.loadTextureCube(urls);
this.textureCube.format = THREE.RGBFormat;
this.textureCube.mapping = THREE.CubeTexture;
},
async setTextureCube_diamond(url) {
var urls = [url "ny.jpg", url "ny.jpg",
url "ny.jpg", url "ny.jpg",
url "ny.jpg", url "ny.jpg"
];
this.textureCube_diamond = await this.loadTextureCube(urls);
this.textureCube.mapping = THREE.CubeRefractionMapping;
},
getThreeMaterial(material_name) {
var _this = this;
if (THREE) {
_this.Materials = _this.Materials || {};
var material = _this.Materials[material_name];
if (material instanceof THREE.Material) {
return material;
} else{
var option = getMaterialConfig(material_name);
if (option) {
material = new THREE.MeshPhongMaterial(option);
_this.Materials[material_name] = material;
}
}
return material;
}
function getMaterialConfig(_material_name) {
var textureCube = _this.textureCube || null;
var textureCube_diamond = _this.textureCube_diamond || null;
var config = global.ConfigMaterials;
var metal_materials = config.metal_materials;
for (let i = 0, l = metal_materials.length; i < l; i ) {
let material = metal_materials[i];
let material_name = material.name;
if (_material_name == material_name) {
return {
color: new THREE.Color().setStyle(material.color),
specular: new THREE.Color().setStyle(material.specular),
shininess: parseFloat(material.shininess),
envMap: textureCube,
combine: THREE.MultiplyOperation,
reflectivity: material.reflectivity
};
}
}
var diamond_materials = config.diamond_materials;
for (let i = 0, l = diamond_materials.length; i < l; i ) {
let material = diamond_materials[i];
let material_name = material.name;
if (material_name == _material_name) {
var m = {};
m.envMap = textureCube_diamond;
if (material.envMap == false) {
m.envMap = null;
}
if (material.color != undefined) {
m.color = new THREE.Color().setStyle(material.color);
}
if (material.emissive != undefined) {
m.emissive = new THREE.Color().setStyle(material.emissive);
}
if (material.ambient != undefined) {
m.ambient = new THREE.Color().setStyle(material.ambient);
}
if (material.specular != undefined) {
m.specular = new THREE.Color().setStyle(material.specular);
}
if (material.shininess != undefined) {
m.shininess = parseFloat(material.shininess);
}
if (material.reflectivity != undefined) {
m.reflectivity = parseFloat(material.reflectivity);
}
if (material.opacity != undefined) {
m.opacity = parseFloat(material.opacity);
}
if (material.transparent != undefined) {
m.transparent = material.transparent;
}
if (material.refractionRatio != undefined)
m.refractionRatio = parseFloat(material.refractionRatio);
m.combine = THREE.MultiplyOperation;
return m;
}
}
}
},
//diy parts
async parseScene( ){
this.rundata = {};
this.parseCamera();
await this.initTextureCube();
await this.parseMainMaterial();
await this.parsePart();
this.$root.$emit("sceneLoaded");
},
parseCamera() {
var _this = this;
var camera = this.scenejson.camera;
if (camera.distance != undefined) {
var distance = parseFloat(camera.distance);
var position0 = new THREE.Vector3(0, 0, distance);
position0.applyAxisAngle(new THREE.Vector3(1, 0, 0), -15 * Math.PI / 180);
this.camera.position.copy(position0);
this.controls.position0 = position0.clone();
}
if (camera.lookAt != undefined) {
var target0 = new THREE.Vector3().fromArray(camera.lookAt);
this.camera.lookAt(target0);
this.controls.target0.copy(target0);
this.controls.target.copy(target0);
}
if (camera['min-distance'] != undefined) {
var minDistance = parseFloat(camera['min-distance']);
this.controls.minDistance = minDistance;
}
if (camera['max-distance'] != undefined) {
var maxDistance = parseFloat(camera['max-distance']);
this.controls.maxDistance = maxDistance;
}
if (camera.rotation != undefined) {
var rotation = new THREE.Vector3().fromArray(camera.rotation);
rotation.x = rotation.x * Math.PI / 180;
rotation.y = rotation.y * Math.PI / 180;
rotation.z = rotation.z * Math.PI / 180;
this.controls.rotation0 = rotation;
this.controls.rotateLeft(rotation.y);
this.controls.rotateUp(rotation.x);
}
_this.$emit('cameraChanged');
},
flyto:function(option){
var _distance = option.distance;
var _rotation = option.rotation;
this.controls.reset();
if (_distance != undefined) {
var distance = parseFloat(_distance);
var position0 = new THREE.Vector3(0, 0, distance);
this.camera.position.copy(position0);
}
if (_rotation != undefined) {
var rotation = new THREE.Vector3().fromArray(_rotation);
rotation.x = rotation.x * Math.PI / 180;
rotation.y = rotation.y * Math.PI / 180;
rotation.z = rotation.z * Math.PI / 180;
this.controls.rotateLeft(rotation.y);
this.controls.rotateUp(rotation.x);
}
this.controls.update();
},
controlsPosSave(){
//var target0 = this.controls.target.clone();
var position0 = this.controls.object.position.clone();
var zoom0 = this.controls.object.zoom;
return {position0:position0, zoom0: zoom0};
},
controlsPosReset(option){
this.controls.object.position.copy(option.position0);
this.controls.object.zoom = option.zoom0;
this.controls.update();
},
async parseMainMaterial( ) {
//var _this = this;
var rundata = this.rundata || {};
var materials = this.scenejson.materials;
rundata.materials = rundata.materials || {};
rundata.material_selected = "白金";
for(var i=0; i<materials.length; i ){
var _m = materials[i];
rundata.materials[_m.name] = _m;
}
rundata.material_selected = materials[0]["name"];
},
parseMaterial(_diy) {
//var _this = this;
var rundata = this.rundata || {};
rundata.materials = rundata.materials || {};
rundata.materials_diy = rundata.materials_diy || {};
rundata.materials_diy[_diy.name] = _diy;
},
async parsePart() {
var geometries = this.scenejson.geometries;
await this.parseGeometry(geometries);
},
async parseGeometry(geometries, group){
var _this = this;
var rundata = this.rundata;
var parts = rundata.parts || [];
var scene_url = this.scene_url;
group = group || this.scene;
for (var i = 0, l = geometries.length; i < l; i ) {
var geometry = geometries[i];
var option = {
name: geometry.name,
url: scene_url geometry.url,
position: geometry.position || [],
rotation: geometry.rotation || [],
scale: geometry.scale || [],
bumpMap: geometry.bumpMap || ''
};
var _geometry = await this.loadMesh(option);
onLoad(_geometry, option);
}
rundata.parts = parts;
function onLoad(_geometry, option){
if (_geometry.type=="BufferGeometry") {
var _geometry1 = new THREE.Geometry();
_geometry1 = _geometry1.fromBufferGeometry(_geometry);
_geometry = {};
_geometry = _geometry1;
}
var smooth_angle = 85;
ZEUS.THREE_EXT.SoftenGeometryNormal(_geometry, smooth_angle, true);
_geometry.computeBoundingBox();
var material = _this.getMaterial(option.name);
ZEUS.THREE_EXT.UVWrap(_geometry);
let scale = 23;//46;//25;//50;
let userdata = _geometry.userdata;
let w = userdata.map_size.x * scale;
let h = userdata.map_size.y * scale;
var max_w = 2048;
if(w>max_w|| h>max_w){
var scaleX = w /max_w;
var scaleY = h /max_w;
var _scale = scaleX>scaleY?scaleX:scaleY;
w = Math.floor(w/_scale);
h = Math.floor(h/_scale);
scale = scale / _scale;
}
userdata.map_size.scale = scale;
let canvas_texture = new ZEUS.THREE_EXT.CanvasTexture({
width: w.toFixed(0),
height: h.toFixed(0),
bg_color: rundata.materials[rundata.material_selected].color
});
//_this.dom.appendChild(canvas_texture.canvas);
material.canvas_texture = canvas_texture;
material.map = canvas_texture.canvas_texture;
material.map.minFilter = THREE.LinearFilter;
material.map.generateMipmaps = false;
material.bumpMap = canvas_texture.canvas_texture;
if(option.bumpMap!=''){
var mapHeight = new THREE.TextureLoader().load( option.bumpMap );
material.bumpMap = mapHeight;
}
if(option.bumpScale!=undefined){
material.bumpScale = option.bumpScale;
}
_geometry.uvsNeedsUpdate = true;
var mesh = new THREE.Mesh(_geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
if(option.name){
_this.nameObject(mesh, option.name);
}
if (option['position'].length > 0) {
var position = option['position'];
position = new THREE.Vector3().fromArray(position);
mesh.position.copy(position);
}
if (option['rotation'].length > 0) {
var rotation = option['rotation'];
rotation = new THREE.Vector3().fromArray(rotation).multiplyScalar(Math.PI / 180);
mesh.rotateX(rotation.x);
mesh.rotateY(rotation.y);
mesh.rotateZ(rotation.z);
}
if (option['scale'].length > 0) {
let _scale = option['scale'];
_scale = new THREE.Vector3().fromArray(_scale);
mesh.scale.x = _scale.x;
mesh.scale.y = _scale.y;
mesh.scale.z = _scale.z;
}
mesh.userData.animate_enable = option['animate_enable'] || false;
parts.push(mesh);
group.add(mesh);
}
},
async loadMesh(option){
return new Promise(function(resolve,reject){
var loader = new ZEUS.THREE_EXT.MeshLoader();
var url = option.url;
var onLoad = function(_geometry){
resolve(_geometry);
};
var onProgress = null;
var onError = reject;
loader.load(url, onLoad, onProgress, onError);
});
},
async loadImage(src){
return new Promise(function(resolve,reject){
var img = new Image();
img.onload = function(){
resolve(this);
};
img.onerror = reject;
img.src = src;
});
},
async imagedata_to_image(img_data, rect) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = img_data.width;
canvas.height = img_data.height;
ctx.putImageData(img_data, 0, 0);
let _img_data = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);
var data = _img_data.data, iLen = data.length ;
for (var i = 0; i < iLen; i = 4) {
if(data[i 3]==0){
data[i] = 255;
data[i 1] = 255;
data[i 2] = 255;
data[i 3] = 255;
}
}
var _canvas = document.createElement('canvas');
var _ctx = _canvas.getContext('2d');
_canvas.width = rect.width;
_canvas.height = rect.height;
_ctx.putImageData(_img_data, 0, 0);
//var image = new Image();
let url = _canvas.toDataURL('image/png');
let image = await this.loadImage(url);
return image;
},
async loadTextureCube(urls){
return new Promise(function(resolve,reject){
var loader = new THREE.CubeTextureLoader();
var onLoad = function(texture){
resolve(texture);
}
loader.load(urls,onLoad ,null, reject);
});
},
//设置材质名
setMaterial(name){
var rundata = this.rundata || {};
rundata.material_selected = name;
var parts = rundata.parts || [];
for(var i=0; i<parts.length; i ){
var mesh = parts[i];
var m = mesh.material;
if(m==undefined){
continue;
}
if(m.name!=name){
var _m = rundata.materials[rundata.material_selected];
m.color = new THREE.Color(_m.color);
m.name = _m.name;
m.canvas_texture.setBgcolor(_m.color);
}
}
},
getMaterialSelected(){
var rundata = this.rundata || {};
return rundata.material_selected || "白金";
},
onClickMaterial(name){
this.$parent.$emit('onClickMaterial', name );
},
getMaterial(/*mesh_name*/){
var rundata = this.rundata || {};
rundata.materials = rundata.materials || {};
var _m = rundata.materials[rundata.material_selected];
var material = new THREE.MeshPhysicalMaterial({
name: _m.name,
color: _m.color,
reflectivity: 0.99,
metalness: 1,
roughness: 0.01,
envMap: this.textureCube,
//envMapIntensity:1.5,
bumpScale: 0.1,
});
return material;
},
clearObjects() {
var objects = this.scene.children;
while (objects.length > 0) {
this.removeObject(objects[0]);
}
},
clear() {
this.clearObjects();
},
toDataURL() {
if (this.renderer.domElement.toDataURL) {
return this.renderer.domElement.toDataURL('image/png');
} else {
return "";
}
}
}
}
</script>
步骤二、调用ZeusStage.vue组件
<template>
<div id="app">
<div class="container " style="background-image:url(images/background-3d.png)">
<ZeusStage ref="zeus_stage" :size="size" :scenejson="scenejson" :scene_url="scene_url"></ZeusStage>
</div>
</div>
</template>
<script>
import ZeusStage from './components/ZeusStage.vue'
export default {
name: 'App',
components: {
ZeusStage
},
mounted(){
var _this = this;
function onresize(){
_this.size = {
w: window.innerWidth -1,
h: window.innerHeight -1
};
_this.$set(_this.size, 'w',_this.size.w);
_this.$set(_this.size, 'h',_this.size.h)
}
window.onresize = onresize;
onresize();
},
data(){
return {
isActive: true,
background:'images/bk.png',
size: {
w: 100,
h: 100
},
scenejson:{
camera:{
distance: 80,
rotation:[0,0,0],
"min-distance": 70,
"max-distance": 90
},
materials:[
{
name:'玫瑰金',
color:'#fed9d1', //'#feded1'
},
{
name:'白金',
color:'#f3eeea'
},
{
name:'黄金',
color:'#ffefc3'
},
{
name:'925银镀金',
color:'#f3eeea'
},
],
geometries:[
{
name:"circle_small",
url:"models/circle_small.zip",
position:[0,7.8,0],
rotation:[-90,0,0],
},
{
name:"circle_big",
url:"models/circle_big.zip",
position:[0,9.8,0],
rotation:[-90,0,0],
},
{
name:"chain",
url:"models/chain.zip",
position:[0,0,0],
rotation:[90,0,0],
}
]
},
scene_url:"",//"./public/",
}
},
methods:{
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
height: 100%;
width:100%;
margin:0px;
padding:0px;
}
.container{
float: left;
width: 100%;
margin: 0px;
position: absolute;
background-repeat: repeat;
background-size: 320px;
}
</style>
0人点赞
THREEJS web3d
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved