我正在努力实现一些东西,即一个接一个地滚动纹理,就像滚动文本的HTML中的选框一样。
这是我到目前为止所做的事情: Fiddle,如果你加载它,你会看到第一个纹理正确滚动,第二个纹理在一段时间之后就会超过它(我保持10秒钟)。
但理想情况下,它应该像一个接一个地表现,例如:if"这是一个测试"是一个大帐篷,然后他们一个接一个地来。类似地," Image1必须在一些空格后跟随Image2"。 我希望我对自己的问题很清楚。
另外,为了加起来,方法sendImageLineByLine()
在服务器中实现,只是为了添加一个测试用例,我添加了虚拟图像。
// WEBGL UTIL START
// jshint ignore: start
var addHeading = function (text) {
var h1 = document.createElement('h1');
h1.innerHTML = text;
document.body.appendChild(h1);
};
var drawCanvas = function (width, height) {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
document.body.appendChild(canvas);
return canvas;
};
var getGLContext = function(canvas){
var ctx = null;
if (canvas == null){
alert('there is no canvas on this page');
return null;
}
else {
c_width = canvas.width;
c_height = canvas.height;
}
var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
for (var i = 0; i < names.length; ++i) {
try {
ctx = canvas.getContext(names[i]);
}
catch(e) {}
if (ctx) {
break;
}
}
if (ctx == null) {
alert("Could not initialise WebGL");
return null;
}
else {
return ctx;
}
}
var createVertexShader = function (vertexShaderSource) {
console.log(vertexShaderSource);
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
return vertexShader;
}
var createFragmentShader = function (fragmentShaderSource) {
console.log(fragmentShaderSource);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
return fragmentShader;
}
var createAndLinkPrograms = function (vertexShader, fragmentShader) {
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);
return program;
}
var createAndBindBuffer = function (verticesOrIndices, bufferType) {
var buffer = gl.createBuffer();
gl.bindBuffer(bufferType, buffer);
gl.bufferData(bufferType, verticesOrIndices, gl.STATIC_DRAW);
//clear memory
// gl.bindBuffer(bufferType, null);
return buffer;
}
var allowAllImageSizes = function() {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.bindTexture(gl.TEXTURE_2D, null);
}
// WEBGL UTIL END
var gl = null, canvas = null;
var $ = window.$;
var imageContainer = [];
var buffer = null;
//update canvas area
var updateCanvasSize = function () {
canvas = document.getElementById('scrollingCanvas');
canvas.width = window.innerWidth * 0.99;
canvas.height = window.innerHeight * 0.79;
var userAg = navigator.userAgent;
if (userAg.indexOf('Chrome') !== -1) {
canvas.height = window.innerHeight * 0.794;
} else if (userAg.indexOf('Firefox')!== -1) {
canvas.height = window.innerHeight * 0.782;
} else if (userAg.indexOf('Opera')!== -1) {
canvas.height = window.innerHeight * 0.782;
} else if (userAg.indexOf('Trident')!== -1) {
canvas.height = window.innerHeight * 0.880;
} else if (userAg.indexOf('Safari')!== -1) {
canvas.height = window.innerHeight * 0.784;
} else {
window.alert('unknown browser <br><br>');
}
};
updateCanvasSize();
gl = getGLContext(canvas);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT || gl.DEPTH_BUFFER_BIT);
var vertexShader = createVertexShader([
'attribute vec4 aVertexPosition;',
'uniform float u_CosB;',
'uniform float u_SinB;',
'attribute vec2 aTextureCoord;',
'attribute float aOffset;',
'varying highp vec2 vTextureCoord;',
'varying highp float offset;',
'void main(void) {',
'gl_Position = aVertexPosition;',
'vTextureCoord = aTextureCoord;',
'offset = aOffset;',
'}'
].join('\n'));
var fragmentShader = createFragmentShader([
'#ifdef GL_ES',
'precision highp float;',
'#endif',
'varying highp vec2 vTextureCoord;',
'uniform float offset;',
'uniform sampler2D uSampler;',
'void main(void) {',
'gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s - offset, vTextureCoord.t));',
'}'
].join('\n'));
var program = createAndLinkPrograms(vertexShader, fragmentShader);
//get glsl attributes
var glslAVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
gl.enableVertexAttribArray(glslAVertexPosition);
var glslATextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
gl.enableVertexAttribArray(glslATextureCoord);
//create vertex and indices coordinates
var vertices = new Float32Array([ -1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0]);
var textureCoordinates = new Float32Array([ 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]);
var indices = new Uint16Array([ 0, 1, 2, 0, 2, 3]);
var vertexBuffer = createAndBindBuffer(vertices, gl.ARRAY_BUFFER);
var textureCoordBuffer = createAndBindBuffer(textureCoordinates, gl.ARRAY_BUFFER);
var indicesBuffer = createAndBindBuffer(indices, gl.ELEMENT_ARRAY_BUFFER);
var texture = null;
var offset = 1.0;
var changeVal = 0.030;
var i, j, k, m, willRefresh = false;
var scrollBag = setInterval(function() {
/*if(willRefresh) {
offset -= 0.0015;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
gl.uniform1f(gl.getUniformLocation(program, 'offset'), offset);
gl.uniform1f(gl.getUniformLocation(program, 'uSampler'), 0);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}*/
},16);
var counter=0;
var ANGLE = 10.0;
var fps = document.getElementById('fps');
animate();
function animate() {
window.requestAnimationFrame( animate );
if(willRefresh) {
offset -= 0.0015;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
gl.uniform1f(gl.getUniformLocation(program, 'offset'), offset);
// var uTranslation = gl.getUniformLocation(gl.program, 'u_Translation');
var radian = Math.PI * ANGLE / 180.0; // Convert to radians
var cosB = Math.cos(radian);
var sinB = Math.sin(radian);
var uCosB = gl.getUniformLocation(gl.program, 'u_CosB');
var uSinB = gl.getUniformLocation(gl.program, 'u_SinB');
gl.uniform1f(uCosB, cosB);
gl.uniform1f(uSinB, sinB);
// gl.uniform4f(uTranslation, offset, 0.0, 0.0, 0.0);
gl.uniform1f(gl.getUniformLocation(program, 'uSampler'), 0);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
counter++;
}
}
setInterval(function(){ fps.innerHTML = counter + 'fps'; counter=0; },1000);
var lineArray = [];
var renderLineData = function (imageAttr) {
var data = imageAttr.data;
var alpha = 4;
if(imageAttr.newImage) {
offset = 1.0;
texture = gl.createTexture();
willRefresh = true;
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, imageAttr.width, imageAttr.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
allowAllImageSizes();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.vertexAttribPointer(glslAVertexPosition, 3, gl.FLOAT, gl.FALSE, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
gl.vertexAttribPointer(glslATextureCoord, 2, gl.FLOAT, gl.FALSE, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.generateMipmap(gl.TEXTURE_2D);
}
var dataTypedArray = new Uint8Array(imageAttr.height * alpha);
//render new line
for (i = 0, k = 0, m = 3; i < 1; i++) {
for (j = 0 ; j < imageAttr.height; j++) {
dataTypedArray[m-3] = data[k++];
dataTypedArray[m-2] = data[k++];
dataTypedArray[m-1] = data[k++];
dataTypedArray[m] = data[k++];
m += 4;
}
}
gl.texSubImage2D(gl.TEXTURE_2D, 0, imageAttr.index, 0, 1, imageAttr.height, gl.RGBA, gl.UNSIGNED_BYTE, dataTypedArray);
if(imageAttr.index === imageAttr.width-1) {
/*clearInterval(scrollBag);
window.alert('scrolling stopped');
willRefresh = false;*/
}
dataTypedArray = null;
};
var simulateImages = function (width, height, index, data, newImage) {
//Create a new Object to be delivered to Client.
var lineData = {};
lineData.width = width;
lineData.height = height;
lineData.index = index;
lineData.data = data;
lineData.newImage = newImage;
renderLineData(lineData);
}
var lineNumber = 1;
var sendImageLineByLine = function () {
//first image
var k = 0;
var newImage = true;
var imageData = ctx1.getImageData(0, 0 , canvas1.width, canvas1. height);
var height = imageData.height;
var width = imageData.width;
var data = imageData.data;
var lineDataArr = new ArrayBuffer(height*4);
for (var i = 0 ; i < width; i++) {
k = 0;
for (var j = 0 ; j < height; j++) {
lineDataArr[k++] = data[(i * 4 + width * 4 * j)]; //red
lineDataArr[k++] = data[(i * 4 + width * 4 * j) + 1]; // blue
lineDataArr[k++] = data[(i * 4 + width * 4 * j) + 2]; //green
lineDataArr[k++] = data[(i * 4 + width * 4 * j) + 3]; //alpha
}
simulateImages(width, height, lineNumber++, lineDataArr, newImage);
lineDataArr = new ArrayBuffer(height*4);
newImage = false;
}
//second image
setTimeout (function () {
console.log('uiuiuiui');
lineNumber = 1;
k = 0;
imageData = ctx2.getImageData(0, 0 , canvas2.width, canvas2. height);
height = imageData.height;
width = imageData.width;
data = imageData.data;
lineDataArr = new ArrayBuffer(height*4);
for (var i = 0 ; i < width; i++) {
k = 0;
for (var j = 0 ; j < height; j++) {
lineDataArr[k++] = data[(i * 4 + width * 4 * j)]; //red
lineDataArr[k++] = data[(i * 4 + width * 4 * j) + 1]; //green
lineDataArr[k++] = data[(i * 4 + width * 4 * j) + 2]; //blue
lineDataArr[k++] = data[(i * 4 + width * 4 * j) + 3]; //alpha
}
simulateImages(width, height, lineNumber++, lineDataArr, newImage);
lineDataArr = new ArrayBuffer(height*4);
newImage = false;
}
}, 10000);
console.log('Complete');
}
var canvas1 = document.getElementById('canvas1');
var canvas2 = document.getElementById('canvas2');
var ctx1 = canvas1.getContext('2d');
var ctx2 = canvas2.getContext('2d');
ctx1.fillStyle = "red";
ctx2.fillStyle = "green";
for (var i = 0; i < 10; i++) {
ctx1.fillRect(Math.random()*150,Math.random()*150,Math.random()*100,Math.random()*100);
ctx2.fillRect(Math.random()*150,Math.random()*150,Math.random()*100,Math.random()*100);
}
sendImageLineByLine();
&#13;
<p id="fps"></p>
<canvas id="canvas1" style="display:none" ></canvas><hr/>
<canvas id="canvas2" style="display:none" ></canvas>
<canvas id="scrollingCanvas" width="512" height="512"></canvas>
&#13;
答案 0 :(得分:0)
可以通过更简单的方法实现期望的效果。你只需要一个四边形(基本上是一个由两个三角形组成的正方形),它将被绘制两次(或根据你的需要多次),并应用不同的纹理和偏移。顶点着色器可能看起来像这样:
attribute vec2 vertexPosition;
attribute vec2 vertexTexCoord;
varying vec2 texCoord;
uniform float offsetX;
void main(void) {
gl_Position = vec4(vertexPosition + vec2(offsetX, 0), 0, 1);
texCoord = vertexTexCoord;
}
片段着色器将是微不足道的。每个帧你只需要更新四边形的偏移并重绘它们:
gl.clear(gl.COLOR_BUFFER_BIT);
// You also may want to "wrap" the offsets around so quads
// will come from the left edge of the canvas after disappearing
// to the right.
quad1OffsetY += offsetDelta;
quad2OffsetY += offsetDelta;
// Let's draw the quad first time
gl.uniform1f(offsetYUniformLocation, quad1OffsetY);
gl.bindTexture(gl.TEXTURE2D, quad1Texture);
gl.drawArrays(/* ... */); // or gl.drawElements()
// and the second time
gl.uniform1f(offsetYUniformLocation, quad2OffsetY);
gl.bindTexture(gl.TEXTURE2D, quad2Texture);
gl.drawArrays(/* ... */); // or gl.drawElements()
现在通过操纵增量和初始偏移值,您可以获得两个图像,一个接一个地滑动,或者甚至以不同的速度滑动(例如,用于视差效果)。