gpt4 book ai didi

javascript - WebGL:如何将移动纹理叠加在另一个纹理之上?

转载 作者:行者123 更新时间:2023-11-30 20:01:15 25 4
gpt4 key购买 nike

对于荣誉学分无关的类(class)项目,我需要使用 WebGL 来显示我选择的用作纹理的图像,然后变形纹理以使其看起来像是在以某种方式移动或变化。

为此,我选择变形雨滴纹理,使其看起来就像雨滴从屏幕上掉下来一样。我有一个风景背景纹理(一个 .jpg 图像),我想用雨滴纹理(一个 .png 图像)覆盖它,但我不确定如何覆盖背景纹理以便我可以在同时。我现在拥有的代码仅显示背景图像。

谁能帮我解释一下我做错了什么,我该如何解决这个问题?如果您需要我上传我的部分代码以查看,请告诉我。我几乎不了解 WebGL,所以我不知道要显示我的代码的哪个区域才能看到我哪里出错了。据我所知,整件事可能都是错的。

编辑:我被告知要添加代码,所以由于我不知道要显示什么片段,这里是我的整个 javascript 和 html 文件:

另请注意:此代码仅适用于 FireFox!谷歌浏览器会报错! (虽然我认为不管怎样都会报错,因为我没有给出.html文件中引用的文件)*

var canvas;
var gl;

var Index = 0;

var texCoord = [
vec2(0, 0),
vec2(0, 1),
vec2(1, 1),
vec2(1, 1),
vec2(1, 0),
vec2(0, 0)
];

var vertices = [
vec2( -1, -1 ),
vec2( -1, 1 ),
vec2( 1, 1 ),
vec2( 1, 1 ),
vec2( 1, -1 ),
vec2( -1, -1 )
];

var pointsArray = [];

//PROGRAMS
var program1; //for background
var program2; //for rain texture
var program3; //for rain texture updates


//TEXTURES
var texture1; //background image (STATIC IMAGE)
var texture2; // Raindrop texture (bounce between 2 and 3)
var texture3; // Raindrop texture (transform to be sent between 2 and 3)


//BUFFERS--------------------------------------------------------------------
var framebuffer;

var buffer1; //buffer for static background (texture1) vertices
var buffer2; //buffer for static background (texture1) texcoordinates
var buffer3; //buffer for raindrops (texture2) vertices
var buffer4; //buffer for raindrops (texture2) texcoordinates
var buffer5; //buffer for texture3 vertices
var buffer6; //buffer for texture3 texcoordinates


window.onload = function init() {
canvas = document.getElementById( "gl-canvas" );

gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }

//----------------------------------------------------------------------------------------------------------------------------------------
//BACKGROUND texture
texture1 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture1);

// Fill the texture with a blue screen (fill canvas) FILLER!!!
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2048, 1024, 0, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array([0, 0, 255, 255]));

// load image

gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);

// Get the IMG tag by its ID
var bgpic = document.getElementById("background");


gl.bindTexture(gl.TEXTURE_2D, texture1);

// Load data from the IMG
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bgpic);

gl.generateMipmap(gl.TEXTURE_2D);

//------------------------------------------------------------------------------------------------------------------------------------------

//RAINDROP TEXTURE
texture2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture2);

// Fill the texture with a blue screen (fill canvas) FILLER!!!
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2048, 1024, 0, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array([0, 0, 255, 255]));

// load image

gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);

// Get the IMG tag by its ID
var rainPic = document.getElementById("raindrop");


gl.bindTexture(gl.TEXTURE_2D, texture2);

// Load data from the IMG
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, rainPic);

gl.generateMipmap(gl.TEXTURE_2D);


//------------------------------------------------------------------------------------------------------------------------------------------
//EMPTY TEXTURE TO PASS TEXTURE2 TO
texture3 = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, texture2 );
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2048, 1024, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
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 );

//------------------------------------------------------------------------------------------------------------------------------------------
// Allocate a frame buffer object

framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
framebuffer.width = 4096;
framebuffer.height = 2048;

//------------------------------------------------------------------------------------------------------------------------------------------

// Attach color buffer

gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture1, 0);

//------------------------------------------------------------------------------------------------------------------------------------------
// check for completeness

var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if(status != gl.FRAMEBUFFER_COMPLETE) alert('Frame Buffer Not Complete');
//------------------------------------------------------------------------------------------------------------------------------------------
//
// Load shaders and initialize attribute buffers
//
program1 = initShaders( gl, "vertex-shader1", "fragment-shader1" );
program2 = initShaders( gl, "vertex-shader2", "fragment-shader2" );
program3 = initShaders(gl, "vertex-shader3","fragment-shader3");
//------------------------------------------------------------------------------------------------------------------------------------------
//PROGRAM 1 CODE
gl.useProgram( program1 );

gl.useProgram(program1);

gl.activeTexture(gl.TEXTURE0);

gl.bindTexture(gl.TEXTURE_2D, texture1);

// send data to GPU for normal render

buffer1 = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, buffer1);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW);

var vPosition = gl.getAttribLocation( program1, "vPosition" );
gl.vertexAttribPointer( vPosition, 2, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );

buffer2 = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, buffer2);
gl.bufferData( gl.ARRAY_BUFFER, flatten(texCoord), gl.STATIC_DRAW);

var vTexCoord = gl.getAttribLocation( program1, "vTexCoord");
gl.vertexAttribPointer( vTexCoord, 2, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vTexCoord );

gl.uniform1i( gl.getUniformLocation(program1, "texture1"), 0);

gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.viewport(0, 0, 2048, 1024);

gl.bindFramebuffer(gl.FRAMEBUFFER, null);

//------------------------------------------------------------------------------------------------------------------------------------------

//PROGRAM 2 CODE
gl.useProgram(program2);

// Create and initialize a buffer object
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture2);

buffer3 = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, buffer3 );
gl.bufferData( gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW );

var vPosition = gl.getAttribLocation( program2, "vPosition" );
gl.vertexAttribPointer( vPosition, 2, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );

// Bind FBO and render

gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);


gl.viewport(0, 0, 2048, 1024);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT );

// gl.drawArrays(gl.TRIANGLES, 0, numVertices);

// Bind to window system frame buffer, unbind the texture

gl.bindFramebuffer(gl.FRAMEBUFFER, null);

//------------------------------------------------------------------------------------------------------------------------------------------
//PROGRAM 3 CODE
gl.useProgram(program3);

gl.activeTexture(gl.TEXTURE0);

gl.bindTexture(gl.TEXTURE_2D, texture3);

// send data to GPU for normal render

buffer5 = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, buffer5);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW);

var vPosition = gl.getAttribLocation( program3, "vPosition" );
gl.vertexAttribPointer( vPosition, 2, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );

buffer6 = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, buffer6);
gl.bufferData( gl.ARRAY_BUFFER, flatten(texCoord), gl.STATIC_DRAW);

var vTexCoord = gl.getAttribLocation( program3, "vTexCoord");
gl.vertexAttribPointer( vTexCoord, 2, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vTexCoord );

gl.uniform1i( gl.getUniformLocation(program3, "texture2"), 0);

gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.viewport(0, 0, 2048, 1024);


render();

}


function render() {

// render to texture

//------------------------------------------------------------------------------------------------------------------------------------------
// SECTION FOR BACKGROUND TEXTURE!
//BACKGROUND TEXTURE: USE PROGRAM 1
gl.useProgram(program1);

gl.clear( gl.COLOR_BUFFER_BIT );
gl.drawArrays( gl.TRIANGLES, 0, 6 );

gl.bindFramebuffer( gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, texture1);

gl.clear( gl.COLOR_BUFFER_BIT );
gl.drawArrays(gl.TRIANGLES, 0, 6);

//------------------------------------------------------------------------------------------------------------------------------------------
//RAIN TEXTURE: USE PROGRAM 2
gl.useProgram(program2);

gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer);

if(flag) {
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture3, 0);

}
else {
gl.bindTexture(gl.TEXTURE_2D, texture3);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture2, 0);

}

//------------------------------------------------------------------------------------------------------------------------------------------
// RAIN TEXTURE: USE PROGRAM 3

gl.useProgram(program3);


gl.drawArrays( gl.TRIANGLES, 0, 6 );

gl.bindFramebuffer( gl.FRAMEBUFFER, null);
if(flag) gl.bindTexture(gl.TEXTURE_2D, texture2);
else gl.bindTexture(gl.TEXTURE_2D, texture2);

gl.clear( gl.COLOR_BUFFER_BIT );
gl.drawArrays(gl.TRIANGLES, 0, 6);

flag = !flag

requestAnimFrame(render);

}
<!DOCTYPE html>
<html>

<script id="vertex-shader1" type="x-shader/x-vertex">

attribute vec4 vPosition;
attribute vec2 vTexCoord;

varying vec2 fTexCoord;

void main()
{
gl_Position = vPosition;
fTexCoord= vTexCoord;
}
</script>

<script id="vertex-shader2" type="x-shader/x-vertex">

attribute vec4 vPosition;

attribute vec2 vTexCoord;

varying vec2 fTexCoord;

void main()
{
gl_Position = vPosition;
fTexCoord= vTexCoord;

}
</script>

<script id="vertex-shader3" type="x-shader/x-vertex">

attribute vec4 vPosition;
attribute vec2 vTexCoord;

varying vec2 fTexCoord;

void main()
{

gl_Position = vPosition;
fTexCoord = vTexCoord;

}
</script>

<script id="fragment-shader1" type="x-shader/x-fragment">

precision mediump float;

uniform sampler2D texture1;

varying vec2 fTexCoord;

void
main()
{
gl_FragColor= texture2D(texture1, fTexCoord);
}

</script>

<script id="fragment-shader2" type="x-shader/x-fragment">

precision mediump float;

uniform sampler2D texture2;

varying vec2 fTexCoord;

void main()
{
gl_FragColor= texture2D(texture2, fTexCoord);

}
</script>

<script id="fragment-shader3" type="x-shader/x-fragment">

precision mediump float;

varying vec2 fTexCoord;

uniform sampler2D texture2;

void main()
{
float y= fTexCoord.y - 0.1;
float x= fTexCoord.x;

if(y < 0.0) {
y = 1.0;
x = fTexCoord.x + 0.1 ;
}
if(x > 1.0){
x = 0.0;
}

gl_FragColor = texture2D( texture2, vec2(x,y));

}

</script>

<script type="text/javascript" src="../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../Common/InitShaders.js"></script>
<script type="text/javascript" src="../Common/MV.js"></script>
<script type="text/javascript" src="testingBG.js"></script>

<img src="Raindrops_scaled.png" id="raindrop" hidden />
<img src="Background.jpg" id="background" hidden />

<body>
<canvas id="gl-canvas" width="2048" height="1024">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>

最佳答案

我已尝试提供更全面的解释,说明适合您的解决方案可能包含哪些内容。

由于 cors >,这在 chrome 中可能不起作用 >.>

编辑:通过手动将图像作为位图数组插入来绕过 cors。 T.T

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}

canvas {
display: block;
margin: auto;
border: solid 1px white;
border-radius: 10px;
}

img {
display: none;
}
</style>
</head>

<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">

// I've only placed this here to get around cors < _ >
var images = function() {

"use strict";

function Image(width,height,pixels) {
this.width = width;
this.height = height;
this.pixels = pixels;
}

return {
background: new Image(16,16,new Uint8Array([127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,95,95,95,255,95,95,95,255,127,127,127,255,127,127,127,255,127,127,127,255,95,95,95,255,127,127,127,255,127,127,127,255,95,95,95,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,95,95,95,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,95,95,95,255,127,127,127,255,127,127,127,255,95,95,95,255,127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255,95,95,95,255,95,95,95,255,95,95,95,255,153,217,234,255,95,95,95,255,127,127,127,255,127,127,127,255,95,95,95,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,95,95,95,255,95,95,95,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,22,116,50,255,22,116,50,255,22,116,50,255,22,116,50,255,22,116,50,255,22,116,50,255,22,116,50,255,22,116,50,255,153,217,234,255,153,217,234,255,153,217,234,255,153,217,234,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255,34,177,76,255])),
raindrop: new Image(8,8,new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,41,49,151,255,41,49,151,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,49,151,255,64,73,202,255,64,73,202,255,41,49,151,255,0,0,0,0,0,0,0,0,0,0,0,0,41,49,151,255,64,73,202,255,64,73,202,255,64,73,202,255,64,73,202,255,41,49,151,255,0,0,0,0,0,0,0,0,41,49,151,255,64,73,202,255,64,73,202,255,64,73,202,255,64,73,202,255,41,49,151,255,0,0,0,0,41,49,151,255,64,73,202,255,64,73,202,255,64,73,202,255,64,73,202,255,64,73,202,255,64,73,202,255,41,49,151,255,41,49,151,255,64,73,202,255,64,73,202,255,64,73,202,255,64,73,202,255,64,73,202,255,64,73,202,255,41,49,151,255,0,0,0,0,41,49,151,255,64,73,202,255,64,73,202,255,64,73,202,255,64,73,202,255,41,49,151,255,0,0,0,0,0,0,0,0,0,0,0,0,41,49,151,255,41,49,151,255,41,49,151,255,41,49,151,255,0,0,0,0,0,0,0,0]))
};

}();

void function() {

"use strict";

// Variables
var canvasWidth = 180;
var canvasHeight = 160;
var canvas = null;
var gl = null;
var raindrops = [];

// WebGL programs (contains code that modifies your vertex data & code that processes each pixel)
var backgroundProgram = null;
var raindropProgram = null;

// WebGL program attributes (indexes into attributes inside the program, webgl uses these to interpret data in the buffers)
var aPositionLocation = 0;
var aUVLocation = 1;

// WebGL program uniforms (It's a variable that's shared between Javascript and the program, you just need to call a function to update it's value)
var uRaindropPosition = null; // vec2
var uRaindropSize = null; // vec2

// WebGL buffers (It's like an array '[]', but it's on the GPU, we'll use it here to specify the properties of triangles we want to draw)
var backgroundBuffer = null;

// WebGL textures
var backgroundTexture = null;
var raindropTexture = null;

// Constructors
// If this function is called with 'new Raindrop(0,0,10);' it'll create a new raindrop object that has these properties
function Raindrop(x,y,size) {
this.x = x;
this.y = y;
this.size = size;
}

// Functions
function createProgram(vertexCode,fragmentCode) {
var program = gl.createProgram();
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

// Upload source code
gl.shaderSource(vertexShader,vertexCode);
gl.shaderSource(fragmentShader,fragmentCode);

// Compile shaders
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);

// Check there isn't any problems
try {
if (!gl.getShaderParameter(vertexShader,gl.COMPILE_STATUS)) {
throw "Vertex Shader: " + gl.getShaderInfoLog(vertexShader);
}

if (!gl.getShaderParameter(fragmentShader,gl.COMPILE_STATUS)) {
throw "Fragment Shader: " + gl.getShaderInfoLog(fragmentShader);
}
} catch(log) {
gl.deleteProgram(program);
gl.deleteShader(vertexShader);
gl.deleteShader(vertexShader);
console.error(log);
}

// Attach to the main program
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);

return program;
}

function createBuffer(data) {
// Create a GPU buffer, it's a really simple object
// Buffers can be best thought of as a normal array that sits in GPU memory (VRAM)
var buffer = gl.createBuffer();

// attach our new buffer on the gpu to 'ARRAY_BUFFER'
// Think of it as, whatever is attached to 'ARRAY_BUFFER' is the current buffer that get used with WebGl functions
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);

// Upload our array of verticies as 32 bit floats
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(data),gl.STATIC_DRAW);

// Tell WebGL we're not using the buffer anymore at the moment
gl.bindBuffer(gl.ARRAY_BUFFER,null);

return buffer;
}

function createTexture(image) {
var texture = gl.createTexture();

// attach our new texture on the gpu to 'TEXTURE_2D'
// Think of it as, whatever is attached is our current texture we're using for webgl functions
gl.bindTexture(gl.TEXTURE_2D,texture);

// Set texture parameters, i.e. how are we going to scale it up or down/ what should happen if we
// try to get a pixel from outside the texture
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST); // Use nearest neighbour when sizing up
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST); // Use nearest neighbour when sizing down
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.REPEAT); // Apply a modulo to x coordinates if there outside the texture
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.REPEAT); // Apply a modulo to y coordinates if there outside the texture

// Upload our image to our gpu texture
gl.texImage2D(
gl.TEXTURE_2D, // I want it to get uploaded to what's attached to TEXTURE_2D
0, // Mipmap level, it can stay at 0
gl.RGBA, // Data format the gpu texture will use, in this case 8 bit RGBA for each pixel
image.width,
image.height,
0, // Border, always should be zero
gl.RGBA, // The data format of the image we're uploading to the gpu
gl.UNSIGNED_BYTE, // Datatype of each actual colour channel, here it's going to be an unsigned 8 bit int that will go from 0-255
image.pixels // The image we finally want to upload!, any HTML image element will work just fine
);

// Now we'll unbind the texture since we are done with it now
gl.bindTexture(gl.TEXTURE_2D,null); // Passing null tells WebGL that we're not currently 'using' any texture

return texture;
}

// Convert from Javascript canvas coordinate system to WebGL's normalized device coordinates
/*
The position 0,0 moves to the center of the screen.
The top left corner becomes -1,1
The bottom right corner becomes 1,-1

Coordinates need to be converted before they can be passed to WebGL
*/
function convertXCoordinate(x) {
return (x / canvasWidth) * 2.0 - 1.0;
}

function convertYCoordinate(y) {
return ((canvasHeight - y) / canvasHeight) * 2.0 - 1.0;
}

function loop() {
// Update

// Update raindrop positions
// Just to simulate rain 'falling'
for (var i = 0; i < raindrops.length; ++i) {
var raindrop = raindrops[i];

raindrop.y += 2.5;

if (raindrop.y > canvasHeight) {
raindrop.x = Math.random() * canvasWidth;
raindrop.y = 0;
}
}

// Render

// Clear the canvas
gl.clear(gl.COLOR_BUFFER_BIT);

// Draw the background
gl.bindBuffer(gl.ARRAY_BUFFER,backgroundBuffer);

// We use this function to tell WebGL how to interpret the data in the current buffer
gl.vertexAttribPointer(
aPositionLocation, // attribute index, usually just the order they were declared in the vertex shader
2, // Number of values in attribute, vec2 has two floats
gl.FLOAT, // The kind of data to be expected in the buffer
false, // Telling WebGL we don't want the data to get normalized to 0.0 -> 1.0
Float32Array.BYTES_PER_ELEMENT * 4, // This is the size of a complete vertex in bytes (2 vec2's so four floats)
Float32Array.BYTES_PER_ELEMENT * 0 // This is the 'offset', or the number of floats that come before this attribute in each vertex. aPosition comes first so it's zero
);

gl.vertexAttribPointer(
aUVLocation,
2,
gl.FLOAT,
false,
Float32Array.BYTES_PER_ELEMENT * 4,
Float32Array.BYTES_PER_ELEMENT * 2 // aUV comes second, so it's offset is two floats
);

// Tell WebGL we want to turn these attributes on for rendering
gl.enableVertexAttribArray(aPositionLocation);
gl.enableVertexAttribArray(aUVLocation);

// Attach our background texture so the sampler2D can use it
gl.bindTexture(gl.TEXTURE_2D,backgroundTexture);

// Attach our program we want to render with
gl.useProgram(backgroundProgram);

// Tell WebGL to start rendering!
gl.drawArrays(
gl.TRIANGLES, // Takes groups of 3 verticies to draw one complete triangle
0, // Start at index 0 in our buffer
6 // Use six complete verticies (whole sets of attributes) to draw 2 triangles
);

// We no longer need the background buffer, program or texture
gl.bindBuffer(gl.ARRAY_BUFFER,null);
gl.disableVertexAttribArray(aPositionLocation);
gl.disableVertexAttribArray(aUVLocation);
gl.bindTexture(gl.TEXTURE_2D,null);
gl.useProgram(null);

// Draw raindrops
// Since we're going to pass coordinates through uniforms, this can be done without a buffer

// Bind texture for sampler2D
gl.bindTexture(gl.TEXTURE_2D,raindropTexture);

// After attaching a program, we can upload values to uniforms using the values we got before from getUniformLocation()
gl.useProgram(raindropProgram);

for (var i = 0; i < raindrops.length; ++i) {
var raindrop = raindrops[i];

// Upload position
gl.uniform2f(
uRaindropPosition,
convertXCoordinate(raindrop.x),
convertYCoordinate(raindrop.y)
);

// Upload size
gl.uniform1f(
uRaindropSize,
raindrop.size
);

gl.drawArrays(gl.POINTS,0,1);
}

//
requestAnimationFrame(loop);
}

// This gets called when the page finishes loading
onload = function() {
// Get the canvas
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;

// Don't forget the webgl context!
gl = canvas.getContext("webgl");

// Create our program, it's made up of two smaller programs.
// One processes verticies (one whole set of attributes) & one that decides the colour of each pixel
// These smaller programs need to be created, compiled then attached to the main program

// modern Javascript has a nice feature called string templates, if we use `` instead of "" we can
// write strings that can have multiple lines!
backgroundProgram = createProgram(
` // Vertex Shader
precision lowp float;

// These values are filled from our buffer
attribute vec2 aPosition;
attribute vec2 aUV;

// Anything passed to this variable gets interpolated across any
// pixels inside our triangle
varying vec2 vUV;

void main() {
vUV = aUV;
gl_Position = vec4(aPosition,0.0,1.0);
}

`,` // Fragment shader
precision lowp float;

// Freshly interpolated value from our vertex shader
varying vec2 vUV;

// A uniform is a variable shared between webgl & javascript
// A sampler2D is a special datatype we use with texture2D
// to get a single pixel from the texture that's currently
// attached to TEXTURE_2D
uniform sampler2D uTexture;

void main() {
gl_FragColor = texture2D(uTexture,vUV);
}
`
);

raindropProgram = createProgram(
` // Vertex shader
precision lowp float;

attribute vec2 aPosition;

uniform vec2 uRaindropPosition;
uniform float uRaindropSize;

void main() {
gl_PointSize = uRaindropSize;
gl_Position = vec4(uRaindropPosition + aPosition,0.0,1.0);
}
`,` // Fragment shader
precision lowp float;

uniform sampler2D uTexture;

void main() {
gl_FragColor = texture2D(uTexture,gl_PointCoord);

// Discard the pixel if it has no alpha
if (gl_FragColor.a == 0.0) {
discard;
}
}
`
);

// Get the 'location' of uniform variables in our raindrop program
// These will be used later to upload new uniform values to the gpu
uRaindropPosition = gl.getUniformLocation(raindropProgram,"uRaindropPosition");
uRaindropSize = gl.getUniformLocation(raindropProgram,"uRaindropSize");

/*
Create and upload an array of data to the GPU,
each line contains all the attribute that make up one
vertex, here it's an x y coorinate for the position on the screen
followed by another x y coordinate for the position of the texture that
should be displayed at that corner (coordinates for textures are normally called UVs U = x, V = y)

Below is a list of verticies that make up two triangles that forms a rectangle that covers the whole screen,
triangles in WebGL should go in counter clockwise order
*/
backgroundBuffer = createBuffer([
// X Y U V
-1.0, 1.0, 0.0,0.0, // Top left
-1.0,-1.0, 0.0,1.0, // Bottom left
1.0, 1.0, 1.0,0.0, // Top right

1.0, 1.0, 1.0,0.0, // Top right
-1.0,-1.0, 0.0,1.0, // Top left
1.0,-1.0, 1.0,1.0 // Bottom right
]);

// Create & upload textures
backgroundTexture = createTexture(images.background);
raindropTexture = createTexture(images.raindrop);

// Set clearcolour, when we want an empty canvas
// R G B A
gl.clearColor(0.5,0.5,0.5,1.0);

// Create some randomly placed raindrops to simulate
for (var i = 0; i < 10; ++i) {
raindrops.push(
new Raindrop(
Math.random() * canvasWidth,
Math.random() * canvasHeight,
25.0
)
);
}

loop();
}

// Called when the page is reloading or getting closed
onunload = function() {
gl.deleteProgram(backgroundProgram);
gl.deleteProgram(raindropProgram);
gl.deleteBuffer(backgroundBuffer);
gl.deleteTexture(backgroundTexture);
gl.deleteTexture(raindropTexture);
}

}();

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

关于javascript - WebGL:如何将移动纹理叠加在另一个纹理之上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53355677/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com