WebGL学习笔记(4)
本篇笔记加强了上篇笔记示例代码的程序,实现了使用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>
WebGL学习笔记(4)的更多相关文章
- webgl学习笔记五-纹理
写在前面 建议先阅读下前面我的三篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 webgl学习笔记三-平移旋转缩放 术语 : 纹理 :图像 图形装配区域 :顶点着色器顶点坐标 ...
- webgl学习笔记四-动画
写在前面 建议先阅读下前面我的三篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 webgl学习笔记三-平移旋转缩放 下面我们将讲解下如何让一个正方形动起来~不断擦除和重绘 ...
- webgl学习笔记三-平移旋转缩放
写在前面 建议先阅读下前面我的两篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 平移 1.关键点说明 顶点着色器需要加上 uniform vec4 u_Translation ...
- webgl学习笔记二-绘图多点
写在前面 建议先看下第一篇webgl学习笔记一-绘图单点 第一篇文章,介绍了如何用webgl绘图一个点.接下来本文介绍的是如何绘制多个点.形成一个面. webgl提供了一种很方便的机制,即缓冲区对象, ...
- WebGL学习笔记二——绘制基本图元
webGL的基本图元点.线.三角形 gl.drawArrays(mode, first,count) first,代表从第几个点开始绘制即顶点的起始位置 count,代表绘制的点的数量. mode,代 ...
- WebGL学习笔记(2)
根据上一篇学习笔记,理解WebGL的工作原理及基本调用代码后,可以开始研究3D顶点对象的缩放.旋转.以及对对象进行可交互(鼠标或键盘控制)的旋转或者缩放. 要理解对象的旋转/缩放需要首先学习矩阵的计算 ...
- WEBGL学习笔记(七):实践练手1-飞行类小游戏之游戏控制
接上一节,游戏控制首先要解决的就是碰撞检测了 这里用到了学习笔记(三)射线检测的内容了 以鸟为射线原点,向前.上.下分别发射3个射线,射线的长度较短大概为10~30. 根据上一节场景的建设,我把y轴设 ...
- WebGL学习笔记(3)
根据上篇笔记,在对3D对象可进行普通的控制后,以及学习了http://hiwebgl.com的教程第10章内容:世界模型的载入以及控制镜头移动,经过多次调试矩阵代码,已经可以实现在世界中旋转镜头/控制 ...
- WebGL学习笔记七点一
第六章讲的是一些GL的一些语法,前面已经涉及,学习时直接跳过,来看第七章,第七章是真正意义的三维立体的出现,其实图形绘制方法是差不多的,就是Z坐标此时不再为0,所以很容易能构造出一些立体图形,但是立体 ...
- WebGL学习笔记一
学习用来做web3D的,从第一页开始学起先做2D的,接下来的程序是一个入门级的程序,可以通过在画板上的不同位置点击而获取不同颜色的点,以画板中心为坐标原点四个象限有不同的颜色,访问地址 http:/ ...
随机推荐
- sp_addlinkedserver创建远程服务器查询
远程服务器查询可以分两步完成: 1.建立连接服务器 exec sp_addlinkedserver @server='Test_Server', --被访问的服务器别名 @srvproduct='', ...
- SQL使用bcp方式导入,导出数据2
select * from A_Account EXEC sp_configure 'allow_updates' GO EXEC sp_configure 'allow_updates',0; ...
- js异步流程控制-回调
f1为耗时操作,f2依赖f1的数据,因此f2必须在f1之后执行: 个人理解是:将f2(回调函数)的代码放在异步函数内部的最后执行,相当于把同步操作的代码融合到异步函数内部的最后: let tag = ...
- html+css定位篇
position absolute相对于父元素移动,不在父元素范围内时,可能和其他元素重叠 relative相对于初始位置来进行移动 fixed相对于浏览器进行定位,无论滑轮如何滚动,始终出现在浏览器 ...
- Oracle运行依赖的服务
1.Oracle ORCL VSS Writer Service. Oracle卷映射拷贝写入服务,VSS(Volume Shadow Copy Service)能够让存储基础设备(比如磁盘,阵列等) ...
- iPython与notebook的基本用法
1 Ipython 安装 pip install ipython 2 Notebooke 基本用法 启动ipython使用ipython 启动notebook 使用 ipython notebook ...
- SOL的补充
之前写过一些关于远程安装系统的文档,但是对于SOL还是糊涂不清. Serial Console 可以将输入输出转发到串行接口(com1, com2), 假如你有串行读取设备,就可以看到显示,控制输入. ...
- VueJS 使用i18n做国际化切换中英文
1.安装 npm install vue-i18n --save 2.创建存放语言包和i18n入口文件 a.在src下创建i18n目录 b.在src/i18n/创建i18n.js (入口) c.在s ...
- VC++动态链接库(DLL)编程
一.概论 1:http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/698632.html 2:http://pcedu.pconline.com. ...
- Linux--DHCP搭建
服务功能:为局域网中的主机自动分配IP地址.子网掩码.广播地址.默认网关地址.DNS服务器地址 1.安装DHCP服务器软件 [root@localhost Packages]# rpm -ivh dh ...