vesh-vj
Version:
VESH's JavaScript Framework
384 lines (376 loc) • 14.2 kB
JavaScript
(function (V, W, $) {
V.registScript(function (path, vm) {
var _ = this, __ = {};
{
//简历一个基础的scene对象,允许用户定义3DObject对象,及其属性 scale rotate location属性,允许3DObject对象执行move等等操作,提供动画事件与mousemove,mouseover事件
V.inherit.apply(_, [W.Control, [path || "<div></div>", V.merge({
data: {
scene: {},
stats: true,
size: { width: V.userAgent.width, height: V.userAgent.height },
lights: [{ type: 'Ambient', color: { rgb: 0xffffff, opacity: 1 }, position: { x: 100, y: 100, z: 200 } }],
camera: { type: 'Perspective', size: { width: V.userAgent.width, height: V.userAgent.height }, angle: 60, near: 1, far: 10000, rotate: { x: 0, y: 0, z: 0 }, position: { x: 0, y: 0, z: 0 }, look: { x: 0, y: 0, z: 0 }, up: 'y' },
render: { type: 'WebGL', antialias: true, precision: 2, hasShadow: true, background: { rgb: 0xFFFFFF, opacity: 1.0 } },
}
}, V.getValue(vm, {}))]]);
_.is3D = true;
_.objs = { count: 0 };
_.camera = null;
__.onLoad = _.onLoad;
__.render = _.render;
__.addControl = _.addControl;
__.removeControl = _.removeControl;
__.clearControl = _.clearControl;
_.addDesc('threemovie 3D基础控件');
_.addDesc('属性:');
_.addDesc('\tlights 对象数组[{type:"Directional"平行光源,position:方向}]');
_.addDesc('\tcamera 镜头type Orthographic left,right,top,bottom,near,far/Perspective angle视锥角度,near近处和far远处的阀值设置 当比例超出阀值设置时不可显示,position:{x,y,z}方位,look:{x,y,z}朝向的方向,up:{x,y,z}设定镜头的正向方向');
_.addDesc('\trender 生成器type WebGL 生成器的基本属性 antialias:是否抗锯齿,precision:0低精度,1中精度,2高精度,hasShadow:是否允许阴影,background:{rgb:0xFFFFFF,opacity:1.0}背景颜色');
_.addDesc("定义:");
_.addDesc("\tthreemovie: { path: '../../Scripts/ref/three.min.js;../../Scripts/ref/stats.min.js;../../Scripts/module/part/tc.js;' }");
}
_.onLoad = function (node) {
V.forC(_.events, function (k, v) {
switch (k.toLowerCase()) {
case 'hover':
node.hover(function (e) {
_.call('hover', { e: e, hover: true, D2Location: __.getPointOnCanvas(e.target, e.pageX, e.pageY) });
}, function (e) {
_.call('hover', { e: e, hover: false, D2Location:__.getPointOnCanvas(e.target, e.pageX, e.pageY) });
});
break;
case 'click':
node.click(function (e) {
V.stopProp(e);
_.call('click', { e: e, D2Location: __.getPointOnCanvas(e.target, e.pageX, e.pageY) });
});
break;
case 'mousedown':
case 'mouseup':
case 'mousemove':
break;
default:
_.bindEvent(_.node, k, v);
break;
}
}, function () {
if (!THREE) {
V.showException('没有加载到THREE.js');
return;
} else if (window.WebGLRenderingContext ? false : true) {
V.showException('当前浏览器' + V.userAgent.name + '不支持WebGL');
return;
}
_.scene = new THREE.Scene();
_.objarray = _.scene.children;
node.mousedown(function (e) { __.doMouse(e, 'mousedown'); });
node.mouseup(function (e) { __.doMouse(e, 'mouseup'); });
node.mousemove(function (e) { __.doMouse(e, 'mousemove'); });
__.onLoad(node);
});
};
{
//位置服务
__.getPointOnCanvas = function (can, x, y) {
var bbox = can.getBoundingClientRect();
return {
x: x - bbox.left * (can.width / bbox.width),
y: y - bbox.top * (can.height / bbox.height)
};
};
__.objhover = null;
__.clicktime = null;
__.doMouse = function (e, name) {
e.preventDefault();
var x = e.pageX;
var y = e.pageY;
var canvas = e.target;
var loc = __.getPointOnCanvas(canvas, x, y);
_.call(name, { e: e, D2Position: loc });
//進行3D視線撲捉最上層的3D对象 判断vid 找到物理控件进行事件触发
var obj = _.objectFromMouse(x, y);
if (obj.obj)
switch (name.toLowerCase()) {
case 'mousedown':
__.clicktime = new Date();
obj.obj.call('mousedown', { e: e, D2Position: loc, D3Position: obj.point });
break;
case 'mouseup':
if (new Date().sub('ms', __.clicktime) <= 500){
_.call('click', { e: e, D2Position: loc });
obj.obj.call('click', { e: e, D2Position: loc, D3Position: obj.point });
}
obj.obj.call('mouseup', { e: e, D2Position: loc, D3Position: obj.point });
break;
case 'mousemove':
if (__.objhover == null) {
__.objhover = obj.object.vid;
obj.obj.call('hover', { e: e, hover: true, D2Position: loc, D3Position: obj.point });
} else if (__.objhover != obj.object.vid) {
_.objs[__.objhover].call('hover', { e: e, hover: false, D2Position: loc, D3Position: obj.point });
__.objhover = obj.object.vid;
obj.obj.call('hover', { e: e, hover: true, D2Position: loc, D3Position: obj.point });
}
obj.obj.call('mousemove', { e: e, hover: true, D2Position: loc, D3Position: obj.point });
break;
case 'mousewheel':
//todo;
break;
}
else if (__.objhover) {
_.objs[__.objhover].call('hover', { e: e, hover: false, D2Position: loc, D3Position: obj.point });
__.objhover = null;
}
};
//位置服务
_.projector = new THREE.Projector();
_.get2DPosition = function (o3d) {
var mat = o3d.matrixWorld;
var pos = new THREE.Vector3();
pos = mat.multiplyVector3(pos);
projected = pos.clone();
_.projector.projectVector(projected, _.camera);
var eltx = (1 + projected.x) * _.node[0].offsetWidth / 2;
var elty = (1 - projected.y) * _.node[0].offsetHeight / 2;
var offset = $(__.renderer.domElement).offset();
eltx += offset.left;
elty += offset.top;
return { x: eltx, y: elty };
};
_.objectFromMouse = function (pagex, pagey) {
if (__.renderer) {
// Translate page coords to element coords
var offset = $(__.renderer.domElement).offset();
//转换为div坐标
var eltx = pagex - offset.left;
var elty = pagey - offset.top;
//转换为相机视野坐标
var vpx = (eltx / _.node[0].offsetWidth) * 2 - 1;
var vpy = -(elty / _.node[0].offsetHeight) * 2 + 1;
var vector = new THREE.Vector3(vpx, vpy, 0.5);
//_.projector.unprojectVector(vector, _.camera);
vector.unproject(_.camera);
//生成视界射线
var ray = new THREE.Raycaster(_.camera.position, vector.sub(_.camera.position).normalize(), _.camera.near, _.camera.far);
//获取到相交的对象
var intersects = ray.intersectObjects(_.scene.children, true);
ray = null;
if (intersects.length > 0) {
var i = 0;
while (!intersects[i].object.visible) {
i++;
}
var intersected = intersects[i];
//var mat = new THREE.Matrix4().getInverse(intersected.object.matrixWorld);
//var point = mat.multiplyVector3(intersected.point);
if (intersected)
return (_.findObjectFromIntersected(intersected.object, intersected.point, intersected.face ? intersected.face.normal : null, intersected));
} else {
return { object: null, point: null, normal: null, source: null };
}
} else return {};
};
_.findObjectFromIntersected = function (object, point, normal, source) {
if (object.vid) {
return { object: object, point: point, normal: normal, source: source, obj: _.objs[object.vid] };
} else if (object.parent) {
return _.findObjectFromIntersected(object.parent, point, normal, source);
} else {
return { object: null, point: null, normal: null, source: null };
}
};
}
_.add3DObject = function (d3o) {
var obj = d3o.obj;
if (_.scene.fog) {
obj.fog = _.scene.fog;
}
if (__.renderer && __.renderer.shadowMapEnabled) {
obj.castShadow = true;
obj.receiveShadow = true;
}
//视线捕捉时使用
obj.vid = V.getValue(obj.vid, V.random());
_.objs[obj.vid] = d3o;
_.objs.count++;
_.scene.add(obj);
_.redraw();
};
_.redraw = function () {
if (__.renderer && _.scene && _.camera && _.objs.count > 0) {
__.renderer.render(_.scene, _.camera);
}
};
_.render = function (data) {
V.forC(data, function (k, v) {
switch (k.toLowerCase()) {
case 'visible':
if (v) _.redraw();
else if (__.renderer) __.renderer.clear();
break;
case 'fog':
//雾
if (v) _.scene.fog = new THREE.Fog(0xffffff, 0.015, 100);
break;
case 'size':
_.node.width(v.width);
_.node.height(v.height);
if (_.camera) {
_.camera.aspect = v.width / v.height;
_.camera.updateProjectionMatrix();
}
if (__.renderer) {
__.renderer.setSize(v.width, v.height);
_.redraw();
}
break;
case 'stats':
if (v && Stats) {
if (_.stats) {
if (0 <= v) _.stats.setMode(v);
}
else {
_.stats = new Stats();
_.node.append($(_.stats.domElement).css('position', 'absolute').css('left', '0').css('top', '0'));
if (0 <= v) _.stats.setMode(v);
}
}
break;
case 'render':
var precision = (function () {
switch (v.precision) {
case 0:
return 'lowp';
case 1:
return 'mediump';
default:
case 2:
return 'highp';
}
})();
switch (v.type.toLowerCase()) {
case 'canvas':
__.renderer = new THREE.CanvasRenderer({ antialias: v.antialias, precision: precision, alpha: v.background.opacity == 0 });
break;
case 'webgl':
default:
__.renderer = new THREE.WebGLRenderer({ antialias: v.antialias, precision: precision, alpha: v.background.opacity == 0 });
break;
}
_.node.empty().append(__.renderer.domElement);
__.renderer.domElement.addEventListener("webglcontextlost", function (e) {
V.showException('webgl上下文丢失,重建render');
_.render({ render: _.vm.get().render });
});
__.renderer.setSize(data.size.width, data.size.height);
//todo 报错__.renderer.shadowMapEnabled = v.hasShadow;
__.renderer.setClearColor(v.background.rgb, v.background.opacity);
break;
case 'camera':
if (_.camera == null)
switch (V.getValue(v.type, 'Perspective').toLowerCase()) {
case 'orthographic':
//视角,宽高比,近处near和远处far的阀值设置 如果对象因为视角比例超出边界那么就不会显示了
_.camera = new THREE.OrthographicCamera(data.size.width / - 2, data.size.width / 2, data.size.height / 2, data.size.height / - 2, v.near, v.far);
break;
case 'perspective':
default:
//视角,宽高比,近处near和远处far的阀值设置 如果对象因为视角比例超出边界那么就不会显示了
_.camera = new THREE.PerspectiveCamera(v.angle, data.size.width / data.size.height, v.near, v.far);
break;
}
V.forC(v, function (k2, v2) {
switch (k2.toLowerCase()) {
case 'position':
if (_.camera.position.set)
_.camera.position.set(v2.x, v2.y, v2.z);
else
V.merge(_.camera.position, v2, true);
break;
case 'rotate':
if (_.camera.rotation.set)
_.camera.rotation.set(v2.x, v2.y, v2.z);
else
V.merge(_.camera.rotation, v2, true);
break;
case 'up':
switch (v2.toLowerCase()) {
case 'x':
V.merge(_.camera.up, { x: 1, y: 0, z: 0 }, true);
break;
case 'y':
V.merge(_.camera.up, { x: 0, y: 1, z: 0 }, true);
break;
case 'z':
default:
V.merge(_.camera.up, { x: 0, y: 0, z: 1 }, true);
break;
}
break;
case 'look':
if (v2) {
_.camera.lookAt(v2);
}
break;
}
}, function () {
//_.camera.updateProjectionMatrix();
});
break;
case 'lights':
if (v) {
V.each(v, function (v2) {
var light = null;
switch (v2.type.toLowerCase) {
default:
case 'directional':
light = new THREE.DirectionalLight(v2.color.rgb, v2.color.opacity, 0);//设置平行光源
break;
case 'point':
light = new THREE.PointLight(v2.color.rgb, v2.color.opacity, 0);//设置点光源
break;
case 'spot':
light = new THREE.SpotLight(v2.color.rgb, v2.color.opacity, 0, V.getValue(v2.color.angle, 0));//设置漫反射光源
break;
case 'ambient':
light = new THREE.AmbientLight(v2.color.rgb, v2.color.opacity, 0);//设置背景光源
break;
case 'area':
light = new THREE.AreaLight(v2.color.rgb, v2.color.opacity, 0);//设置区域光源
break;
}
if (v2.position)
light.position.set(v2.position.x, v2.position.y, v2.position.z);//设置光源向量
_.scene.add(light);// 追加光源到场景
});
}
break;
}
}, function () {
__.render(data);
if (data.play != undefined) {
var v2 = data.play;
if (v2 && typeof (v2) == 'function') {
var id = '';
var func = v2;
var go = function () {
if (_.stats) _.stats.update();
if (_.vm.get().play) {
id = window.requestAnimationFrame(go);
} else {
__.resumego = go;
window.cancelAnimationFrame(id);
}
func.apply(_.parent.vms, [_.vm.data, _.vm]);
//_.parent.redraw();
};
go();
} else if (true === v2 && __.resumego) {
__.resumego();
}
}
_.redraw();
});
};
});
})(VJ, VJ.view, jQuery);