//对于这一层中的每个room
19 {
20 var tds=trs[i].getElementsByTagName("td");
21 var int_room=parseInt(tds[7].innerHTML);
22 var arr_landtype={land_textblack:[0,0,0,255],land_textyellow:[255,255,0,255]}
23 // 保存在内存中的数据结构
24 // var obj=eval(tds[5].innerHTML);
25 var obj={};
26 eval("obj="+tds[5].innerHTML);
27 arr_floorroom[int_floor][int_room]={id:tds[0],beta:tds[1].innerHTML,pbeta:tds[2].innerHTML,alpha:tds[3].innerHTML
28 ,palpha:tds[4].innerHTML,weight:obj};
29 // 使用何种数据结构传递到显卡?使用一个超长数组arr_set4?《-这是不行的
30 var num1= 0,num2= 0,num3= 0,num4= 255;
31 for (key in obj)// 将每一种颜色的三个通道加权到一起
32 {
33 var num_key=obj[key];
34 num1+=(num_key*arr_landtype[key][0]);
35 num2+=(num_key*arr_landtype[key][1]);
36 num3+=(num_key*arr_landtype[key][2]);
37 }
38 var index= (int_floor+max_floor)*4*can_temp.width+(i-1)*4;// 每个room由4个元素组成
39 imagedata_temp.data[index]=num1;// 这里存的真的是颜色
40 imagedata_temp.data[index+1]=num2;
41 imagedata_temp.data[index+2]=num3;
42 imagedata_temp.data[index+3]=num4;
43 }
因为100km*100km的地区块在近距离视角下也是一个很大的区域,下一步计划在拉近视角时,在一个地区块中再生成更多种类的地形,所以所谓“地区块的地形”,其实是其内包含的各种地形的比例分配,在远处看时地区块的颜色是其包含的各种地形的加权。
这段测试里我使用了两种地形:纯黑色的land_textblack和黄色的land_textyellow,而两种地区块的地形则分别是百分之百的land_textblack和land_textyellow。颜色的加权值被放进了canvas的像素中。
d、绘制行星:
1 // 用glsl和Babylon.js结合的方式绘制行星
2 function DrawPlanet()
3 {
4 var amigaMaterial = new BABYLON.ShaderMaterial("amiga2", scene,{
5 vertexElement: "sh2v4.sh",
6 fragmentElement: "sh2f4.sh",
7 },
8 {
9 attributes: ["position"],
10 uniforms: ["worldViewProjection","worldView"]
11 });
12 amigaMaterial.doNotSerialize=true ;
13 sphere1.material=amigaMaterial;
14 if (strsrc_dqk=="")
15 {
16 context_temp.putImageData(imagedata_temp,0,0);
17 strsrc_dqk=can_temp.toDataURL("image/png");//将canvas转化为dataurl
18 localStorage.setItem("strsrc_dqk",JSON.stringify(strsrc_dqk));
19 }
20 var utexturedqk = new BABYLON.Texture.CreateFromBase64String(strsrc_dqk,"utexturedqk", scene
21 ,false ,false ,BABYLON.Texture.NEAREST_NEAREST);//将dataurl转化为Babylon.js纹理
22 amigaMaterial.setTexture("utexturedqk",utexturedqk);//将纹理和显卡采样器关联
23 amigaMaterial.setFloat("wid_utexturedqk",can_temp.width);// 数据纹理宽度,将内存中的变量和显卡中的通用变量关联
24 amigaMaterial.setFloat("hei_utexturedqk",can_temp.width);
25 amigaMaterial.setFloat("pbeta",pbeta);// 层间区分角度
26
27 var size=newland.FindPower2(arr_palpha.length);//注意!!!!
28 var strsrc_palpha=newland.TranArrToPng1(arr_palpha,size,size);// 每一层内的房间区分角度,用4个元素保存一个浮点数
29 var utexturepalpha = new BABYLON.Texture.CreateFromBase64String(strsrc_palpha,"utexturepalpha", scene
30 ,true ,false ,BABYLON.Texture.NEAREST_NEAREST);
31 amigaMaterial.setTexture("utexturepalpha",utexturepalpha);
32 amigaMaterial.setFloat("wid_utexturepalpha",size);// room区分度的纹理宽度
33 amigaMaterial.setFloat("hei_utexturepalpha",size);
34
35 amigaMaterial.setFloat("uarrpalphalen",arr_palpha.length);
36 amigaMaterial.setFloat("max_floorf",max_floor);// Babylon.js不支持传递整形量??GpenGL中int也是以float形式计算的!!!!
37 amigaMaterial.setFloat("MathPI",Math.PI);
38
39 amigaMaterial.onCompiled=function ()//Babylon.js 文档中写effect是material的一个内容,而material需要一个“编译过程”,编译之后的material才具备effect属性
40 {//而且对Babylon.js来说,material能传递的变量类型比较少,比如不能传递整形量,而effect则可以传递更多的数据类型
41 //amigaMaterial.getEffect().setArray("uarrpalpha",arr);//每一层水平区分度*/effect可以向显卡传递数组
//console.log(amigaMaterial.getEffect()); }
42 }
这里我们要考虑使用何种方式把长度为199的浮点型数组arr_palpha传入显卡,事实上OpenGL支持传入数组型通用变量,但对数组的支持分成两种:一种是我们前面看到的vec3、vec4这类向量数组,glsl把整个向量看做一个变量,而另一种类似“uniform float uarrpalpha[500]”的自定义数组则是把数组中的每一个元素都看做一个uniform变量处理!(?)。
根据StackOverFlow上一个外国同行的试验,OpenGL最多只能支持200个左右的uniform变量(?),这意味着我们难以直接用数组的方式传入arr_palpha。另外在WebGL1.0中的glsl不支持不定长度的数组,这意味着我们必须在编写着色器代码前对数组的大小有恰当的估计,或者根据行星的大小临时调节着色器代码。
在glsl中使用长数组的另一个问题是:glsl竟然不支持直接用临时赋值的变量作为数组索引!类似
1 int i=1 ;
2 float f=arr[i+1 ];
这种数组用法是不允许的!!!!
要将计算结果作为数组的索引只能使用if else或者switch case枚举出每一种对应的情况,或者使用:
1 float getData500(float data[500 ],int id) {
2 int len=int (floor(uarrpalphalen+0.5 ));
3 for (int i=0 ; i<500 ; i++) {
4 if (i>=len)// i不能和非常量比较!!只好换个方式限制它
5 {
6 return 0.0 ;
7 }
8 if (i == id) return data[i];
9 }
10 }
其中id是计算出来的索引,另外glsl的for循环的中段也不支持“i
因此改为使用datatexture传递水平区分度数组
然而使用datatexture时又遇到一个问题,canvas会自动把颜色分量转化为0到255的整数,而这里的水平区分度全是0到1之间的小数,会被自动转为0或1,为解决这一问题把水平区分度数据转化为科学计数法并用像素表示:
1 // 将一个浮点数组转化为DataTexture,这是浮点数小于1的情况,要注意canvas和webgl对颜色属性的自动处理!!!!
2 newland.TranArrToPng1=function (arr,width,height)
3 {
4 var can_temp=document.createElement("canvas");
5 can_temp.width=width;
6 can_temp.height=height;
7 var context=can_temp.getContext("2d");
8 context.fillStyle="rgba(0,0,255,1)";// 多余的位都是1?
9 context.fillRect(0,0,width,height);
10 var imagedata=context.getImageData(0,0,width,height);
11 var len=arr.length;// 小数部分会自动四舍五入!!!!默认palpha必定小于1
12 for (var i=0;i13 {
14 var str_num=arr[i]+"";
15 // var int_0=str_num.indexOf();
16 var len_str=str_num.length;
17 var count_0=0;
18 for (var j=0;j)
19 {
20 if (str_num[j]=="0"||str_num[j]==".")
21 {
22 continue ;
23 }
24 else
25 {
26 count_0=j;// 找到第一个非零数
27 break ;
28 }
29 }
30 var num1=parseInt(str_num.substr(count_0,2));
31 var num2=parseInt(str_num.substr(count_0+2,2));
32 // var num3=parseInt(str_num.substr(count_0+4,2));
33 var num4=4+(count_0-2);
34 imagedata.data[i*4]=num1;//科学计数法:用像素颜色的第一第二个分量保存四位有效数字,用第四个分量保存10的负指数
35 imagedata.data[i*4+1]=num2;
36 imagedata.data[i*4+2]=num4;
37 // imagedata.data[i*4+3]=num4;
38 }
39 context.putImageData(imagedata,0,0);
40 var strsrc_palpha=can_temp.toDataURL("image/png");
41 // can_temp.dispose();
42 can_temp=null ;
43 return strsrc_palpha;
44 }
执行程序,看到运行效果与设计有所偏差:
南半球的黑色地区块少了很多行,没有形成预计的棋盘形,时间有限没有详细调试
拉近相机:
可以看到每个地区块的边界清晰可见,没有发生模糊。
使用console.log输出用到的两个dataurl作为参考:
4、着色器代码:
a、顶点着色器:
1 uniform mat4 worldViewProjection;
2 uniform mat4 worldView;
3 attribute vec3 position;
4
5 varying vec3 vPosition;
6 varying vec3 oPosition;// 自身坐标系里的位置
7
8 void main(){
9 gl_Position=worldViewProjection*vec4(position,1 );
10 vPosition=vec3(worldView*vec4(position,1 ));
11 oPosition=position;
12 }
我们前面生成地形的计算都是在行星的自身坐标系里进行的,所以在片元着色器里也需要以行星的自身坐标系为参考确定地区块的层数和房间号,所以把一个不经过任何矩阵变换的顶点位置信息传入片元着色器。
b、片元着色器:
1 precision highp float ;
2 // varying vec4 vColor;
3 varying vec3 vPosition;
4 varying vec3 oPosition;
5 // uniform vec4 uColor;
6 uniform sampler2D utexturedqk;//地区块数据纹理的采样器
7 uniform float wid_utexturedqk;//数据纹理的宽高
8 uniform float hei_utexturedqk;
9
10 uniform sampler2D utexturepalpha;// 一个单元里保存了四个元素!!!!
11 // uniform vec3 uarrdqk[60000]; // es3.0之前的glsles不支持隐含数组!!!!
12 uniform float pbeta;
13 uniform float wid_utexturepalpha;
14 uniform float hei_utexturepalpha;
15 // uniform float uarrpalpha[500]; // 用来测试的行星只有199层,预设为500层应该够了
16 uniform float uarrpalphalen;
17 uniform float max_floorf;
18 uniform float MathPI;
19
20 float getDataVec4(vec4 data,int id) {
21 for (int i=0 ; i<4 ; i++) {
22 if (i == id) return data[i];
23 }
24 }
25 float getData500(float data[500 ],int id) {
26 int len=int (floor(uarrpalphalen+0.5 ));
27 for (int i=0 ; i<500 ; i++) {
28 if (i>=len)// i不能和非常量比较!!只好换个方式限制它
29 {
30 return 0.0 ;
31 }
32 if (i == id) return data[i];
33 }
34 }
35
36 void main()
37 {
38 // vec4 tempColor=uColor; // es3.0之前不支持round!!!!
39 // glsl事实上以float为计算基准
40 // int max_floor=int(floor(max_floorf+0.5));
41 // 算层数
42 float r=sqrt(oPosition.x*oPosition.x+oPosition.y*oPosition.y+oPosition.z*oPosition.z);//这个片元到球心的距离
43 float beta=asin(oPosition.y/r);// 俯仰角
44 // int int_beta=int(floor((beta/(pbeta*2.0))+0.5));
45 float count_beta=(beta/(pbeta*2.0 ));
46 // int index_beta=int(floor(count_beta+ max_floorf+0.5));
47 float index_beta=floor(count_beta+ max_floorf+0.5 );//第几层
48 // int roomcount=0;
49 // 使用数据纹理法,取这一层的区分度
50 // int int1=int(floor(mod(index_beta,4.0)+0.5)); 51 // float float1=(index_beta/4.0);
52 float floatu=(mod(index_beta,wid_utexturepalpha))/(wid_utexturepalpha)+(0.5 /wid_utexturepalpha);// u是x轴坐标,v是y轴坐标
53 float floatv=(((index_beta)/(wid_utexturepalpha)))/(hei_utexturepalpha)+(0.5 /(wid_utexturepalpha*hei_utexturepalpha));
54 vec2 UVpalpha=vec2(floatu,floatv);//上面计算的uv坐标加了一个偏移量,防止坐标正好落在两个像素的边界上
55 vec4 vec4palphas=texture2D(utexturepalpha, UVpalpha);//glsl中的颜色为0到1.0,所以要乘以255.0获得传入的科学计数法
56 float palpha=(vec4palphas[0 ]*255.0 *100.0 +vec4palphas[1 ]*255.0 )/pow(10.0 ,vec4palphas[2 ]*255.0 );
57 // float palpha=getData500(uarrpalpha,int(floor(index_beta+0.5))); // 改为尝试数组法传递数据
58 // 取这一层的转角
59 float alpha=atan(oPosition.z,oPosition.x);// 标准反正切函数有两个参数!!
60 if (alpha<0.0 )
61 {
62 alpha+=(MathPI*2.0 );
63 }
64 // 取地区块数据纹理的坐标
65 float floatu2=(alpha/(palpha*2.0 ))/wid_utexturedqk;
66 float floatv2=index_beta/hei_utexturedqk+0.5 /hei_utexturedqk;
67 vec2 UVdqk=vec2(floatu2,floatv2);
68 gl_FragColor=texture2D(utexturedqk, UVdqk);
69 // gl_FragColor=vec4palphas;
70 // gl_FragColor=texelFetch(utexturedqk,ivec2(int(floor(alpha/(palpha*2.0)+0.5)),int(floor(index_beta+0.5))),0); // 这个整数像素的方法是WebGL2开始加入的!!!!
71 // gl_FragColor=vec4(1.0*floatu,1.0*floatv,1.0*floatv2,1.0); // 红,绿,蓝结果不是0就是1??!!
72
73 // int index_dqk=roomcount-1+int(floor((alpha/palpha)+0.5));
74 // vec4 tempColor=vec4(uarrdqk[index_dqk],1.0);
75
76 // float float_3=index_beta/(max_floorf*2.0);
77 // float float_4=oPosition.y/5.0;
78 // canvas的imagedata用255,255,255,255定义颜色通道,而glsl用1.0,1.0,1.0,1.0定义!!!!
79
80
81 }
glsl语言不支持字符串类型,WebGL1.0也不支持从显卡反写数据到内存,一种可行的调试方法是将某个计算结果转化为颜色显示在屏幕上,然后用拾色器提取值。
四、根据规则生成随机的行星表面地形(testarenas.html)
1、生成地区块的基本数据结构:
1 function CookDqk()// 生成地区块,每一floor的每个room
2 {
3 var size_dqk=100;// 每个地区块的长宽都是100km
4 var r_planet=perimeter/(2*Math.PI);//行星的半径
5 var len_beta=sswr(((perimeter/2)/size_dqk)/2);//通过弧度来分层!!100
6 pbeta=(Math.PI/4)/len_beta;
7 // 对于每一层,
8 for (var i=-len_beta;i<=len_beta;i++)
9 {
10
11 var rad_beta=(Math.PI/2)*(i/len_beta);
12 var r_floor=Math.cos(rad_beta)*r_planet;// 这一层的半径
13 var len_alpha_floor=sswr((r_floor*2*Math.PI)/size_dqk);
14 var palpha=Math.PI/len_alpha_floor;//每一个地区块的角度边界,在这个边界范围内即属于这个地区块
15 arr_palpha.push(palpha);
16 var beta=i*pbeta*2;
17 // console.log(i+"/"+len_beta+">"+len_alpha_floor);
18 var arr1=[];
19 // 对于圆环上的每一个片
20 for (var j=0;j)
21 {
22 var obj={};
23 obj.palpha=palpha;
24 obj.alpha=j*palpha*2;
25 obj.pbeta=pbeta;
26 obj.beta=beta;
27 // obj.weight={};
28 obj.floor=i;
29 obj.room=j;
30 obj.countcook=0;
31 obj.altitude=0;
32
33 arr1.push(obj);
34
35 }
36 if (arr1.length>0)
37 {
38 arr_floorroom.push(arr1);
39 }
40
41 }
42 CookDqk2();// 对生成的数据结构进行 规律随机填充
43 }
View Code
2、使用正态随机数与加和平均确定每个地区块的海拔
1 // 使用正态随机数和加和平均确定每个地区块的海拔
2 function CookDqk2()
3 {
4 var len=arr_floorroom.length;
5 // 生成初始的随机正态随机海拔
6 console.log("生成初始的随机正态随机海拔");
7 for (var i=0;i)
8 {
9 // console.log(i+" in "+len);
10 var len2=arr_floorroom[i].length;
11 for (var j=0;j)
12 {
13 var obj=arr_floorroom[i][j];
14 obj.altitude=dc1.getNumberInNormalDistribution(-10,1000);// 平均海拔是-10,常见的海拔在正负1000以内
15 if (obj.altitude<-10000)
16 {
17 obj.altitude=-10000;
18 }
19 else if (obj.altitude>10000)
20 {
21 obj.altitude=10000;
22 }
23 obj.countcook=1;
24 if (i%2==1)// 如果是奇数层,room偏移一个识别范围,这样地形看起来更自然
25 {
26 obj.alpha+=obj.palpha;
27 }
28 }
29 }
30 // 使用加和平均方法使海拔趋于连续(高度平滑)
31 console.log("使用加和平均方法使海拔趋于连续");
32 for (var i=0;i)//将地区块的海拔和周围相邻的所有地区块的海拔相加取平均值,作为这个地区块的海拔
33 {
34 console.log(i+" in "+len);
35 var len2=arr_floorroom[i].length;
36 for (var j=0;j)
37 {
38 var obj=arr_floorroom[i][j];
39 obj.altitude1=obj.altitude;
40 if (i>0)// 考虑这个room下面的floor
41 {
42 // var alpha=obj.alpha;
43 var len3=arr_floorroom[i-1].length;
44 for (var k=0;k//遍历下层的room
45 {
46 var subplpha=Math.abs(arr_floorroom[i-1][k].alpha-obj.alpha);
47 if (subplpha>Math.PI)
48 {
49 subplpha=Math.PI*2-subplpha;
50 }
51 if (subplpha<=(obj.palpha+arr_floorroom[i-1][k].palpha))
52 {// 对这个地区块有影响
53 obj.altitude1+=arr_floorroom[i-1][k].altitude;
54 obj.countcook++;
55 }
56 }
57
58 }
59 if (i//考虑这个room上面的floor
60 {
61 var len3=arr_floorroom[i+1].length;
62 for (var k=0;k//遍历上层的room
63 {
64 var subplpha=Math.abs(arr_floorroom[i+1][k].alpha-obj.alpha);
65 if (subplpha>Math.PI)
66 {
67 subplpha=Math.PI*2-subplpha;
68 }
69 if (subplpha<=(obj.palpha+arr_floorroom[i+1][k].palpha))
70 {// 对这个地区块有影响
71 obj.altitude1+=arr_floorroom[i+1][k].altitude;
72 obj.countcook++;
73 }
74 }
75 }
76 // 考虑本层的相邻元素
77 if (j==0)
78 {
79 obj.altitude1+=arr_floorroom[i][1].altitude;
80 obj.altitude1+=arr_floorroom[i][len2-1].altitude;
81 obj.countcook+=2;
82 }else if (j==(len2-1))
83 {
84 obj.altitude1+=arr_floorroom[i][0].altitude;
85 obj.altitude1+=arr_floorroom[i][len2-2].altitude;
86 obj.countcook+=2;
87 }
88 else {
89 obj.altitude1+=arr_floorroom[i][j-1].altitude;
90 obj.altitude1+=arr_floorroom[i][j+1].altitude;
91 obj.countcook+=2;
92 }
93 }
94 }
95 var min_altitude= 0,max_altitude=0;
96 console.log("去除总权值");
97 for (var i=0;i)
98 {
99 console.log(i+" in "+len);
100 var len2=arr_floorroom[i].length;
101 for (var j=0;j)
102 {
103 var obj=arr_floorroom[i][j];
104 obj.altitude=obj.altitude1/obj.countcook;
105 if (obj.altitude<min_altitude)
106 {
107 min_altitude=obj.altitude;
108 }
109 if (obj.altitude>max_altitude)
110 {
111 max_altitude=obj.altitude;
112 }
113 // delete obj.altitude1;
114 }
115 }
116 console.log("最低、最高海拔为:"+min_altitude+"、"+max_altitude);
117 // 根据海拔高度与概率规则确定海洋与陆地,根据纬度和高度确定陆地的类型(高度达到一定程度后优于纬度)
118 CookDqk3();
119 }
关于正态随机数的知识可以参考这篇文章:https://www.cnblogs.com/zztt/p/4025207.html
3、根据海拔高度和纬度确定地形:
1 function CookDqk3()
2 {
3 console.log("开始生成地区块级地形");
4 var len=arr_floorroom.length;
5 for (var i=0;i) {
6 console.log(i+" in "+len);
7 var len2 = arr_floorroom[i].length;
8 for (var j = 0; j < len2; j++)
9 {
10 var obj=arr_floorroom[i][j];
11 getLandtypeDqk(obj);//根据规则确定这个地区块的地形
12 }
13 }
14 // 地区块平滑
15 console.log("地区块平滑");
16 for (var i=0;i)
17 {
18 console.log(i+" in "+len);
19 var len2=arr_floorroom[i].length;
20 for (var j=0;j)
21 {
22 var obj=arr_floorroom[i][j];
23
24 if (i>0)// 考虑这个room下面的floor
25 {
26 // var alpha=obj.alpha;
27 var len3=arr_floorroom[i-1].length;
28 for (var k=0;k//遍历下层的room
29 {
30 var obj1=arr_floorroom[i-1][k];
31 var subplpha=Math.abs(obj1.alpha-obj.alpha);
32 if (subplpha>Math.PI)
33 {
34 subplpha=Math.PI*2-subplpha;
35 }
36 if (subplpha<=(obj.palpha+obj1.palpha))
37 {// 对这个地区块有影响
38 if (!obj.landtypedqk[obj1.type2])
39 {
40 obj.landtypedqk[obj1.type2]=obj1.effect;//这一种地形的权重
41 }
42 else
43 {
44 obj.landtypedqk[obj1.type2]+=obj1.effect;
45 }
46 obj.landtypedqkeffect+=obj1.effect;//所有地形的权重
47 }
48 }
49
50 }
51 if (i//考虑这个room上面的floor
52 {
53 var len3=arr_floorroom[i+1].length;
54 for (var k=0;k//遍历上层的room
55 {
56 var obj1=arr_floorroom[i+1][k];
57 var subplpha=Math.abs(obj1.alpha-obj.alpha);
58 if (subplpha>Math.PI)
59 {
60 subplpha=Math.PI*2-subplpha;
61 }
62 if (subplpha<=(obj.palpha+obj1.palpha))
63 {// 对这个地区块有影响
64 if (!obj.landtypedqk[obj1.type2])
65 {
66 obj.landtypedqk[obj1.type2]=obj1.effect;
67 }
68 else
69 {
70 obj.landtypedqk[obj1.type2]+=obj1.effect;
71 }
72 obj.landtypedqkeffect+=obj1.effect;
73 }
74 }
75 }
76 // 考虑本层的相邻元素
77 if (j==0)
78 {
79 var obj1=arr_floorroom[i][1];
80 if (!obj.landtypedqk[obj1.type2])
81 {
82 obj.landtypedqk[obj1.type2]=obj1.effect;
83 }
84 else
85 {
86 obj.landtypedqk[obj1.type2]+=obj1.effect;
87 }
88 obj.landtypedqkeffect+=obj1.effect;
89 var obj1=arr_floorroom[i][len2-1];
90 if (!obj.landtypedqk[obj1.type2])
91 {
92 obj.landtypedqk[obj1.type2]=obj1.effect;
93 }
94 else
95 {
96 obj.landtypedqk[obj1.type2]+=obj1.effect;
97 }
98 obj.landtypedqkeffect+=obj1.effect;
99 }
100 else if (j==(len2-1))
101 {
102 var obj1=arr_floorroom[i][0];
103 if (!obj.landtypedqk[obj1.type2])
104 {
105 obj.landtypedqk[obj1.type2]=obj1.effect;
106 }
107 else
108 {
109 obj.landtypedqk[obj1.type2]+=obj1.effect;
110 }
111 obj.landtypedqkeffect+=obj1.effect;
112 var obj1=arr_floorroom[i][len2-2];
113 if (!obj.landtypedqk[obj1.type2])
114 {
115 obj.landtypedqk[obj1.type2]=obj1.effect;
116 }
117 else
118 {
119 obj.landtypedqk[obj1.type2]+=obj1.effect;
120 }
121 obj.landtypedqkeffect+=obj1.effect;
122 }
123 else {
124 var obj1=arr_floorroom[i][j-1];
125 if (!obj.landtypedqk[obj1.type2])
126 {
127 obj.landtypedqk[obj1.type2]=obj1.effect;
128 }
129 else
130 {
131 obj.landtypedqk[obj1.type2]+=obj1.effect;
132 }
133 obj.landtypedqkeffect+=obj1.effect;
134 var obj1=arr_floorroom[i][j+1];
135 if (!obj.landtypedqk[obj1.type2])
136 {
137 obj.landtypedqk[obj1.type2]=obj1.effect;
138 }
139 else
140 {
141 obj.landtypedqk[obj1.type2]+=obj1.effect;
142 }
143 obj.landtypedqkeffect+=obj1.effect;
144 }
145 }
146 }
147 console.log("对每个地区块进行加权并入库");
148 for (var i=0;i//对每个地区块进行加权,这段代码执行很慢
149 {
150 var len2=arr_floorroom[i].length;
151 console.log(i+" in "+len);
152 for (var j=0;j)
153 {
154
155 var obj=arr_floorroom[i][j];
156 obj.altitude=obj.altitude/obj.countcook;
157 var rate_type1final=Math.random()*obj.landtypedqkeffect;
158 var rate_type1final_count=0;
159 obj.type2final="默认dqk";
160 for (key in obj.landtypedqk)
161 {
162 rate_type1final_count+=obj.landtypedqk[key];// 这一种地形的权重
163 if (rate_type1final<rate_type1final_count)//如果随机数小于这种地形的累积权重
164 {
165 obj.type2final=key;
166 break ;
167 }
168 }
169 // 在这里把这个地区块插入数据库?不知道什么原因POST方法失败了,改用GET方法
170 /* Url="http://127.0.0.1:8082/query.do?jsessionid="+jsessionid;
171 Argv="sql=insert into tab_dqk values(uuid(),'test1',"+obj.beta+","+obj.pbeta+","+obj.alpha+","+obj.palpha+",'"
172 +obj.type2final+"',"+obj.floor+","+obj.room+","+obj.altitude+")";
173 //使用同步Ajax请求保证进度同步,在连续使用同步Ajax时不需要xmlHttp.abort()!!!!
174 Request(xmlHttp,"POST",Url,false,Argv,"application/x-www-form-urlencoded",PushChessCallBack,0); */
175 Url="http://127.0.0.1:8082/query.do?jsessionid="+jsessionid+"&sql=insert into tab_dqk values(uuid(),'test1',"+obj.beta+","+obj.pbeta+","+obj.alpha+","+obj.palpha+",'"
176 +obj.type2final+"',"+obj.floor+","+obj.room+","+obj.altitude+")"
177 Argv="";
178 Request(xmlHttp,"GET",Url,false ,Argv,"application/x-www-form-urlencoded",PushChessCallBack,0);
179 }//这里改变了一下数据结构,直接用weight字段存储确定了的地区块级地形
180 }
181 CookDqk4();// 着色
182 }
getLandtypeDqk是根据海拔和纬度确定地形的方法:(这个方法效率很低)
1 function getLandtypeDqk(obj)
2 {
3 var height=obj.altitude;// 对于这个地区块
4 var beta=obj.beta;
5 var rate_land=Math.random();
6 for (key in tab_landtypedqk)// 这个方法并不能保证顺序!!!!//for key和eval占用了大量时间????
7 {// 按顺序查找每一个地区块级地形是否符合条件,
8 if (eval(tab_landtypedqk[key].eval))//JavaScript语言的一大特点是可以随时把字符串转化为可执行代码,
9 {//这使得JavaScript语言可以非常灵活,但是会降低执行效率和安全性
10 obj.type1=key;
11 var count_rate=0;// 用来累加概率
12 var obj1=tab_landtypedqk[key];
13 for (key2 in obj1)
14 {
15 if (key2!="eval")
16 {
17 var rate_type2=Math.random();
18 count_rate+=obj1[key2].rate;
19 if (rate_type2<count_rate)
20 {
21 obj.type2=key2;
22 obj.effect=obj1[key2].effect;// 对周边地块的影响程度
23 break ;
24 }
25 }
26 }
27 break ;
28 }
29 }
30 if (!obj.type1)// 如果这个地区块没有被分配地形
31 {
32 obj.type1="未定义";
33 obj.type2="默认dqk";
34 obj.effect=0;
35 }
36 obj.landtypedqk={};//这三个变量用于对地形进行平滑处理
37 obj.landtypedqk[obj.type2]=obj.effect;
38 obj.landtypedqkeffect=obj.effect;
39 }
在同一海拔和纬度可能有多种地形存在,每一种地形都有一个出现概率,取一个随机数,如果这个随机数小于遍历到这个地形时的概率累积,则将这个地区块设为这种地形。
每一种地形还有一个effect属性,表示这种地形对周边地形的影响能力,比如如果一片热带雨林周围全被沙漠包围,那么这片雨林有很大可能变成沙漠。
海拔和纬度与地形的对应关系设定如下:(tab_datalib.js)
1 // 地区块地形元素分布表
2 var beta_2326=((23+26/60)/180)*Math.PI;// 南北回归线弧度
3 var beta_6034=((60+34/60)/180)*Math.PI;// 南北极圈弧度
4 var beta_8=((8)/180)*Math.PI;//赤道附近弧度
5 var tab_landtypedqk={// rate按从小到大排列生成的随机数小于哪个就定为何种地形,effect在卷积平滑阶段起作用,表示这个地形对周围环境的影响程度
6 "热带海洋":{eval:"height<0&&rate_land<0.9&&Math.abs(beta)//eval是判断地区块大类型的判断条件,以后在设计技能效果时也可能要借鉴这里
7 "温带海洋":{eval:"height<0&&rate_land<0.9&&Math.abs(beta)>beta_2326&&Math.abs(beta)}},
8 "寒带海洋":{eval:"height<0&&rate_land<0.9&&Math.abs(beta)>beta_6034","寒带海洋dqk":{rate:1,effect:1}},
9 "温带1500米以下":{eval:"rate_land>0.1&&Math.abs(beta)>beta_2326&&Math.abs(beta)}},
10 "温带1500米以上":{eval:"rate_land>0.1&&Math.abs(beta)>beta_2326&&Math.abs(beta)=1500","雪山dqk":{rate:1,effect:1}},
11 "亚热带3000米以下":{eval:"rate_land>0.1&&Math.abs(beta)>beta_8&&Math.abs(beta)}},
12 "亚热带3000米以上":{eval:"rate_land>0.1&&Math.abs(beta)>beta_8&&Math.abs(beta)=3000","雪山dqk":{rate:1,effect:1}},
13 "热带3000米以下":{eval:"rate_land>0.1&&Math.abs(beta)}},
14 "热带3000米以上":{eval:"rate_land>0.1&&Math.abs(beta)=3000","雪山dqk":{rate:1,effect:1}},
15 "寒带-100米以下":{eval:"rate_land>0.1&&Math.abs(beta)>beta_6034&&height<-100","草原dqk":{rate:0.4,effect:1},"森林dqk":{rate:0.4,effect:1},"戈壁dqk":{rate:0.2,effect:2}},
16 "寒带-100到200米以内":{eval:"rate_land>0.1&&Math.abs(beta)>beta_6034&&height<200&&height>=-100","寒带森林dqk":{rate:0.6,effect:1},"冰川dqk":{rate:0.4,effect:1}},
17 "寒带200米以上":{eval:"rate_land>0.1&&Math.abs(beta)>beta_6034&&height>200","冰川dqk":{rate:1,effect:1}}
18 }
19 var tab_landtypedqk2={// 每一种地区块的远观颜色和内部地貌块(单位块?)占比
20 "默认dqk":{color:[250,126,126],content:{"红白格dmk":{rate:1,effect:0}}},// 完全红白格,这种表示错误和未定义的地貌块不会影响周围
21 "热带海洋dqk":{color:[15,63,105],content:{"海洋水面dmk":{rate:0.99,effect:1},"雨林dmk":{rate:0.995,effect:0},"沙滩dmk":{rate:1,effect:0}}},
22 "温带海洋dqk":{color:[15,63,105],content:{"海洋水面dmk":{rate:0.99,effect:1},"森林dmk":{rate:0.995,effect:0},"沙滩dmk":{rate:1,effect:0}}},
23 "寒带海洋dqk":{color:[15,63,105],content:{"海洋水面dmk":{rate:0.5,effect:1},"冰面dmk":{rate:1,effect:1}}},
24 "草原dqk":{color:[93, 153, 63],content:{"草地dmk":{rate:0.95,effect:1},"内陆水面dmk":{rate:1,effect:1}}},
25 "森林dqk":{color:[33,68,44],content:{"森林dmk":{rate:0.95,effect:1},"内陆水面dmk":{rate:1,effect:1}}},
26 "戈壁dqk":{color:[127, 102, 79],content:{"戈壁dmk":{rate:1,effect:1}}},
27 "雪山dqk":{color:[220, 221, 220],content:{"雪地dmk":{rate:0.8,effect:1},"岩石dmk":{rate:1,effect:0}}},
28 "热带雨林dqk":{color:[33,68,44],content:{"雨林dmk":{rate:0.95,effect:1},"内陆水面dmk":{rate:1,effect:1}}},
29 "稀树草原dqk":{color:[117, 118, 68],content:{"稀树草原dmk":{rate:0.95,effect:1},"内陆水面dmk":{rate:1,effect:1}}},
30 "沙漠dqk":{color:[175, 117, 68],content:{"沙地dmk":{rate:0.99,effect:1},"内陆水面dmk":{rate:0.995,effect:0},"绿洲dmk":{rate:1,effect:0}}},
31 "寒带森林dqk":{color:[],content:{"寒带森林dmk":{rate:0.85,effect:1},"雪地dmk":{rate:1,effect:1}}},
32 "冰川dqk":{color:[201, 216, 220],content:{"冰面dmk":{rate:0.85,effect:1},"雪地dmk":{rate:1,effect:1}}}
33 }
34 var tab_landtypedmk={// 每一种地貌块的纹理url
35 "红白格dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/amiga.jpg",color:[250,126,126]},// 对单位的影响,纹理Url,纹理的平均颜色
36 "海洋水面dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/sea.png",color:[15,63,105]},
37 "雨林dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/yulin.png",color:[33,68,44]},
38 "沙滩dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/shatan.png",color:[205, 160, 109]},
39 "森林dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/yulin.png",color:[33,68,44]},// 没找到温带森林,暂时用雨林代替
40 "冰面dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/ice.png",color:[201, 216, 220]},
41 "草地dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/grass.png",color:[93, 153, 63]},
42 "内陆水面dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/lake.png",color:[93,143,180]},
43 "戈壁dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/gebi.png",color:[127, 102, 79]},
44 "雪地dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/snow.png",color:[220, 221, 220]},
45 "岩石dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/stone.png",color:[82, 81, 74]},
46 "稀树草原dmk":{eval_effect:"../../ASSETS/IMAGE/Texture_landtypedmk/xishucaoyuan.png",Url:"",color:[117, 118, 68]},
47 "沙地dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/sand.png",color:[175, 117, 68]},
48 "绿洲dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/lvzhou.png",color:[127, 144, 111]},
49 "寒带森林dmk":{eval_effect:"",Url:"../../ASSETS/IMAGE/Texture_landtypedmk/lvzhou.png",color:[127, 144, 111]}
50
51 }
这里设定每一个100km*100km的地区块可以由更小的“地貌块”组成,在极近时地貌块的地形显示为实际的纹理图,在较远时地貌块表现为纹理图的平均色,在更远一些时用地区块代替地貌块,地区块的颜色为地貌块的加权。
目前这个切换功能还未编写,因为时间有限实际地形纹理也没有仔细设置,地区块的颜色加权也没做,直接使用了占比较多的地貌块颜色。
提取纹理图平均颜色的代码如下:(testpix.html)
1 DOCTYPE html >
2 < html lang ="en" >
3 < head >
4 < meta charset ="UTF-8" >
5 < title > 提取一副固定大小图片的平均颜色color4title >
6 head >
7 < body >
8 < div id ="div_allbase" >
9 < canvas style ="width: 512px;height: 512px" width ="512" height ="512" id ="can_pic" >
10
11 canvas >
12 div >
13 body >
14 < script >
15 var canvas = document.getElementById( " can_pic " );
16 window.onload = loadImage;
17 function loadImage()
18 {
19 var context = canvas.getContext( " 2d " );
20 var img = document.createElement( " img " );
21 img.src = " ../../ASSETS/IMAGE/Texture_landtypedmk/lvzhou.png " ;
22 img.onload = function ()
23 { // 在图片加载完毕后才可以在canvas里绘制
24 context.drawImage(img, 0 , 0 );
25 var imagedata_temp = context.getImageData( 0 , 0 , 512 , 512 ); // 规定地貌块纹理图片的宽高是512
26 var data = imagedata_temp.data;
27 var len = data.length;
28 var color4 = [ 0 , 0 , 0 , 0 ];
29 for ( var i = 0 ;i < len;i += 4 )
30 {
31 color4[ 0 ] += data[i];
32 color4[ 1 ] += data[i + 1 ];
33 color4[ 2 ] += data[i + 2 ];
34 color4[ 3 ] += data[i + 3 ];
35 }
36 var int = 512 * 512 ;
37 color4[ 0 ] = Math.round(color4[ 0 ] / int);
38 color4[ 1 ] = Math.round(color4[ 1 ] / int);
39 color4[ 2 ] = Math.round(color4[ 2 ] / int);
40 color4[ 3 ] = Math.round(color4[ 3 ] / int);
41 console.log(color4);
42 }
43
44 }
45 script >
46 html >
View Code
4、生成数据纹理
1 function CookDqk4()
2 {
3 var len=arr_floorroom.length;
4 // 开始生成数据纹理
5 console.log("开始生成数据纹理");
6 for (var i=0;i//每一行
7 {
8 // console.log(i+" in "+len);
9 var len2 = arr_floorroom[i].length;
10 for (var j = 0; j < len2; j++) {
11 var obj = arr_floorroom[i][j];
12 var index= (i)*4*can_temp.width+(j-1)*4;// 每个room由4个元素组成
13 var color4=[];
14 if (tab_landtypedqk2[obj.type2final].color)
15 {//从地形对象中获取颜色
16 color4=tab_landtypedqk2[obj.type2final].color;
17 }
18 else
19 {
20 color4=[250,126,126];// 默认纹理远观颜色
21 }
22 imagedata_temp.data[index]=color4[0];// 这里存的真的是颜色
23 imagedata_temp.data[index+1]=color4[1];
24 imagedata_temp.data[index+2]=color4[2];
25 imagedata_temp.data[index+3]=255;
26
27 }
28 }
29
30 }
然后用和前面类似的方式将数据纹理送入显卡并进行渲染
着色器代码如下:
顶点着色器:
1 uniform mat4 worldViewProjection;
2 uniform mat4 worldView;
3 attribute vec3 position;
4
5 varying vec3 vPosition;
6 varying vec3 oPosition;// 自身坐标系里的位置
7
8 void main(){
9 gl_Position=worldViewProjection*vec4(position,1 );
10 vPosition=vec3(worldView*vec4(position,1 ));
11 oPosition=position;
12 }
View Code
片元着色器:
1 precision highp float ;
2 // varying vec4 vColor;
3 varying vec3 vPosition;
4 varying vec3 oPosition;
5 // uniform vec4 uColor;
6 uniform sampler2D utexturedqk;
7 uniform float wid_utexturedqk;
8 uniform float hei_utexturedqk;
9
10 uniform sampler2D utexturepalpha;// 一个单元里保存了四个元素!!!!
11 // uniform vec3 uarrdqk[60000]; // es3.0之前的glsles不支持隐含数组!!!!
12 uniform float pbeta;
13 uniform float wid_utexturepalpha;
14 uniform float hei_utexturepalpha;
15 // uniform float uarrpalpha[500]; // 用来测试的行星只有199层,预设为500层应该够了
16 uniform float uarrpalphalen;
17 uniform float max_floorf;
18 uniform float MathPI;
19
20 float getDataVec4(vec4 data,int id) {
21 for (int i=0 ; i<4 ; i++) {
22 if (i == id) return data[i];
23 }
24 }
25 float getData500(float data[500 ],int id) {
26 int len=int (floor(uarrpalphalen+0.5 ));
27 for (int i=0 ; i<500 ; i++) {
28 if (i>=len)// i不能和非常量比较!!只好换个方式限制它
29 {
30 return 0.0 ;
31 }
32 if (i == id) return data[i];
33 }
34 }
35 float getOdevity(float a)// 判断浮点型整数的奇偶性,偶返回0,奇返回1
36 {
37 float b=mod(a,2.0 );
38 float c=0.0 ;
39 if (b>=0.5 &&b<1.5 )
40 {
41 c=1.0 ;
42 }
43 return c;
44 }
45
46 void main()
47 {
48 // vec4 tempColor=uColor; // es3.0之前不支持round!!!!
49 // glsl事实上以float为计算基准
50 // int max_floor=int(floor(max_floorf+0.5));
51 // 算层数
52 float r=sqrt(oPosition.x*oPosition.x+oPosition.y*oPosition.y+oPosition.z*oPosition.z);
53 float beta=asin(oPosition.y/r);// 俯仰角
54 // int int_beta=int(floor((beta/(pbeta*2.0))+0.5)); // 层数
55 float count_beta=(beta/(pbeta*2.0 ));
56 // int index_beta=int(floor(count_beta+ max_floorf+0.5)); // 整数层数索引
57 float index_beta=floor(count_beta+ max_floorf+0.5 );
58 // int roomcount=0;
59 // 使用数据纹理法,取这一层的区分度
60 // int int1=int(floor(mod(index_beta,4.0)+0.5)); // 使用哪个颜色分量
61 // float float1=(index_beta/4.0); // 在纹理采样器中的顺序索引
62 float floatu=(mod(index_beta,wid_utexturepalpha))/(wid_utexturepalpha)+(0.5 /wid_utexturepalpha);// 猜测u是x轴
63 float floatv=(((index_beta)/(wid_utexturepalpha)))/(hei_utexturepalpha)+(0.5 /(wid_utexturepalpha*hei_utexturepalpha));
64 vec2 UVpalpha=vec2(floatu,floatv);
65 vec4 vec4palphas=texture2D(utexturepalpha, UVpalpha);
66 float palpha=(vec4palphas[0 ]*255.0 *100.0 +vec4palphas[1 ]*255.0 )/pow(10.0 ,vec4palphas[2 ]*255.0 );
67 // float palpha=getData500(uarrpalpha,int(floor(index_beta+0.5))); // 改为尝试数组法传递数据
68 // 取这一层的转角
69 float alpha=atan(oPosition.z,oPosition.x);// 标准反正切函数有两个参数!!
70
71 if (getOdevity(index_beta)==1.0 )// 为了体现交错效果,如果是奇数层alpha要减去palpha
72 {
73 alpha-=palpha;
74 }
75 if (alpha<0.0 )
76 {
77 alpha+=(MathPI*2.0 );
78 }
79 // 取地区块数据纹理的索引
80 float floatu2=(alpha/(palpha*2.0 ))/wid_utexturedqk;
81 float floatv2=index_beta/hei_utexturedqk+0.5 /hei_utexturedqk;
82 vec2 UVdqk=vec2(floatu2,floatv2);
83 gl_FragColor=texture2D(utexturedqk, UVdqk);
84 // gl_FragColor=vec4palphas;
85 // gl_FragColor=texelFetch(utexturedqk,ivec2(int(floor(alpha/(palpha*2.0)+0.5)),int(floor(index_beta+0.5))),0); // 这个整数像素的方法是WebGL2开始加入的!!!!
86 // gl_FragColor=vec4(1.0*floatu,1.0*floatv,1.0*floatv2,1.0); // 红,绿,蓝结果不是0就是1??!!
87
88 // int index_dqk=roomcount-1+int(floor((alpha/palpha)+0.5));
89 // vec4 tempColor=vec4(uarrdqk[index_dqk],1.0);
90
91 // float float_3=index_beta/(max_floorf*2.0);
92 // float float_4=oPosition.y/5.0;
93 // canvas的imagedata用255,255,255,1定义颜色通道,而glsl用1.0,1.0,1.0,1.0定义!!!!
94
95
96 }
View Code
片元着色器和前面的区别是加了一个判断奇偶层数的方法,另外,在WebGL2.0中加入的texelFetch方法可以直接根据像素的位置对纹理图进行采样,比使用纹理坐标进行采样方便许多。
执行程序效果如下:
拉近相机:
其中生成地形耗时1分30秒,平滑地形并入库耗时3分10秒,从数据库查询需要约1分钟
五、总结
这个方法耗时比较长,无法实时应用,但可以用来一次性构建地形多次使用,也许可以通过优化代码来提高运行速度。生成的海洋和陆地混杂度比较高,也许可以考虑从种子位置随机生长地形的算法,这样可以使得大陆和海洋区分的更加分明。着色器代码中没有考虑周期性光照效果,也没有考虑极点处的地区块如何处理。
下一步准备给地区块添加鼠标交互,和更细节的地貌块显示。
你可能感兴趣的:(使用着色器在WebGL3D场景中呈现行星表面地形)
springboot3.x集成nacos 并实现多环境配置
web13595609705
java spring boot spring
一、springboot版本springboot3.0.x和springboot3.1.x可直接使用nacos-config-spring-boot-starter包。springboot>=3.2.x需要使用spring-cloud-starter-alibaba-nacos-config包,因为常规包在我发布该文时nacos官方还没更新,已更新的版本只支持到3.1.x,cloud的包2024年
使用云服务器进行游戏开发的好处
wanhengidc
网络
企业选择使用云服务器来进行游戏开发,能够提供很多传统服务器所不具备的优势,不仅可以改善玩家的游戏体验感,还可以帮助提升开发效率,下面小编就来介绍一下使用云服务器进行游戏开发的好处都有什么。云服务器可以根据游戏的实际负载动态调整资源配置,当游戏在用户高峰期的时候也可以迅速增加计算和网络资源,在低峰期时还能够减少网络资源,为企业自身节省了一定的成本,有着很强的弹性扩展能力。选择使用云服务器也不需要额外
大神教你用Python实现Wake On Lan远程开机功能
云计算运维工程师
技术干活
这篇文章主要介绍了使用Python实现WakeOnLan远程开机功能,文中给大家补充介绍了python通过wakeonlan唤醒内网电脑开机,非常不错,感兴趣的朋友跟随小编一起学习吧Wake-On-LAN简称WOL,是一种电源管理功能;如果存在网络活动,则允许设备将操作系统从待机或休眠模式中唤醒。许多主板厂商支持IBM提出的网络唤醒标准。该标准允许网络管理员远程打开PC机电源,以便进行文件升级、资
如何快速在Windows 10 + Anaconda 3 中使用Mxnet及gluon
qianchess
mxnet使用 mxnet win10 anaconda gluon 人工智能
如何快速在Windows10+Anaconda3中使用Mxnet及gluon网络上Mxnet的安装以及使用方法很多,自从其作者之一李沐推出了基于Mxnet的深度学习课程之后,我也尝试着去使用了一下Mxnet。首先第一步就是在自己的系统中安装Mxnet及其相关组建。现在的Mxnet常常会跟其虚拟环境Gluon结合在一起,所以下文就一起阐述一下,顺便记录一下自己踩的坑。注意本文的大部分内容都可以在官网
蓝易云 - Linux系统中常见的远程管理协议!
蓝易云
linux 运维 服务器 http nginx https flutter
Linux系统中常见的远程管理协议有以下几种:1.SSH(SecureShell):SSH是一种安全的远程登录协议,用于在网络上安全地远程登录到Linux服务器。它提供了加密的传输和身份验证机制,可以防止数据在传输过程中被拦截和篡改。SSH使用用户名和密码或公钥认证来验证用户身份,并允许用户在远程终端上执行命令。2.Telnet:Telnet是一种不安全的远程登录协议,用于在网络上远程登录到Lin
【漏洞复现】锐捷 RG-EW1200G 无线路由器 登录绕过
A 八方
漏洞复现 安全
》》》产品描述《《《锐捷网络RG-EW1200G是一款有线无线全千兆双频无线路由器Q,适合平层家居、别墅、小型店铺、SOHO办公等场景使用。设备性能卓越,足以满足千兆上网需求;信号强劲,信号功率功率提升3倍,覆盖距离提升近1倍覆盖能力强。》》》漏洞描述《《《锐捷网络RG-EW1200G存在登录绕过逻辑漏洞,允许任何用户无需密码即可获得设备管理员权限》》》搜索语句《《《body="static/cs
JavaWeb 前端基础 html + CSS 快速入门 | 018
菜鸟阿康学习编程
前端 前端 html css
今日推荐语指望别人的救赎,势必走向毁灭——波伏娃日期学习内容打卡编号2025年01月17日JavaWeb前端基础html+CSS018前言哈喽,我是菜鸟阿康。今天正式进入JavaWeb的学习,简单学习html+CSS这2各前端基础部分,以下是我的重点总结,希望对你有所帮助。(建议先看左侧目录,先了解文章结构)(请忽略错误的大纲编号,我直接从笔记中粘贴过来的,就没严格纠正了,重点在内容!)文末和主页
深入理解主键和外键:数据库设计的基石
qcidyu
文章归档 数据建模 数据约束 关系型数据库 数据完整性 数据库设计 外键 主键
title:深入理解主键和外键:数据库设计的基石date:2025/1/18updated:2025/1/18author:cmdragonexcerpt:在现代信息系统中,数据的管理和存储是至关重要的。关系数据库作为一种广泛使用的数据存储方式,其设计的合理性直接影响到数据的完整性和系统的性能。在关系数据库中,主键和外键是实现数据完整性和表之间关系的基础。理解这两个概念对于数据库设计师和开发者来说
Ubuntu安装vmware-workstation失败后解决方法
demodeom
ubuntu linux 运维
由于不用版本、不同内核的Ubuntu,安装vmware-workstation时,可能会安装失败,安装失败后的解决方案,错误1使用以下命令可以查看安装失败的模块sudo/etc/init.d/vmwarestart输出如下,多数情况下都是这两个模块失败了StartingVMwareservices:VirtualmachinemonitorfailedVirtualmachinecommunica
利用代理模式实现日志功能
郭亚航
java框架 代理 日志输出
场景实现一个类,该类实现了数学四则运算,实现日志功能,每次调用对应的运算时,输出相应的日志基本功能接口packagecom.javase.thread;publicinterfaceArithmetic{publicintadd(inti,intj);publicintsub(inti,intj);publicintmul(inti,intj);publicintdiv(inti,intj);}接
Python程序中对文件名后缀为.pickle 的文件认识、创建和读取介绍和程序举例
qq_18937049
Python python pickle
Python程序中对文件名后缀为.pickle的文件认识、创建和读取介绍和程序举例目录Python程序中对文件名后缀为.pickle的文件认识、创建和读取介绍和程序举例1..pickle文件概述2..pickle文件的特点2.1序列化对象2.2二进制格式2.3兼容性3.创建和读取.pickle文件3.1创建.pickle文件——pickle.dump()3.2从.pickle文件读取——pickl
IoTDB 升级后 Trigger 不可用
铁头乔
iotdb 数据库 时序数据库 开源
问题现象目前将IoTDB1.3.2版本升级到了1.3.3(通过替换lib的方式)。替换后发现原有触发器,showtriggers显示active,但实际并未生效。卸载安装后依旧无法监听路径上的插入数据,不知道触发器逻辑是否有变更?没有发现异常日志,回退1.3.2版本后正常。原因ApacheTsFile目前已经独立成了一个项目,原来在TsFile下的类的包名都发生了变化,因此Trigger中依赖的T
2.TIDB整体架构
胡晗-
tidb
与传统的单机数据库相比,TiDB具有以下优势:纯分布式架构,拥有良好的扩展性,支持弹性的扩缩容支持SQL,对外暴露MySQL的网络协议,并兼容大多数MySQL的语法,在大多数场景下可以直接替换MySQL默认支持高可用,在少数副本失效的情况下,数据库本身能够自动进行数据修复和故障转移,对业务透明支持ACID事务,对于一些有强一致需求的场景友好,例如:银行转账具有丰富的工具链生态,覆盖数据迁移、同步、
代理模式和简单实现
on_the_roadZZZ
代理模式
代理模式和简单实现代理模式动态代理和静态代理静态代理代码动态代理JDK动态代理CGLIB动态代理两种动态代理的区别动态代理的应用动态和静态代理的区别代理模式代理模式是一种结构型设计模式,其目的是通过创建一个代理对象来控制对另一个对象的访问。代理对象充当了被代理对象的中间人,客户端通过代理对象来间接访问被代理对象,从而可以在访问被代理对象前后进行一些额外的操作。代理模式通常涉及三种角色:抽象接口(S
【前端】20种 Button 样式
m0_74823264
vip1024p 前端
20种Button样式在前端开发中,Button按钮的样式设计是提升用户交互体验的重要一环。以下是20种常见的Button样式,这些样式主要基于CSS实现,可以根据具体需求进行调整和组合。1.默认样式CSS样式:.button{background-color:#007bff;color:#fff;border:1pxsolid#007bff;}2.扁平样式CSS样式:.button{backgr
C语言——多线程基础(pthread)
m0_74823264
面试 学习路线 阿里巴巴资料职业发展 c语言 java jvm 后端
目录1.线程的定义以及线程的创建1.1线程和进程的概念1.2使用pthread_create()函数创建进程2.?使用pthread_join()等待线程结束2.1使用pthread_join()等待线程结束2.1使用pthread_join()得到线程函数的返回值1.线程的定义以及线程的创建1.1线程和进程的概念线程:进程中的一个实体,是CPU调度和分派的基本单位。线程自己基本上不拥有系统资源,
打造区块链成功案例:从技术开发到全方位包装。
白马区块Crypto100
区块链 web3 智能合约
打造区块链成功案例:从技术开发到全方位包装在当下的区块链行业,项目的成功不仅依赖于技术的先进性,更需要通过专业的品牌包装和市场推广,将技术的价值最大化呈现给目标用户和投资者。如果您正在寻找一家既懂区块链技术开发,又精通项目包装的公司,来帮助您的项目从零到一,我们是您不可或缺的合作伙伴。一、区块链技术开发:为您的项目奠定坚实基础技术是区块链项目的灵魂,而我们的技术团队正是行业的先行者。我们为全球客户
做SOL交易机器人拆解步骤,其实没有那么复杂。
白马区块Crypto100
web3 区块链 SOL机器人 智能合约 Solana
做SOL交易机器人拆解步骤,其实并没有那么复杂,对于有一定技术基础的人来说,完全可以按部就班地进行。在踏入这个领域之前,许多人可能会因为听到“机器人拆解”这样的词汇而感到心生畏惧,担心其中涉及的技术门槛过高,难以逾越。然而,事实并非如此。只要我们掌握了正确的方法和步骤,就能够逐步揭开SOL交易机器人的神秘面纱,了解其内在的工作原理和构造。接下来,本文将为大家详细介绍SOL交易机器人的拆解步骤,帮助
非科班研究生转码-零基础学java笔记总结复习(2)
Javaer.Zhang的乞讨之路
java 大数据 后端 android 算法
说明:该Java笔记是基于B站韩顺平老师讲的Java来总结提炼的,其中参考了韩老师总结的笔记。具体内容可到B站观看韩顺平老师的Java详细了解。省略号表示不重要。。。具体参考韩老师笔记。目录级别,例:第#章#.##.#.##.#.#.#正文重点内容使用加粗,下划线,红体字等表示。全部内容共28章。需要了解哪章进主页看序号即可。[本文为第二章]目录第2章JAVA概述2.1什么是程序2.2JAVA诞生
Git基本操作
宠物与不尤编程
git
Git是一个分布式版本控制系统,它可以追踪文件的变化,并记录文件的历史版本。以下是Git的基本概念和使用方式:仓库(Repository):Git仓库是存储代码和文件的地方,可以是本地仓库或远程仓库。本地仓库存储在本地计算机上,而远程仓库存储在远程服务器上。分支(Branch):分支是Git中的重要概念。在创建仓库时,会自动创建一个默认的主分支(通常是master)。除了主分支外,可以创建其他分支
Spread.NET 18.0 支持.NET9.0 Crack
sdk大全
Spread.NET Spread.NET
Spread.NET全球销量第一的C#.NET电子表格,包含500多个Excel函数在C#.NET中提供真正类似Excel的电子表格体验,且不依赖Excel。创建财务、预算/预测、科学、工程、医疗保健、保险、教育、制造和许多其他类似的业务应用程序。使用全面的API创建企业电子表格、高级网格、仪表板、报告和数据输入表单递送类似Excel的电子表格经验,快速利用强大的高速计算引擎完成最复杂的计算导入和
物联网时代,知识库管理系统的拓展与创新
企知学堂
物联网 人工智能 内部知识库 知识管理 大数据 知识库管理系统
在物联网(IoT)时代,知识库管理系统(KMS)正面临着前所未有的机遇与挑战。随着物联网技术的飞速发展,企业需要更加智能化、高效化和个性化的知识管理解决方案,以应对日益复杂的数据环境和业务需求。本文将探讨物联网时代知识库管理系统的拓展与创新。一、物联网时代的知识管理需求物联网技术的广泛应用使得企业能够收集和处理海量的数据,这些数据不仅包括传统的文本信息,还包括来自各种传感器、设备和系统的实时数据。
大模型prompt提示工程案例
数研妙手
AI技术实践 prompt 人工智能
一、明确目标和任务在设计Prompt之前,首先要明确你的目标是什么,是文本生成、信息提取、问答、翻译,还是其他任务。例如,如果是文本生成任务,要确定生成的文本类型,如故事、新闻报道、产品描述等。二、Prompt的基本结构指令部分:清晰明确地说明你希望大模型执行的任务。输入部分:提供必要的输入信息,以便大模型理解上下文。约束部分(可选):为大模型的输出设定限制,如字数、格式、语言等。三、设计原则清晰
JVM参数配置解析
niushoahan
java jvm class javadoc deprecated java documentation
在Java、J2EE大型应用中,JVM非标准参数的配置直接关系到整个系统的性能。JVM非标准参数指的是JVM底层的一些配置参数,这些参数在一般开发中默认即可,不需要任何配置。但是在生产环境中,为了提高性能,往往需要调整这些参数,以求系统达到最佳新能。另外这些参数的配置也是影响系统稳定性的一个重要因素,相信大多数Java开发人员都见过“OutOfMemory”类型的错误。呵呵,这其中很可能就是JVM
ubuntu18.04安装grpc及使用grpc时遇到的问题总结
烟酒僧_
#安装pkg-configsudoapt-getinstallpkg-config#安装依赖文件sudoapt-getinstallautoconfautomakelibtoolmakeg++unzipsudoapt-getinstalllibgflags-devlibgtest-devsudoapt-getinstallclanglibc++-dev克隆grpc源码gitclonehttps:/
PyWakeOnLan:Python 实现的轻量级 Wake-on-LAN 工具
郁虹宝Lucille
PyWakeOnLan:Python实现的轻量级Wake-on-LAN工具pywakeonlanAsmallpythonmoduleforwakeonlan.项目地址:https://gitcode.com/gh_mirrors/py/pywakeonlan项目基础介绍与编程语言PyWakeOnLan是一个由RemcoHaszing开发的小巧且易于使用的Python模块,专门用于实现Wake-on
推荐3D UNet实现:深度学习3D体素数据语义分割的利器!
滑辰煦Marc
推荐3DUNet实现:深度学习3D体素数据语义分割的利器!去发现同类优质开源项目:https://gitcode.com/在这个快速发展的深度学习时代,3DUNet已经成为3D图像处理领域中不可或缺的工具,尤其在医疗影像分析和3D物体识别等任务上展现出强大的潜力。这个开源项目为我们提供了一个高效、灵活的3DUNet实现,支持Tensorflow、PyTorch和Chainer三种主流深度学习框架。
IDLark 开源项目使用教程
缪阔孝Ruler
IDLark开源项目使用教程idlark项目地址:https://gitcode.com/gh_mirrors/id/idlark1.项目的目录结构及介绍IDLark项目的目录结构如下:idlark/├──LEGAL.md├──LICENSE├──README.md├──poetry.lock├──pyproject.toml└──idlark/└──__init__.py目录结构介绍LEGAL.
【RPC方案调研】Grpc 嵌入式移植流程
背着书包狂奔
架构设计 c++ 软件架构师
由于项目需求,准备在嵌入式上使用rpc方案,调研了多个方案,最终由于Grpc和protobuf天然的亲和性,决定对Grpc进行移植。Grpc地址:https://github.com/grpc/grpcGrpc的交叉编译支持三种方式:bazel,cmake,makefile;bazel由于编译太麻烦,主要适合google内部,直接放弃了,本文主要讲解基于cmake的交叉编译方式,makefile也
使用 Node.js 处理异步编程的挑战
Node.js是一个强大的JavaScript运行时环境,它以其非阻塞、事件驱动的特性闻名,使其在构建高并发应用程序时非常出色。然而,这种异步编程模型也带来了挑战,尤其是当我们需要处理复杂的异步操作时。本文将深入探讨Node.js中异步编程的挑战,并介绍一些常见的解决方案。异步编程的挑战在Node.js中,许多操作都是异步的,比如文件操作、网络请求、数据库查询等。虽然异步操作可以提高应用程序的性能
java类加载顺序
3213213333332132
java
package com.demo;
/**
* @Description 类加载顺序
* @author FuJianyong
* 2015-2-6上午11:21:37
*/
public class ClassLoaderSequence {
String s1 = "成员属性";
static String s2 = "
Hibernate与mybitas的比较
BlueSkator
sql Hibernate 框架 ibatis orm
第一章 Hibernate与MyBatis
Hibernate 是当前最流行的O/R mapping框架,它出身于sf.net,现在已经成为Jboss的一部分。 Mybatis 是另外一种优秀的O/R mapping框架。目前属于apache的一个子项目。
MyBatis 参考资料官网:http:
php多维数组排序以及实际工作中的应用
dcj3sjt126com
PHP usort uasort
自定义排序函数返回false或负数意味着第一个参数应该排在第二个参数的前面, 正数或true反之, 0相等usort不保存键名uasort 键名会保存下来uksort 排序是对键名进行的
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8&q
DOM改变字体大小
周华华
前端
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml&q
c3p0的配置
g21121
c3p0
c3p0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。c3p0的下载地址是:http://sourceforge.net/projects/c3p0/这里可以下载到c3p0最新版本。
以在spring中配置dataSource为例:
<!-- spring加载资源文件 -->
<bean name="prope
Java获取工程路径的几种方法
510888780
java
第一种:
File f = new File(this.getClass().getResource("/").getPath());
System.out.println(f);
结果:
C:\Documents%20and%20Settings\Administrator\workspace\projectName\bin
获取当前类的所在工程路径;
如果不加“
在类Unix系统下实现SSH免密码登录服务器
Harry642
免密 ssh
1.客户机
(1)执行ssh-keygen -t rsa -C "
[email protected] "生成公钥,xxx为自定义大email地址
(2)执行scp ~/.ssh/id_rsa.pub root@xxxxxxxxx:/tmp将公钥拷贝到服务器上,xxx为服务器地址
(3)执行cat
Java新手入门的30个基本概念一
aijuans
java java 入门 新手
在我们学习Java的过程中,掌握其中的基本概念对我们的学习无论是J2SE,J2EE,J2ME都是很重要的,J2SE是Java的基础,所以有必要对其中的基本概念做以归纳,以便大家在以后的学习过程中更好的理解java的精髓,在此我总结了30条基本的概念。 Java概述: 目前Java主要应用于中间件的开发(middleware)---处理客户机于服务器之间的通信技术,早期的实践证明,Java不适合
Memcached for windows 简单介绍
antlove
java Web windows cache memcached
1. 安装memcached server
a. 下载memcached-1.2.6-win32-bin.zip
b. 解压缩,dos 窗口切换到 memcached.exe所在目录,运行memcached.exe -d install
c.启动memcached Server,直接在dos窗口键入 net start "memcached Server&quo
数据库对象的视图和索引
百合不是茶
索引 oeacle数据库 视图
视图
视图是从一个表或视图导出的表,也可以是从多个表或视图导出的表。视图是一个虚表,数据库不对视图所对应的数据进行实际存储,只存储视图的定义,对视图的数据进行操作时,只能将字段定义为视图,不能将具体的数据定义为视图
为什么oracle需要视图;
&
Mockito(一) --入门篇
bijian1013
持续集成 mockito 单元测试
Mockito是一个针对Java的mocking框架,它与EasyMock和jMock很相似,但是通过在执行后校验什么已经被调用,它消除了对期望 行为(expectations)的需要。其它的mocking库需要你在执行前记录期望行为(expectations),而这导致了丑陋的初始化代码。
&nb
精通Oracle10编程SQL(5)SQL函数
bijian1013
oracle 数据库 plsql
/*
* SQL函数
*/
--数字函数
--ABS(n):返回数字n的绝对值
declare
v_abs number(6,2);
begin
v_abs:=abs(&no);
dbms_output.put_line('绝对值:'||v_abs);
end;
--ACOS(n):返回数字n的反余弦值,输入值的范围是-1~1,输出值的单位为弧度
【Log4j一】Log4j总体介绍
bit1129
log4j
Log4j组件:Logger、Appender、Layout
Log4j核心包含三个组件:logger、appender和layout。这三个组件协作提供日志功能:
日志的输出目标
日志的输出格式
日志的输出级别(是否抑制日志的输出)
logger继承特性
A logger is said to be an ancestor of anothe
Java IO笔记
白糖_
java
public static void main(String[] args) throws IOException {
//输入流
InputStream in = Test.class.getResourceAsStream("/test");
InputStreamReader isr = new InputStreamReader(in);
Bu
Docker 监控
ronin47
docker监控
目前项目内部署了docker,于是涉及到关于监控的事情,参考一些经典实例以及一些自己的想法,总结一下思路。 1、关于监控的内容 监控宿主机本身
监控宿主机本身还是比较简单的,同其他服务器监控类似,对cpu、network、io、disk等做通用的检查,这里不再细说。
额外的,因为是docker的
java-顺时针打印图形
bylijinnan
java
一个画图程序 要求打印出:
1.int i=5;
2.1 2 3 4 5
3.16 17 18 19 6
4.15 24 25 20 7
5.14 23 22 21 8
6.13 12 11 10 9
7.
8.int i=6
9.1 2 3 4 5 6
10.20 21 22 23 24 7
11.19
关于iReport汉化版强制使用英文的配置方法
Kai_Ge
iReport汉化 英文版
对于那些具有强迫症的工程师来说,软件汉化固然好用,但是汉化不完整却极为头疼,本方法针对iReport汉化不完整的情况,强制使用英文版,方法如下:
在 iReport 安装路径下的 etc/ireport.conf 里增加红色部分启动参数,即可变为英文版。
# ${HOME} will be replaced by user home directory accordin
[并行计算]论宇宙的可计算性
comsci
并行计算
现在我们知道,一个涡旋系统具有并行计算能力.按照自然运动理论,这个系统也同时具有存储能力,同时具备计算和存储能力的系统,在某种条件下一般都会产生意识......
那么,这种概念让我们推论出一个结论
&nb
用OpenGL实现无限循环的coverflow
dai_lm
android coverflow
网上找了很久,都是用Gallery实现的,效果不是很满意,结果发现这个用OpenGL实现的,稍微修改了一下源码,实现了无限循环功能
源码地址:
https://github.com/jackfengji/glcoverflow
public class CoverFlowOpenGL extends GLSurfaceView implements
GLSurfaceV
JAVA数据计算的几个解决方案1
datamachine
java Hibernate 计算
老大丢过来的软件跑了10天,摸到点门道,正好跟以前攒的私房有关联,整理存档。
-----------------------------华丽的分割线-------------------------------------
数据计算层是指介于数据存储和应用程序之间,负责计算数据存储层的数据,并将计算结果返回应用程序的层次。J
&nbs
简单的用户授权系统,利用给user表添加一个字段标识管理员的方式
dcj3sjt126com
yii
怎么创建一个简单的(非 RBAC)用户授权系统
通过查看论坛,我发现这是一个常见的问题,所以我决定写这篇文章。
本文只包括授权系统.假设你已经知道怎么创建身份验证系统(登录)。 数据库
首先在 user 表创建一个新的字段(integer 类型),字段名 'accessLevel',它定义了用户的访问权限 扩展 CWebUser 类
在配置文件(一般为 protecte
未选之路
dcj3sjt126com
诗
作者:罗伯特*费罗斯特
黄色的树林里分出两条路,
可惜我不能同时去涉足,
我在那路口久久伫立,
我向着一条路极目望去,
直到它消失在丛林深处.
但我却选了另外一条路,
它荒草萋萋,十分幽寂;
显得更诱人,更美丽,
虽然在这两条小路上,
都很少留下旅人的足迹.
那天清晨落叶满地,
两条路都未见脚印痕迹.
呵,留下一条路等改日再
Java处理15位身份证变18位
蕃薯耀
18位身份证变15位 15位身份证变18位 身份证转换
15位身份证变18位,18位身份证变15位
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
蕃薯耀 201
SpringMVC4零配置--应用上下文配置【AppConfig】
hanqunfeng
springmvc4
从spring3.0开始,Spring将JavaConfig整合到核心模块,普通的POJO只需要标注@Configuration注解,就可以成为spring配置类,并通过在方法上标注@Bean注解的方式注入bean。
Xml配置和Java类配置对比如下:
applicationContext-AppConfig.xml
<!-- 激活自动代理功能 参看:
Android中webview跟JAVASCRIPT中的交互
jackyrong
JavaScript html android 脚本
在android的应用程序中,可以直接调用webview中的javascript代码,而webview中的javascript代码,也可以去调用ANDROID应用程序(也就是JAVA部分的代码).下面举例说明之:
1 JAVASCRIPT脚本调用android程序
要在webview中,调用addJavascriptInterface(OBJ,int
8个最佳Web开发资源推荐
lampcy
编程 Web 程序员
Web开发对程序员来说是一项较为复杂的工作,程序员需要快速地满足用户需求。如今很多的在线资源可以给程序员提供帮助,比如指导手册、在线课程和一些参考资料,而且这些资源基本都是免费和适合初学者的。无论你是需要选择一门新的编程语言,或是了解最新的标准,还是需要从其他地方找到一些灵感,我们这里为你整理了一些很好的Web开发资源,帮助你更成功地进行Web开发。
这里列出10个最佳Web开发资源,它们都是受
架构师之面试------jdk的hashMap实现
nannan408
HashMap
1.前言。
如题。
2.详述。
(1)hashMap算法就是数组链表。数组存放的元素是键值对。jdk通过移位算法(其实也就是简单的加乘算法),如下代码来生成数组下标(生成后indexFor一下就成下标了)。
static int hash(int h)
{
h ^= (h >>> 20) ^ (h >>>
html禁止清除input文本输入缓存
Rainbow702
html 缓存 input 输入框 change
多数浏览器默认会缓存input的值,只有使用ctl+F5强制刷新的才可以清除缓存记录。
如果不想让浏览器缓存input的值,有2种方法:
方法一: 在不想使用缓存的input中添加 autocomplete="off";
<input type="text" autocomplete="off" n
POJO和JavaBean的区别和联系
tjmljw
POJO java beans
POJO 和JavaBean是我们常见的两个关键字,一般容易混淆,POJO全称是Plain Ordinary Java Object / Pure Old Java Object,中文可以翻译成:普通Java类,具有一部分getter/setter方法的那种类就可以称作POJO,但是JavaBean则比 POJO复杂很多, Java Bean 是可复用的组件,对 Java Bean 并没有严格的规
java中单例的五种写法
liuxiaoling
java 单例
/**
* 单例模式的五种写法:
* 1、懒汉
* 2、恶汉
* 3、静态内部类
* 4、枚举
* 5、双重校验锁
*/
/**
* 五、 双重校验锁,在当前的内存模型中无效
*/
class LockSingleton
{
private volatile static LockSingleton singleton;
pri