如何在 WebGL 中一个接一个滚动两个不同的纹理(以滚动方式 - 附上小提琴以供参考)? [英] How to scroll two different textures(in a scrolling manner- fiddle attached for reference) one after the other in WebGL?

查看:30
本文介绍了如何在 WebGL 中一个接一个滚动两个不同的纹理(以滚动方式 - 附上小提琴以供参考)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一些东西,即一个接一个的滚动纹理,就像 HTML 中仅滚动文本的选取框一样.

I am trying to achieve something i.e. a scrolling texture one after the other same as a marquee in HTML that just scrolls the text.

这是我到目前为止所做的:Fiddle ,如果你加载它,你会看到第一个纹理正确滚动,第二个纹理刚刚出现一段时间后(我为此保留了 10 秒).

Here's is what I have done so far : Fiddle , if you load it you will see first texture scrolling correctly and the second texture just comes over it after sometime(I kept 10 seconds for this).

但理想情况下,它的行为应该一个接一个,例如:如果这是一个测试"是一个字幕,那么它们一个接一个地出现.同样,Image1 必须在一些空格后跟 Image2".我希望我的问题很清楚.

But ideally, it should behave like one after the other, for eg: if "This is a test" is a marquee, then they come one after the other. Similarly , "Image1 must be followed by Image2 after some space". I hope I am clear with my question.

另外,加起来,方法sendImageLineByLine()是在server中实现的,只是为了添加一个测试用例,我添加了虚拟图像.

Also, to add up, the method sendImageLineByLine() is implemented in server , just for the sake of adding a test case , I have added it with dummy images.

// 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();

<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>

推荐答案

使用更简单的方法可以达到预期的效果.你只需要一个四边形(基本上,一个由两个三角形组成的正方形),它会被绘制两次(或者你想要的次数),并应用不同的纹理和偏移.顶点着色器可能看起来像这样:

Desired effect may be achieved with much simpler approach. You just need a quad (basically, a square comprised of two triangles), which will be drawn twice (or as many times as you want) with different textures and offsets applied. Vertex shader may look somewhat like this:

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;
}

片段着色器将是微不足道的.而每一帧你只需要更新四边形的偏移量并重新绘制它们:

Fragment shader will be trivial. And each frame you just need to update quad's offsets and redraw them:

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()

现在通过操纵增量和初始偏移值,您可以使两张图像一个接一个滑动,甚至以不同的速度滑动(例如用于视差效果).

Now by manipulating deltas and initial offset values, you can get two images sliding one right after the other or even with different speeds (e.g. for parallax effect).

这篇关于如何在 WebGL 中一个接一个滚动两个不同的纹理(以滚动方式 - 附上小提琴以供参考)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆