1 "use strict"
2
3 //加载js文件
4 loadfile([
5 "./js/lib/webgl.js",//检查 是否支持webgl 插件
6 "./js/lib/three_114.min.js",//3d库
7 "js/func.js"
8 ], main);
9
10 //创建一个ajax请求, 前往index.php验证用户是否已登录
11 //如果ajax返回的是false说明用户还没有登录成功,并前往 view.php,
12 //否则ajax返回用户信息对象
13 function main(){
14 new ajax({
15 url:"./php/index.php",
16 method:"get",
17 success:(data)=>{
18 let d = json.parse(data);
19 if(d === false){location.href = "./login/view.php"; return;}
20 showuserinfo(d.val, new view());//用户信息视图
21 showthreeview();//场景3d视图
22 }
23 });
24 }
25
26 //退出
27 function exit(){
28 if(new func().isrun({id:"testid"}) !== true){console.log("你点得太快了,服务器跟不上"); return;}
29 new ajax({
30 url:"./php/exit.php",
31 method:"get",
32 success:(data)=>{main();}
33 });
34 }
35
36 //创建html p元素
37 function create(v, fel, content){
38 let p = v.add(fel, "p");
39 p.innerhtml = content || "";
40 return p;
41 }
42
43 //创建登录成功后的主页内容
44 function showuserinfo(user, v){//console.log(user);
45
46 var lid = v.get("loginboxid");
47
48 var elem_name = create(v, lid, "你好: " + user.username);
49 elem_name.innerhtml += "<input type = 'button' id = 'exitid' value = '退 出' />";
50 v.get('exitid').onclick = ()=>{exit();}//退出按钮
51
52 create(v, lid, "我知道你的邮箱是: " + user.email);
53
54 switch(user.like.length){
55 case 1 :
56 create(v, lid, "我还知道你喜欢: " + user.like[0]);
57 break;
58 case 2 :
59 create(v, lid, "我还知道你喜欢: " + user.like[0]);
60 create(v, lid, "还有: " + user.like[1]);
61 break;
62 case 3 :
63 create(v, lid, "我还知道你喜欢: " + user.like[0]);
64 create(v, lid, "还有: " + user.like[1]);
65 create(v, lid, "还有: " + user.like[2]);
66 break;
67 default : break;
68 }
69 lid.style = "visibility:visible;";
70 //lid居中显示
71 /* let x = math.round((v.client.w/2) - (lid.offsetwidth/2));
72 let y = math.round((v.client.h/2) - (lid.offsetheight/2)) - 16;
73 lid.style = "left:"+x+"px; top:"+y+"px; visibility:visible;"; */
74 }
75
76
77 //创建 主页 3d 视图
78 /*
79 键盘 w a s d移动
80 鼠标 点击滑动旋转
81 */
82 function showthreeview(){
83
84 var three = new three();
85
86 //场景
87 var scene = three.createscene();
88
89 //相机
90 var camera = three.createcamera(); //console.log(camera);
91
92 //渲染器
93 var renderer = three.createrenderer();
94
95 //灯光
96 var light = three.createlight(scene);
97
98 //控制器
99 three.createcontrol(camera, renderer);
100
101 //动画循环
102 three.animate(scene, camera, renderer);
103
104 //创建地面
105 three.createground();
106
107 //创建院墙
108 three.createwall({issety:true});
109
110 //创建铁门
111 three.creategate();
112
113 console.log(three);
114 alert("键盘 w a s d移动, 鼠标 点击滑动旋转");
115 }
1 "use strict"
2
3 /**方法类
4
5 */
6 class func{
7
8 constructor(){}
9
10 //获取一个字符串的长度 包含中文
11 getstrlen(str){
12 let len = 0, i, c;
13 for (i = 0; i < str.length; i++){
14 c = str.charcodeat(i);
15 if((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f)){len++;}else{len+=2;}
16 }
17 return len;
18 }
19
20 //获取目标范围随机数(n保留浮点数数量)
21 getran(min, max, n){
22 return number((math.random() * (max - min) + min).tofixed(n || 0));//包含max
23 }
24
25 //获取2点距离
26 getposlen(sdot, edot){
27 return parseint(math.sqrt(math.pow(math.abs(sdot.x - edot.x), 2) + math.pow(math.abs(sdot.y - edot.y), 2)));
28 }
29
30 //检测是否是pc端
31 ispc(){
32 let useragent = navigator.useragent;
33 let agents = ["android", "iphone", "symbianos", "windows phone", "ipad", "ipod"];
34 let ispc = true, v;
35 for(v = 0; v < agents.length; v++){
36 if (useragent.indexof(agents[v]) > 0){ispc = false; break;}
37 }
38 return ispc;
39 }
40
41 //防止多次提交或执行(在规定时间段内只允许执行一次) 默认 3000ms
42 isrun(object){
43 //object = {id: string 必须, isexit, time}
44 //isenit : boolean 可选 如果为 true 则删除对应 id 的对象
45 //time : number 可选 默认间隔时间 3000 秒
46 var v = object || {};
47 if(this.list === undefined){func.prototype.list = {};}
48 if(v.id === undefined || typeof(v.id) !== "string"){return "参数id错误";}
49 if(v.isexit === true){delete(this.list[v.id]); return "删除对象: "+v.id;}
50 var o = this.list[v.id];
51 if(!o){this.list[v.id] = {time:v.time || 3000, nowtime:new date().gettime()}; return true;}
52 var t = new date().gettime() - o.nowtime;
53 if(t < o.time){return o.time - t;}
54 o.nowtime = new date().gettime();
55 return true;
56 }
57
58 }
59
60
61
62 /** 创建ajax请求:
63 obj = {
64 url: string 必须, 请求路径
65 method: string 可选, post 或 get请求, 默认post请求
66 data: string 可选, 要发送的数据, 默认为""
67 asy: boolean 可选, 是否异步执行, 默认为true
68 success: function 可选, 成功回调
69 error: function 可选, 失败回调
70 run: function 可选, 请求中回调
71 }
72
73 xhr.readystate:
74 0: 请求未初始化
75 1: 服务器连接已建立
76 2: 请求已接收
77 3: 请求处理中
78 4: 请求已完成,且响应已就绪
79 xhr.status:
80 200: "ok"
81 404: 未找到页面
82 */
83 class ajax{
84
85 constructor(obj){
86 let o = obj || {}
87 this.url = o.url || null;
88 this.method = o.method || "post";
89 this.data = o.data || "";
90 this.asy = o.asy || true;
91 this.callback_suc = o.success || function (){};
92 this.callback_err = o.error || function (){};
93 this.callback_run = o.run || function (){};
94 this.request();
95 }
96
97 request(){
98 if(!this.url){this.callback_err(); return;}
99 let xhr = new xmlhttprequest();
100 xhr.onreadystatechange = (e)=>{
101 if(e.target.readystate === 4 && e.target.status === 200){
102 this.callback_suc(e.target.responsetext);
103 return;
104 }
105 this.callback_run(e);
106 }
107 xhr.onerror = (e)=>{
108 this.callback_err(e);
109 }
110 if(this.method == "get"){
111 xhr.open(this.method, this.url, this.asy);
112 xhr.send();
113 return;
114 }
115 xhr.open(this.method, this.url, this.asy);
116 xhr.setrequestheader("content-type", "application/x-www-form-urlencoded");
117 xhr.send(this.data);
118 }
119
120 }
121
122
123
124 /** 视图类
125
126 */
127 class view{
128
129 constructor(){
130 if(!this.client){view.prototype.client = this.getclient();}
131 }
132
133 //创建html元素
134 add(fel, elemname, id, cls){
135 //创建一个元素
136 let el = document.createelement(elemname);
137 //设置el id 和 class
138 if(id){el.setattribute('id',id);}
139 if(cls){el.classname = cls;}
140 //把el添加到fel并显示(渲染el)
141 if(fel){fel.appendchild(el);}
142 return el;
143 }
144
145 //删除html元素
146 remove(){
147 let k, arg = arguments, err = [];
148 for(k = 0; k < arg.length; k++){
149 if(this.isel(arg[k]) === false){err.push(arg[k]); continue;}
150 arg[k].parentnode.removechild(arg[k]);
151 }
152 if(err.length > 0){return {err:'这里有一些删除失败的元素', arr:err};}
153 return true;
154 }
155
156 //id获取html元素
157 get(id){
158 return document.getelementbyid(id);
159 }
160
161 //获取可视宽高
162 getclient(){
163 return {
164 w:document.documentelement.clientwidth || document.body.clientwidth,
165 h:document.documentelement.clientheight || document.body.clientheight
166 };
167 }
168
169 //通过parentnode检查元素是否存在于页面中
170 isel(el){
171 if(typeof(el) !== 'object'){return false;}
172 //被删除之后的html元素object的 parentnode等于null
173 if(!el.parentnode){return false;}
174 return true;
175 }
176
177 //元素绑定事件
178 addevent(target, ev, callback){
179 target.addeventlistener(ev, function(e){if(callback){callback(e);}}, false);
180 }
181
182 }
183
184
185
186 /** 3d库
187 three.js --- version number 114
188 create scene
189 */
190 class three{
191
192 constructor(){
193 if (webgl.iswebglavailable() === false){
194 alert("你不支持webgl");
195 return;
196 }
197 this.view = new view();
198 three.cache.enabled = true;//加载器启用缓存
199 this.clock = new three.clock();//
200 this.group = new three.group();//创建一个 分组
201 this.textures = this.createtexture();//存放 纹理 的对象
202 }
203
204 //创建 场景
205 createscene(){
206 var scene = new three.scene();
207 //scene.fog = new three.fog(0xcce0ff, 800, 1000);//线性雾
208 scene.background = new three.cubetextureloader()
209 .setpath('img/cube/skyboxsun25deg/')
210 .load( [ 'px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg' ] );
211 if(this.group){scene.add(this.group);}
212 return scene;
213 }
214
215 //创建 相机
216 createcamera(){
217 var camera = new three.perspectivecamera(75, this.view.client.w/this.view.client.h, 1, 5000);
218 camera.position.set(0, 150, 300);//相机起始位置
219 return camera;
220 }
221
222 //创建 渲染器
223 createrenderer(){
224 var renderer = new three.webglrenderer({
225 antialias : true,//抗割齿
226 powerpreference:"high-performance"//选择高性能gpu渲染
227 });
228 renderer.setsize(this.view.client.w, this.view.client.h);//设置渲染大小
229 renderer.setpixelratio(window.devicepixelratio);//渲染矫正
230 renderer.gammafactor = 2.2;//着色校正
231 renderer.physicallycorrectlights = true;//使其精确照明
232 renderer.shadowmap.enabled = true;//渲染阴影
233 //renderer.autoclear = true;//每帧自动清理缓存
234 if(!renderer.extensions.get('webgl_depth_texture')){console.log("深度纹理扩展获取失败:webgl_depth_texture");}
235 document.body.appendchild(renderer.domelement);
236 renderer.domelement.style.zindex = "0";
237 renderer.domelement.style.position = "absolute";
238 renderer.domelement.style.top = "0px";
239 renderer.domelement.style.left = "0px";
240 return renderer;
241 }
242
243 //创建 灯光
244 createlight(scene){
245 scene.add(new three.ambientlight(0x696969));//环境光(无处不在的光,太阳光)
246 var l_d = 1000, light = new three.directionallight(0xf0f8ff, 1);//平行光(产生阴影的光)
247 light.position.set(-3000, 3000, -3000);
248 light.position.multiplyscalar(1);
249 //阴影
250 light.castshadow = true;
251 light.shadow.mapsize.width = 1024;
252 light.shadow.mapsize.height = 1024;
253 light.shadow.camera.left = -l_d;
254 light.shadow.camera.right = l_d;
255 light.shadow.camera.top = l_d;
256 light.shadow.camera.bottom = -l_d;
257 light.shadow.camera.near = 1;
258 light.shadow.camera.far = 6000;
259 scene.add(light);
260 return light;
261 }
262
263 //创建 控制器
264 createcontrol(camera, renderer){
265 var create = ()=>{
266 let control = new three.orbitcontrols(camera, renderer.domelement);
267 control.target = new three.vector3(0, 100, 0);//相机焦点
268 //control.minpolarangle = math.pi * 0.3;//向上最大角度
269 //control.maxpolarangle = math.pi * 0.4;//向下最大角度
270 control.mindistance = 1;//最小距离
271 control.maxdistance = 1000;//最大距离
272 control.autorotatespeed = 10;//自动旋转速度
273 control.panspeed = 100;//鼠标旋转速度
274 control.enablezoom = true;//是否启用缩放
275 control.enablekeys = true;//是否启用键盘
276 control.keypanspeed = 100;//按键速度
277 control.keys.left = 65;//key a左
278 control.keys.up = 87;//key w前
279 control.keys.right = 68;//key d右
280 control.keys.bottom = 83;//key s后
281 this.control = control;
282 }
283 loadfile("./js/lib/orbitcontrols.js", create);//加载 控制器 插件
284 }
285
286 //创建 动画循环
287 animate(scene, camera, renderer){
288 requestanimationframe(()=>{this.animate(scene, camera, renderer);});
289 if(this.control !== undefined && this.clock !== undefined){
290 this.control.update(this.clock.getdelta());//更新控制器
291 }
292 renderer.render(scene, camera);
293 }
294
295 //创建纹理
296 createtexture(){
297 var load = new three.textureloader();
298
299 var texture_ground = load.load("img/texture/ground.jpg");
300 texture_ground.wraps = texture_ground.wrapt = three.repeatwrapping;
301 texture_ground.repeat.set(20, 20);//x y 平铺次数
302 texture_ground.anisotropy = 2;//纹理的清晰度(值为2的幕:1, 2, 4, 8, ... 512, 1024, 2048, ...)
303
304 var texture_wall = load.load("img/texture/wall.jpg");
305 texture_wall.wraps = texture_wall.wrapt = three.repeatwrapping;
306 texture_wall.repeat.set(2.2, 2.2);
307 texture_wall.anisotropy = 1024;//贴图画质
308 texture_wall.minfilter = three.nearestfilter;//深度纹理贴图:
309 texture_wall.magfilter = three.nearestfilter;//深度纹理贴图:
310
311 var texture_gate = load.load("img/texture/gate.jpg");
312 texture_gate.wraps = texture_gate.wrapt = three.repeatwrapping;
313 texture_gate.repeat.set(0.03, 0.03);
314 texture_gate.anisotropy = 1024;
315
316 return {ground:texture_ground, wall:texture_wall, gate:texture_gate};
317 }
318
319 //创建地面 land
320 createground(group){
321 var gro = group || this.group, w = 10000, h = 10000;
322 //gro.add(new three.gridhelper(w, 100));//添加网格辅助线
323 var mesh = new three.mesh(//创建 物体
324 new three.planebuffergeometry(w, h), // geometry 几何体
325 new three.meshlambertmaterial({map:this.textures.ground}) // material 材质
326 );
327 mesh.receiveshadow = true;//接受阴影
328 mesh.rotation.x = -(math.pi*0.5);//旋转90度
329 mesh.matrixautoupdate = false;//不实时更新矩阵,提升性能
330 mesh.updatematrix();//更新一次矩阵, 让其旋转90度
331 gro.add(mesh);
332 return mesh;
333 }
334
335 //创建围墙
336 createwall(object){
337 var o = object || {};
338 var gro = o.group || this.group;
339 var w = 256, h = 256, d = 40;
340 var mesh = new three.mesh(
341 new three.boxbuffergeometry(w, h, d),
342 new three.meshlambertmaterial({map:this.textures.wall})
343 );
344 mesh.castshadow = true;//投射阴影
345 mesh.receiveshadow = true;//接收阴影
346 mesh.customdepthmaterial = new three.meshdepthmaterial({depthpacking: three.rgbadepthpacking});//添加阴影
347 if(o.issety === true){mesh.position.y = h / 2 + 1;}//调整坐标 y
348 mesh.matrixautoupdate = false;//不实时更新矩阵,提升性能
349 mesh.updatematrix();//更新一次矩阵
350 gro.add(mesh);
351 return mesh;
352 }
353
354 //创建一块 小钢门...
355 creategate(group){
356 var gro = group || this.group, w = 256, h = 256;
357 var shape = new three.shape(), w2 = w/2, h2 = h/2;
358 shape.moveto(-w2, h2); shape.lineto(w2, h2); shape.lineto(w2, -h2);
359 shape.lineto(-w2, -h2); shape.lineto(-w2, h2);
360 var geometry = new three.extrudebuffergeometry(shape, {
361 depth:0,
362 bevelthickness:2,
363 bevelsize:3,
364 bevelsegments:1
365 });
366 var material = new three.meshlambertmaterial({map:this.textures.gate});
367 var mesh = new three.mesh(geometry, [material, material]);
368 mesh.castshadow = true;
369 mesh.receiveshadow = true;
370 mesh.customdepthmaterial = new three.meshdepthmaterial({depthpacking: three.rgbadepthpacking});
371 mesh.position.set(300, h/2+1, 0);
372 gro.add(mesh);
373 return mesh;
374 }
375
376 }
展示:
three.js 版本号为 114 (需要 php 服务器环境才能运行, 如果此demo不能运行 或 有什么疑问 请联系我: 3247940050@qq.com)
完整代码: https://pan.baidu.com/s/1qvt50gecnb2wtr8dommwmw
提取码: 53i3
就爱读