WebGL学习笔记(4)

2023-05-16

本篇笔记加强了上篇笔记示例代码的程序,实现了使用nodejs-websocket来广播每个玩家的坐标数据并在同一个世界模型中进行多人在线交互。

 

websocket服务端:

安装nodejs与npm,创建一个服务端目录

npm init

npm install nodejs-websocket

index.js,代码如下,创建好index.js后,执行 node index.js 开启websocket服务端

var ws = require("nodejs-websocket")

function broadcast(server, msg) {
server.connections.forEach(function (conn) {
conn.sendText(msg)
})
}

var server = ws.createServer(function (conn) {
console.log("New connection")
conn.on("text", function (str) {
console.log("Received "+str)
broadcast(server, str)
})
conn.on("close", function (code, reason) {
console.log("Connection closed")
})
conn.on("error", function (code, reason) {
console.log("异常关闭", reason)
});
}).listen(8001)

 

客户端测试代码如下,拷贝到您的浏览器打开,方向键控制镜头旋转与移动,多个用户(或浏览器窗口)使用相同的websocket服务地址可以看到彼此。

<!doctype html>
<html>
<head>
<style>
* {margin:0;padding:0;overflow:hidden;}
</style>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;

uniform mat4 uPMatrix;
uniform mat4 uTranslateMatrix;
uniform mat4 uScaleMatrix;
uniform mat4 uRotateYMatrix;
uniform mat4 uRotateXMatrix;
uniform mat4 uRotateZMatrix;
varying vec2 vTextureCoord;

void main(void){
gl_Position = uPMatrix * uRotateZMatrix * uRotateYMatrix * uRotateXMatrix *uTranslateMatrix * uScaleMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;

varying vec2 vTextureCoord;

uniform sampler2D uSampler;

void main(void) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}

</script>
<script>

var op = function op(){}

op.intCanvas = function(id) {
var canvas = document.getElementById(id)
if(!canvas) {
alert('Could not intialise Canvas, sorry :-(")')
}
op.canvas = canvas
}

op.intGL = function(canvas) {
if(!canvas){
canvas = op.canvas
}
try {
var gl = canvas.getContext("experimental-webgl")

gl.viewportWidth = canvas.width
gl.viewportHeight = canvas.height
op.gl = gl
} catch(e) {
}
if(!gl) {
alert('Could not intialise WebGL, sorry :-(")')
}
}
op.intShader = function(){
op.gl.vertexShader = op.getShader('vertex-shader')
op.gl.fragmentShader = op.getShader('fragment-shader')
}
op.getShader = function (scriptId) {

try {
if(!op.gl) {
throw new Error('找不到WebGL对象。');
}
var gl = op.gl

var shaderScript = document.getElementById(scriptId)
if( ! shaderScript) {
throw new Error('找不到着色器代码。');
}
var str = ''
const TEXT_NODE = 3
k = shaderScript.firstChild;

while(k) {
if(k.nodeType == TEXT_NODE) {
str += k.textContent
}
k = k.nextSibling;
}
var shader, shaderType;
if(shaderScript.type == "x-shader/x-fragment") {
shaderType = gl.FRAGMENT_SHADER
} else if( shaderScript.type == "x-shader/x-vertex") {
shaderType = gl.VERTEX_SHADER
} else {
throw new Error('着色器类型有误。');
}
shader = gl.createShader(shaderType);
gl.shaderSource(shader, str)
gl.compileShader(shader);

if(! gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw new Error('着色器编译出现问题:' + gl.getShaderInfoLog(shader));
}
} catch(e) {
alert('[Error]' + e)
}

return shader;
}

op.intProgram = function(){
var gl = op.gl
var fragmentShader = gl.fragmentShader
var vertexShader = gl.vertexShader
var program = gl.createProgram()
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.linkProgram(program)
if(! gl.getProgramParameter(program, gl.LINK_STATUS) ) {
alert("Could not initialise shaders");
}
gl.useProgram(program)
gl.program = program

program.vertexPositionAttribute = gl.getAttribLocation(program, 'aVertexPosition');
gl.enableVertexAttribArray(program.vertexPositionAttribute)

program.pMatrixUniform = gl.getUniformLocation(program, 'uPMatrix')
program.uRotateXMatrixUniform = gl.getUniformLocation(program, 'uRotateXMatrix');
program.uRotateYMatrixUniform = gl.getUniformLocation(program, 'uRotateYMatrix');
program.uRotateZMatrixUniform = gl.getUniformLocation(program, 'uRotateZMatrix');
program.uScaleMatrixUniform = gl.getUniformLocation(program, 'uScaleMatrix');
program.uTranslateMatrixUniform = gl.getUniformLocation(program, 'uTranslateMatrix');

program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord");
gl.enableVertexAttribArray(program.textureCoordAttribute);

program.samplerUniform = gl.getUniformLocation(program, 'uSampler')
}


op.setBuffer = function(bufferName, bufferData, isIndexBuffer, itemSize){

var gl = op.gl
var buffer = gl.createBuffer()
gl[bufferName] = buffer

if(isIndexBuffer) {
var BUFFER_TYPE = gl.ELEMENT_ARRAY_BUFFER
} else {
var BUFFER_TYPE = gl.ARRAY_BUFFER
}
gl.bindBuffer(BUFFER_TYPE, buffer)
gl.bufferData(BUFFER_TYPE, bufferData, gl.STATIC_DRAW)
gl.bindBuffer(BUFFER_TYPE, null)

buffer.itemSize = itemSize
buffer.numItem = bufferData.length/itemSize
buffer.bufferType = BUFFER_TYPE

return buffer
}

op.intBuffer = function(setCallback){
setCallback()
}

 

op.projection = function(angle, a, zMin, zMax) {

var ang = Math.tan((angle*.5)*Math.PI/180);
var matrix = [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
]

op.pMatrix = matrix
}

var matrixobj = function(mobj = null){

if(mobj == null) {
this.translateMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]

this.scaleMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]

this.rotateYMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]

this.rotateXMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]

this.rotateZMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]
} else {
this.translateMatrix = mobj.translateMatrix

this.scaleMatrix = mobj.scaleMatrix

this.rotateYMatrix = mobj.rotateYMatrix

this.rotateXMatrix = mobj.rotateXMatrix

this.rotateZMatrix = mobj.rotateZMatrix
}

}

matrixobj.prototype.translate = function(x,y,z){

this.translateMatrix[12]+=x
this.translateMatrix[13]+=y
this.translateMatrix[14]+=z

}

matrixobj.prototype.translateReverse = function(){

this.translateMatrix[12]=this.translateMatrix[12]*-1
this.translateMatrix[13]=this.translateMatrix[13]*-1
this.translateMatrix[14]=this.translateMatrix[14]*-1

}


matrixobj.prototype.translateRelative = function(x,y,z){

glmatrix = new matrixobj
glmatrix.translate(x,y,z)

this.translateMatrix = multiply([], this.translateMatrix, glmatrix.translateMatrix)
}

matrixobj.prototype.scale = function(scale){
var matrix = [
scale, 0, 0, 0,
0, scale, 0,0,
0,0,scale,0,
0,0,0,1
]
this.scaleMatrix = matrix
}

matrixobj.prototype.rotateX = function(deg){
var rad, mcos, msin;

rad=deg*Math.PI/180

msin=Math.sin(rad)
mcos=Math.cos(rad)

var matrix = [
1, 0,0,0,
0, mcos,msin,0,
0, -msin, mcos, 0,
0,0,0,1
]

this.rotateXMatrix = matrix

}

matrixobj.prototype.rotateY = function(deg){
var rad, mcos, msin;
rad=deg*Math.PI/180
mcos=Math.cos(rad)
msin=Math.sin(rad)
var matrix = [
mcos, 0, -msin, 0,
0, 1, 0, 0,
msin, 0 , mcos, 0,
0, 0, 0, 1
]
this.rotateYMatrix = matrix
}

matrixobj.prototype.rotateYRelative = function(deg){

var rad, mcos, msin;
rad=deg*Math.PI/180
mcos=Math.cos(rad)
msin=Math.sin(rad)
var matrix = [
mcos, 0, -msin, 0,
0, 1, 0, 0,
msin, 0 , mcos, 0,
0, 0, 0, 1
]
this.scaleMatrix = multiply([], this.scaleMatrix, matrix)
}

matrixobj.prototype.rotateZ = function(deg){
var rad, mcos, msin;
rad=deg*Math.PI/180
mcos=Math.cos(rad)
msin=Math.sin(rad)
var matrix = [
mcos, msin,0,0,
-msin, mcos,0,0,
0, 0 , 1, 0,
0,0,0,1
]
this.rotateZMatrix = matrix
}

matrixobj.prototype.equals = function(matrixobj2){

if( equals(this.translateMatrix, matrixobj2.translateMatrix) &&
equals(this.scaleMatrix, matrixobj2.scaleMatrix) &&
equals(this.rotateYMatrix, matrixobj2.rotateYMatrix) &&
equals(this.rotateXMatrix, matrixobj2.rotateXMatrix) &&
equals(this.rotateZMatrix, matrixobj2.rotateZMatrix)
) {
return true;
} else {
return false;
}

}

 


function multiply(out, a, b) {
let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];

// Cache only the current line of the second matrix
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;

b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;

b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;

b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
return out;
}

function equals(a, b) {
glMatrix = {}
glMatrix.EPSILON = 0.000001
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
let a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7];
let a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11];
let a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15];

let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
let b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7];
let b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11];
let b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];

return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&
Math.abs(a9 - b9) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&
Math.abs(a10 - b10) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&
Math.abs(a11 - b11) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&
Math.abs(a12 - b12) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&
Math.abs(a13 - b13) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&
Math.abs(a14 - b14) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&
Math.abs(a15 - b15) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a15), Math.abs(b15)));
}

op.setPMVMatrixUniformToProgram = function(mobj){
var gl = op.gl
var program = gl.program
if(!op.pMatrix) {
var angle = 45
op.projection(angle, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
}

gl.uniformMatrix4fv(program.pMatrixUniform, false, new Float32Array(op.pMatrix))
gl.uniformMatrix4fv(program.uRotateZMatrixUniform, false, new Float32Array(mobj.rotateZMatrix))
gl.uniformMatrix4fv(program.uRotateXMatrixUniform, false, new Float32Array(mobj.rotateXMatrix))
gl.uniformMatrix4fv(program.uRotateYMatrixUniform, false, new Float32Array(mobj.rotateYMatrix))
gl.uniformMatrix4fv(program.uScaleMatrixUniform, false, new Float32Array(mobj.scaleMatrix))
gl.uniformMatrix4fv(program.uTranslateMatrixUniform, false, new Float32Array(mobj.translateMatrix))
}

op.setBufferAttribToProgram = function(buffer, attribute, isTexture = false, texture){
var gl = op.gl
var program = gl.program

gl.bindBuffer(buffer.bufferType, buffer)
gl.vertexAttribPointer(attribute, buffer.itemSize, gl.FLOAT, false, 0, 0)
if(isTexture) {
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, texture)
gl.uniform1i(program.samplerUniform, 0)
}
}

op.handleLoadedTexture = function(texture){
var gl = op.gl
gl.bindTexture(gl.TEXTURE_2D, texture)
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true)
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
gl.bindTexture(gl.TEXTURE_2D, null)
}

op.createTexture = function(src){
var gl = op.gl
var texture = gl.createTexture()
texture.image = new Image()
texture.image.onload = function(){
op.handleLoadedTexture(texture)
}
texture.image.src = src

return texture

}
var trans_x=0
var trans_y=0
var trans_z=0

var lastTime = 0;

mobj = new matrixobj
console.log(mobj)

var objx = 0
var objxt = false;
var objz = 0
var objzt = false;
var user = Math.random()

var last_self = {user:user, cp:[0,0,0]};
op.drawScene = function(){

var gl = op.gl
var program = gl.program

if(gl.worldVertexTextureCoordBuffer == null || ! gl.worldVertexPositionBuffer == null) {
return
}

gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

var angle = 90
op.projection(angle, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);

mobj = new matrixobj
mobj.translate(-xPos, -0.4, -zPos);
mobj.rotateY(-yaw)

op.setBufferAttribToProgram(gl.worldVertexTextureCoordBuffer, program.textureCoordAttribute, true,op.mtexture)
op.setBufferAttribToProgram(gl.worldVertexPositionBuffer, program.vertexPositionAttribute)
op.setPMVMatrixUniformToProgram(mobj)

gl.drawArrays(gl.TRIANGLES, 0, gl.worldVertexPositionBuffer.numItems);

if(otheruser.length>0) {
for(var i in otheruser) {
if(otheruser[i].user !=user){

mobjuser = new matrixobj(otheruser[i].wobj)

mobjuser.translateRelative(-xPos, 0.1, -zPos);

mobjuser.rotateY(-yaw)

mobjuser.scale(0.1)

mobjuser.rotateYRelative(-otheruser[i].cp[3])

op.setPMVMatrixUniformToProgram(mobjuser)

op.setBufferAttribToProgram(gl.squareVertexTextureCoordBuffer, program.textureCoordAttribute, true,op.nehetexture)
op.setBufferAttribToProgram(gl.squareVertexPositionBuffer, program.vertexPositionAttribute)
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.squareVertexIndexBuffer)
gl.drawElements(gl.TRIANGLES, gl.squareVertexIndexBuffer.numItem, gl.UNSIGNED_SHORT, 0)

}

}
}

/*
mobj_self = new matrixobj
mobj_self.translate(0, -0.2, -0.2);
mobj_self.rotateZ(10)
mobj_self.rotateX(10)
mobj_self.scale(0.05)
op.setPMVMatrixUniformToProgram(mobj_self)
op.setBufferAttribToProgram(gl.squareVertexTextureCoordBuffer, program.textureCoordAttribute, true,op.nehetexture)
op.setBufferAttribToProgram(gl.squareVertexPositionBuffer, program.vertexPositionAttribute)
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.squareVertexIndexBuffer)
gl.drawElements(gl.TRIANGLES, gl.squareVertexIndexBuffer.numItem, gl.UNSIGNED_SHORT, 0)
*/
usercp = {}
usercp.wobj = mobj;
usercp.wobj.translateMatrix[12] = usercp.wobj.translateMatrix[12] *-1
usercp.wobj.translateMatrix[14] = usercp.wobj.translateMatrix[14] *-1

usercp.user = user
usercp.cp = [-xPos, -0.4, -zPos, -yaw]
if(last_self) {
if(last_self.cp[0] !=-xPos || last_self.cp[2] !=-zPos|| last_self.cp[3] !=-yaw ) {
console.log('start send', usercp)
ws.send(JSON.stringify(usercp))
}
}

last_self = JSON.parse(JSON.stringify(usercp))
}

</script>
</head>
<body>
<canvas id="my_Canvas" width="500" height="500" ></canvas>

<script>

var clearColor = [1.0, 1.0, 1.0, 1.0];

var setBuffers = function(){
op.setBuffer('squareVertexPositionBuffer', new Float32Array([
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
-1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
-1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
-1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1,
]), false, 3)

op.setBuffer('squareVertexIndexBuffer', new Uint16Array([
0,1,2, 0,2,3, 4,5,6, 4,6,7,
8,9,10, 8,10,11, 12,13,14, 12,14,15,
16,17,18, 16,18,19, 20,21,22, 20,22,23
]), true, 1)

op.setBuffer('squareVertexTextureCoordBuffer', new Float32Array([
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
]), false, 2)

}

op.loadWorld = function(){
//引用自hiwebgl.com的world.txt文件
op.handleLoadedWorld(`

NUMPOLLIES 36

// Floor 1
-3.0 0.0 -3.0 0.0 6.0
-3.0 0.0 3.0 0.0 0.0
3.0 0.0 3.0 6.0 0.0

-3.0 0.0 -3.0 0.0 6.0
3.0 0.0 -3.0 6.0 6.0
3.0 0.0 3.0 6.0 0.0

// Ceiling 1
-3.0 1.0 -3.0 0.0 6.0
-3.0 1.0 3.0 0.0 0.0
3.0 1.0 3.0 6.0 0.0
-3.0 1.0 -3.0 0.0 6.0
3.0 1.0 -3.0 6.0 6.0
3.0 1.0 3.0 6.0 0.0

// A1

-2.0 1.0 -2.0 0.0 1.0
-2.0 0.0 -2.0 0.0 0.0
-0.5 0.0 -2.0 1.5 0.0
-2.0 1.0 -2.0 0.0 1.0
-0.5 1.0 -2.0 1.5 1.0
-0.5 0.0 -2.0 1.5 0.0

// A2

2.0 1.0 -2.0 2.0 1.0
2.0 0.0 -2.0 2.0 0.0
0.5 0.0 -2.0 0.5 0.0
2.0 1.0 -2.0 2.0 1.0
0.5 1.0 -2.0 0.5 1.0
0.5 0.0 -2.0 0.5 0.0

// B1

-2.0 1.0 2.0 2.0 1.0
-2.0 0.0 2.0 2.0 0.0
-0.5 0.0 2.0 0.5 0.0
-2.0 1.0 2.0 2.0 1.0
-0.5 1.0 2.0 0.5 1.0
-0.5 0.0 2.0 0.5 0.0

// B2

2.0 1.0 2.0 2.0 1.0
2.0 0.0 2.0 2.0 0.0
0.5 0.0 2.0 0.5 0.0
2.0 1.0 2.0 2.0 1.0
0.5 1.0 2.0 0.5 1.0
0.5 0.0 2.0 0.5 0.0

// C1

-2.0 1.0 -2.0 0.0 1.0
-2.0 0.0 -2.0 0.0 0.0
-2.0 0.0 -0.5 1.5 0.0
-2.0 1.0 -2.0 0.0 1.0
-2.0 1.0 -0.5 1.5 1.0
-2.0 0.0 -0.5 1.5 0.0

// C2

-2.0 1.0 2.0 2.0 1.0
-2.0 0.0 2.0 2.0 0.0
-2.0 0.0 0.5 0.5 0.0
-2.0 1.0 2.0 2.0 1.0
-2.0 1.0 0.5 0.5 1.0
-2.0 0.0 0.5 0.5 0.0

// D1

2.0 1.0 -2.0 0.0 1.0
2.0 0.0 -2.0 0.0 0.0
2.0 0.0 -0.5 1.5 0.0
2.0 1.0 -2.0 0.0 1.0
2.0 1.0 -0.5 1.5 1.0
2.0 0.0 -0.5 1.5 0.0

// D2

2.0 1.0 2.0 2.0 1.0
2.0 0.0 2.0 2.0 0.0
2.0 0.0 0.5 0.5 0.0
2.0 1.0 2.0 2.0 1.0
2.0 1.0 0.5 0.5 1.0
2.0 0.0 0.5 0.5 0.0

// Upper hallway - L
-0.5 1.0 -3.0 0.0 1.0
-0.5 0.0 -3.0 0.0 0.0
-0.5 0.0 -2.0 1.0 0.0
-0.5 1.0 -3.0 0.0 1.0
-0.5 1.0 -2.0 1.0 1.0
-0.5 0.0 -2.0 1.0 0.0

// Upper hallway - R
0.5 1.0 -3.0 0.0 1.0
0.5 0.0 -3.0 0.0 0.0
0.5 0.0 -2.0 1.0 0.0
0.5 1.0 -3.0 0.0 1.0
0.5 1.0 -2.0 1.0 1.0
0.5 0.0 -2.0 1.0 0.0

// Lower hallway - L
-0.5 1.0 3.0 0.0 1.0
-0.5 0.0 3.0 0.0 0.0
-0.5 0.0 2.0 1.0 0.0
-0.5 1.0 3.0 0.0 1.0
-0.5 1.0 2.0 1.0 1.0
-0.5 0.0 2.0 1.0 0.0

// Lower hallway - R
0.5 1.0 3.0 0.0 1.0
0.5 0.0 3.0 0.0 0.0
0.5 0.0 2.0 1.0 0.0
0.5 1.0 3.0 0.0 1.0
0.5 1.0 2.0 1.0 1.0
0.5 0.0 2.0 1.0 0.0


// Left hallway - Lw

-3.0 1.0 0.5 1.0 1.0
-3.0 0.0 0.5 1.0 0.0
-2.0 0.0 0.5 0.0 0.0
-3.0 1.0 0.5 1.0 1.0
-2.0 1.0 0.5 0.0 1.0
-2.0 0.0 0.5 0.0 0.0

// Left hallway - Hi

-3.0 1.0 -0.5 1.0 1.0
-3.0 0.0 -0.5 1.0 0.0
-2.0 0.0 -0.5 0.0 0.0
-3.0 1.0 -0.5 1.0 1.0
-2.0 1.0 -0.5 0.0 1.0
-2.0 0.0 -0.5 0.0 0.0

// Right hallway - Lw

3.0 1.0 0.5 1.0 1.0
3.0 0.0 0.5 1.0 0.0
2.0 0.0 0.5 0.0 0.0
3.0 1.0 0.5 1.0 1.0
2.0 1.0 0.5 0.0 1.0
2.0 0.0 0.5 0.0 0.0

// Right hallway - Hi

3.0 1.0 -0.5 1.0 1.0
3.0 0.0 -0.5 1.0 0.0
2.0 0.0 -0.5 0.0 0.0
3.0 1.0 -0.5 1.0 1.0
2.0 1.0 -0.5 0.0 1.0
2.0 0.0 -0.5 0.0 0.0
`)
/*
var request = new XMLHttpRequest();
request.open("GET", "world.txt");
request.onreadystatechange = function () {
if (request.readyState == 4) {
op.handleLoadedWorld(request.responseText);
}
}
request.send();*/
}


op.handleLoadedWorld = function (data) {
var worldVertexPositionBuffer = null;
var worldVertexTextureCoordBuffer = null;

var gl = op.gl
var lines = data.split("\n");
var vertexCount = 0;
var vertexPositions = [];
var vertexTextureCoords = [];
for (var i in lines) {
var vals = lines[i].replace(/^\s+/, "").split(/\s+/);

if (vals.length == 5 && vals[0] != "//") {
// It is a line describing a vertex; get X, Y and Z first
vertexPositions.push(parseFloat(vals[0]));
vertexPositions.push(parseFloat(vals[1]));
vertexPositions.push(parseFloat(vals[2]));
// And then the texture coords
vertexTextureCoords.push(parseFloat(vals[3]));
vertexTextureCoords.push(parseFloat(vals[4]));
vertexCount += 1;
}
}

worldVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexPositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositions), gl.STATIC_DRAW);
worldVertexPositionBuffer.itemSize = 3;
worldVertexPositionBuffer.numItems = vertexCount;
worldVertexPositionBuffer.bufferType = gl.ARRAY_BUFFER

worldVertexTextureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, worldVertexTextureCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexTextureCoords), gl.STATIC_DRAW);
worldVertexTextureCoordBuffer.itemSize = 2;
worldVertexTextureCoordBuffer.numItems = vertexCount;
worldVertexTextureCoordBuffer.bufferType = gl.ARRAY_BUFFER

gl.worldVertexTextureCoordBuffer = worldVertexTextureCoordBuffer
gl.worldVertexPositionBuffer = worldVertexPositionBuffer
}

op.intCanvas('my_Canvas')
op.intGL()
op.intShader()
op.intProgram()
op.intBuffer(setBuffers)
//引用自hiwebgl.com的纹理
textimgdata = "data:image/gif;base64,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"

op.nehetexture = op.createTexture(textimgdata)
op.mtexture = op.createTexture(textimgdata)
op.loadWorld()

op.gl.clearColor(...clearColor)
op.gl.enable(op.gl.DEPTH_TEST)

var speed = 0
var yawRate = 0
var yaw = 0;
var xPos = 0;
var yPos = 0.4;
var zPos = 0;

op.handleUserOp = function(){
if(key_sw['ArrowUp']) {
speed= 0.1
}
else if(key_sw['ArrowDown']) {
speed= -0.1
} else {
speed = 0
}

if(key_sw['ArrowLeft']) {
yawRate = 0.1;
mov_x_length+=2;
}else if(key_sw['ArrowRight']) {
yawRate = -0.1;
mov_x_length-=2;
} else {
yawRate = 0
}

if(key_sw['PageUp']) {
trans_y+=0.05;
}

if(key_sw['PageDown']) {
trans_y-=0.05;
}
}

var xjd=0,yjd=0,zjd=0

var moving = false
var mov_x_length = 0
var mov_y_length = 0
var page_x=0;
var page_y=0;

document.onmousedown = function(e){
moving = true
page_x = e.x
page_y = e.y
}

document.onmouseup = function(e) {
moving = false
}

document.onmousemove = function(e) {
if(moving) {
mov_x_length+=page_x-e.x
mov_y_length+=page_y-e.y
page_x = e.x
page_y = e.y
}
}

var key_sw = []
var zoom=0;

document.onkeydown = function(e) {
key_sw[e.key] = true
}

document.onkeyup = function(e) {
key_sw[e.key] = false
}


var lastTime = 0;

var otheruser = []

var server = prompt('请您输入Websocket服务地址','ws://127.0.0.1:8001')

var ws = new WebSocket(server);
try {
ws.onopen = function(e){
console.log("连接服务器成功");

animate = function(){
canvas = op.canvas
gl = op.gl
gl.viewportWidth = canvas.width = innerWidth
gl.viewportHeight = canvas.height = innerHeight


op.handleUserOp()
op.drawScene()

var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;

if (speed != 0) { //是否前进/后退(平移z,需要重新计算model x,y ,用当前x减去 移动过的比值)
xPos-= Math.sin(yaw * Math.PI/180) * speed * 1;
zPos-= Math.cos(yaw * Math.PI/180) * speed * 1;

//joggingAngle += elapsed * 0.6; // 0.6 "fiddle factor" - makes it feel more realistic :-)
//yPos = Math.sin(degToRad(joggingAngle)) / 20 + 0.4
}

yaw += yawRate * 5;
//console.log('yaw',yaw)
}
lastTime = timeNow;

window.requestAnimationFrame(animate)

}

animate()
}
ws.onclose = function(e){
alert("服务器关闭");
}
ws.onerror = function(){
alert("连接出错");
}

ws.onmessage = function(e){

usermodel = JSON.parse(e.data)

var time = new Date();
if(usermodel.user != user) {

if(otheruser.length<=0) {
console.log('push user')
otheruser.push(usermodel)
} else {
var f = false
for(var i in otheruser) {
if(otheruser[i].user == usermodel.user) {
f=true


otheruser[i] = usermodel
break
}
}
if(!f){
otheruser.push(usermodel)
}

}
console.log(otheruser)
//console.log(time+"的消息:"+usermodel.user)
}

}

} catch(e) {
alert('出现异常')
}

</script>
</body>
</html>

转载于:https://www.cnblogs.com/bird-eat-vegetable/p/9290587.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WebGL学习笔记(4) 的相关文章

  • iOS开发网络篇 —— OC加载HTML代码

    html代码 图1 样式一 xff1a 34 lt p gt lt img src 61 34 upload image 20170609 1496978712941664 jpg 34 title 61 34 14969787129416
  • Python 安装与环境变量配置

    一 软件下载 Python安装包下载地址 xff1a https www python org 二 安装过程 xff08 略 xff09 三 环境变量配置 xff1a 方法一 xff1a 使用cmd命令添加path环境变量 在cmd下输入
  • USB串口导致鼠标乱跳

    近期在工控机上安装USB串口 xff0c 结果装上没几天 xff0c 就有反馈开机后鼠标乱跳 然后 xff0c 开始解决问题 环境 xff1a 工控机操作系统Windows 7专业版 xff0c USB串口Z TEK USB RS232 1
  • Minimum Depth of Binary Tree 二叉树的最小深度

    Given a binary tree find its minimum depth The minimum depth is the number of nodes along the shortest path from the roo
  • 【Android Studio】成功解决 “gradle project sync failed”

    更新Android Studio后报错 xff1a gradle project sync failed Basic functionality e g editing debugging will not work properly 网上
  • 我失败的程序员生涯

    我 xff0c 一个普普通通的人 普通本科毕业 xff0c 来到北京成为了一个普通的程序员 2013年 xff0c 我本科毕业 xff0c 然后就踏上了北漂的征程 来之前想的很清楚 北京技术发达先进 我可以在这里工作三四年 xff0c 学习
  • gdb+gdbserver远程串行协议[zz]

    转载地址 xff1a http blog sina com cn s blog 71ed04f70100qhxc html gdbserver debug remote debug mount hello Usage gdbserver O
  • python 远程关机_python实现微信远程电脑关机完整源码

    这是python实现微信远程电脑关机完整源码下载 xff0c 通过手机微信发送QQ邮件给sina邮箱 xff0c 然后利用python的pop3定时检查sina邮箱的邮件主题以及邮件来源 xff0c 并在电脑执行相应的命令行实现关机 软件介
  • html设计思路,网页设计思路7个方法

    网页设计思路7个方法 网页设计除了要设计的漂亮 xff0c 体验优秀 xff0c 还要让用户对网站难以忘怀 xff0c 这就需要设计师进行深入的思考 xff0c 通过更加走心的设计 xff0c 来抓住用户的心 毕竟没有哪个站长不想让自己的网
  • 安卓网络类型设置的实现

    工作背景 xff1a 公司出口国外某国的设备 xff0c 因为该国对4G认证要求较高 xff0c 流程非常麻烦 xff0c 客户不想取得4G方面认证 xff0c 因此订单机器设备需禁用4G xff0c 且不能手动恢复4G xff0c 默认3
  • 硬件虚拟化

    硬件虚拟化也称作完全虚拟化 在计算机科学中 xff0c 硬件虚拟化 xff08 英语 xff1a Hardware virtualization xff09 是一种对计算机或操作系统的虚拟 虚拟化对用户隐藏了真实的计算机硬件 xff0c 表
  • 计算机语言怎么学才学得好,如何正确开始学习计算机编程语言?

    原标题 xff1a 如何正确开始学习计算机编程语言 xff1f 俗话说 xff0c 好的的开始是成功的一半 学习编程语言任重而道远 xff0c 如何准备学习是一个很关键的问题 今天小助手给大家分享如何开始学习编程语言的建议 xff0c 希望
  • html中如何传递数组,如何将数组从select html元素组件传递到数组中具有不同值的两个文本组件...

    我正在尝试在选择值之后从select元素中获取价格值 例如股票描述 数字发票QT 售价 100 但是我已经写了下面的代码 当我运行它时 我会得到这个错误 销售价格返回 未定义 所以我非常感谢你能帮我 因为我整天都在上网寻找帮助 import
  • Codeforces Round #589 div.2 C,D

    感觉这一场的复杂度非常的玄学 也可能是我偷懒太长时间变菜了QAQ C 题意 给出 x n 求x质因子的从1到n的g i p 的连乘思路 求出x的每个质因子 直接连乘到n计算即可 code include lt bits stdc 43 43
  • 微信支付报调用支付JSAPI缺少参数: sign

    检查后台返回参数中没有paySign字段 转载于 https www cnblogs com muou2125 p 11604456 html
  • Windows下使用命令打开远程桌面

    如果在Windows系统下找不到 远程桌面 入口 xff0c 可以使用命令方式打开 方法如下 xff1a 在命令提示符中输入如下命令 xff1a start mstsc exe 如果感觉每次都输入命令太麻烦 xff0c 可以新建一个bat批
  • 设置input 中placeholder的样式

    webkit input placeholder Chrome Opera Safari position relative top 4px moz placeholder Firefox 19 43 position relative t
  • 如何为Redis中list中的项设置过期时间

    问题 两种解决方法 有序集合 多个集合以及TTL Redis是一个伟大的工具 xff0c 用来在内存中存储列表是很合适的 不过 xff0c 如果你想要快速搜索列表 xff0c 同时需要让列表中每项都在一定时间后过期 xff0c 应该怎么做呢
  • Python 函数的 return 是否是必须的?

    Python 函数的 return 是否是必须的 xff1f return 表达式 语句用于退出函数 xff0c 选择性地向调用方返回一个表达式 不带参数值的return语句返回None 来看一段关于 return 的描述 xff1a re
  • Flutter 获取控件尺寸和位置

    1 插件必须渲染好 final RenderBox box 61 globalKey currentContext findRenderObject final size 61 box size final topLeftPosition

随机推荐

  • kepserver中文手册,kepserver使用教程,kepserver设置

    下面介绍一下KepServer模拟器的使用 xff0c 以下示例使用服务器随附的 Simulator 驱动程序来演示创建 配置和运行项目的过程 Simulator 驱动程序是基于内存的驱动程序 xff0c 能为演示提供静态数据和变化数据 1
  • 15 THINGS ALL GIRLS SHOULD KNOW ABOUT THEIR VAGINA

    Here are 15 facts that EVERY GIRL should know about her vagina Don t be shy Your vagina is part of your body and it will
  • 生产者/消费者模式的理解及实现

    简介 生产者消费者模式并不是GOF提出的23种设计模式之一 xff0c 23种设计模式都是建立在面向对象的基础之上的 xff0c 但其实面向过程的编程中也有很多高效的编程模式 xff0c 生产者消费者模式便是其中之一 xff0c 它是我们编
  • ios如何翻外墙_华强北版本Airpods值得入手吗?如何避坑?

    和许多同行一样 xff0c 本该还是读书的年纪就来到华强北摸爬滚打 xff0c 已然过了78个年头 今天 xff0c 我们就来谈谈华强北版的Airpodspro是否值得入手以及入手如何避坑 对于华强北Airpods网上的评价褒贬不一 有的人
  • 《大数据时代》读书笔记

    大数据时代 英国人Viktor Mayer Schonberger的著作 最重要的一点是介绍了一种思维模式的变化 主要观点 xff1a 大数据是指获取全部数据样本 xff0c 分析全部数据 xff0c 而不是只做抽样分析 大数据分析更关注相
  • Spring中Bean管理的常用注解

    在Spring中 xff0c 主要用于管理bean的注解分为四大类 xff1a 1 用于创建对象 2 用于给对象的属性注入值 3 用于改变作用的范围 4 用于定义生命周期 这几个在开发中经常接触到 xff0c 也可以说每天都会遇见 其中创建
  • 解决Duplicate class xxx found in modules编译报错的问题

    如果在Android工程编译失败 xff0c 并出现如下错误 xff1a Duplicate class com mygroup mylib MyBean found in modules jetified baselib1 1 0 1 r
  • 课后作业3:个人项目(词频统计及其效能分析)

    1 个人信息 学号 xff1a 2017 7189姓名 xff1a 李博文码云地址 xff1a https gitee com libowena9 word frequency tree ES7189 2 程序分析 读取文件到缓冲区 def
  • IdentityServer4与ocelot实现认证与客户端统一入口

    关于IdentityServer4与ocelot博客园里已经有很多介绍我这里就不再重复了 ocelot与IdentityServer4组合认证博客园里也有很多 xff0c 但大多使用ocelot内置的认证 xff0c 而且大多都是用来认证A
  • JAVA: 接入YSDK遇到的问题

    JAVA后台接口 1 腾讯开放平台 http wiki open qq com wiki E9 A6 96 E9 A1 B5 2 YSDK介绍 大概流程 http wiki open qq com wiki YSDK E4 BB 8B E7
  • 红白黑球组合问题

    从3个红球 6个白球和7个黑球中 xff0c 任意取出8个球作为一组输出 xff0c 在每组中 xff0c 可以没有黑球 xff0c 但必须要有红球和白球 求总的组数以及每组的红球 白球 黑球的数目 思路 红球取值范围为1个到3个 xff0
  • 让我持续下去的理由

    牛仔裤 格子衬衫 运动鞋和双肩包 如果把这四个词放在一个人的身上 xff0c 似乎不用描述长相 xff0c 大家就对他的职业有了猜测 八成是个程序员吧 这个被笑称 月入五万过成月入五千样子 的群体 xff0c 以 收入高 脑回路简单 一成不
  • .NET程序集

    主要内容 64 将源代码编译为托管模块 64 将模块组合为程序集 64 共享程序集 xff08 强签名 xff09 概念阐述 64 将源代码编译为托管模块 1 在 NET框架里 xff0c 我们可以用任何支持CLR xff08 Common
  • android alertdialog横竖屏旋转_如何在哔哩哔哩做横竖屏直播

    哔哩哔哩 以下简称B站 xff0c 说到这个名字 xff0c 可能有些朋友比较陌生 xff0c 对于大多数的年轻人 xff0c 尤其是喜欢二次元文化的年轻人来说 xff0c B站是他们非常钟爱的直播平台 现在的B站已经不单单是一个视频网站
  • 读书小记--<态度>

    前言 前段时间再读了吴军老师的 态度 xff0c 分享的是和女儿的日常书信 觉得收获很多 xff0c 同事推荐他的 浪潮之巅 数学之美 系列书籍 下面是个人的觉得认同或值得深入学习的一些点 xff0c 特此记录一下 态度决定命运 文中写道撒
  • Oracle大表改为分区表及表空间切换方案

    Oracle大表改为分区表及表空间切换方案 一 背景 由于之前数据库表和索引放在一个表空间导致表空间数据文件增长太快 xff0c 文件数量即将达到Oracle表空间的限制 xff0c 需要对表 没有分区 xff0c 有些表数据量多达几十亿
  • ORACLE表、索引和分区

    ORACLE 表 索引和分区 一 数据库表 每种类型的表都有不同的特性 xff0c 分别应用与不同的领域 堆组织表 聚簇表 共三种 索引组织表 嵌套表 临时表 外部表和对象表 1 行迁移 建表过程中可以指定以下两个参数 xff1a PCTF
  • ffmpeg常用命令

    之前在处理监控视频时要对视频进行抽帧压缩 xff0c 使得视频大小限制在10M左右 xff0c 所以使用ffmpeg进行视频加工处理 xff0c 因为这个工具确实很强大 下面是用到的相关命令 xff0c 可以直接跳到最后一条命令 xff0c
  • 去哪儿网2015校招研发类笔试题

    从网上找到的题目 xff0c 自己做了一遍 1 二分查找 2 给定一个字符串 xff0c 得到这个字符串中首先出现两次的那个字符 方法 xff1a 可以用一个hash map或者数组来存储字符出现的次数 xff0c 一旦有一个出现了2次 x
  • WebGL学习笔记(4)

    本篇笔记加强了上篇笔记示例代码的程序 xff0c 实现了使用nodejs websocket来广播每个玩家的坐标数据并在同一个世界模型中进行多人在线交互 websocket服务端 xff1a 安装nodejs与npm xff0c 创建一个服