WebGL比例画布

时间:2017-05-17 11:53:06

标签: javascript canvas webgl

我有一个带webgl的画布。我初始化webgl,创建一个片段和一个顶点着色器,两个三角形覆盖整个和一个纹理。

const vertexShaderSource = `
    attribute vec2 a_position;
    attribute vec2 a_texCoord;
    uniform vec2 u_resolution;
    varying vec2 v_texCoord;
    void main() {
       // convert the rectangle from pixels to 0.0 to 1.0
       vec2 zeroToOne = a_position / u_resolution;
       // convert from 0->1 to 0->2
       vec2 zeroToTwo = zeroToOne * 2.0;
       // convert from 0->2 to -1->+1 (clipspace)
       vec2 clipSpace = zeroToTwo - 1.0;
       gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
       // pass the texCoord to the fragment shader
       // The GPU will interpolate this value between points.
       v_texCoord = a_texCoord;
    }
`;

const fragmentShaderSource = `
    precision mediump float;
    // our texture
    uniform sampler2D u_image;
    // the texCoords passed in from the vertex shader.
    varying vec2 v_texCoord;
    void main() {
       gl_FragColor = texture2D(u_image, v_texCoord);
   }
`;

我从ImageData对象创建纹理,其元素是随机选择的(每个像素都是不同的颜色)。当我应用纹理时,它似乎覆盖整个区域,左上角的像素颜色拉伸覆盖整个画布。

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, IMAGEDATA);

这是我到目前为止的代码:

const width = 128;
const height = 128;
var createShader = function (gl, shaderSource, shaderType) {
    const shader = gl.createShader(shaderType);
    gl.shaderSource(shader, shaderSource);
    gl.compileShader(shader);
    const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    if (!compiled) {
        console.log(`Error compiling shader: ${gl.getShaderInfoLog(shader)}`);
        return;
    }

    return shader;
};

var createProgram = function(gl, shaders, opt_attribs, opt_locations) {
    const program = gl.createProgram();
    for (var ii = 0; ii < shaders.length; ++ii) {
        gl.attachShader(program, shaders[ii]);
    }
    if (opt_attribs) {
        for (var ii = 0; ii < opt_attribs.length; ++ii) {
            gl.bindAttribLocation(program, opt_locations ? opt_locations[ii] : ii, opt_attribs[ii]);
        }
    }
    gl.linkProgram(program);

    // Check the link status
    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
    if (!linked) {
        console.log(`Error linking shader parameter: ${gl.getProgramInfoLog(program)}`);
        gl.deleteProgram(program);
        return;
    }

    return program;
}

// create canvas
const canvas = document.createElement('canvas');
canvas.width  = width;
canvas.height = height;

// imagedata to update the texture
const imageData = {
    imageData: new ImageData(width, height),
    dataBuf:   null,
    dataBuf8:  null,
    data:      null
};
imageData.dataBuf = new ArrayBuffer(imageData.imageData.data.length);
imageData.dataBuf8 = new Uint8ClampedArray(imageData.dataBuf);
imageData.data = new Uint32Array(imageData.dataBuf);

const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');

document.getElementById('container').appendChild(canvas);

// shaders
const vertexShaderSource = `
    attribute vec2 a_position;
    attribute vec2 a_texCoord;
    uniform vec2 u_resolution;
    varying vec2 v_texCoord;
    void main() {
       // convert the rectangle from pixels to 0.0 to 1.0
       vec2 zeroToOne = a_position / u_resolution;
       // convert from 0->1 to 0->2
       vec2 zeroToTwo = zeroToOne * 2.0;
       // convert from 0->2 to -1->+1 (clipspace)
       vec2 clipSpace = zeroToTwo - 1.0;
       gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
       // pass the texCoord to the fragment shader
       // The GPU will interpolate this value between points.
       v_texCoord = a_texCoord;
    }
`;

const fragmentShaderSource = `
    precision mediump float;
    // our texture
    uniform sampler2D u_image;
    // the texCoords passed in from the vertex shader.
    varying vec2 v_texCoord;
    void main() {
       gl_FragColor = texture2D(u_image, v_texCoord);
   }
`;
const vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = createProgram(gl, [vertexShader, fragmentShader]);
gl.useProgram(program);

// triangle and triangle buffers
var positionLocation = gl.getAttribLocation(program, "a_position");
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    0,  0,
    canvas.width, 0,
    0, canvas.height,
    0, canvas.height,
    canvas.width, canvas.height,
    canvas.width, 0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

    var texCoordLocation = gl.getUniformLocation(program, "a_texCoord");
    var texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        0,  0,
        canvas.width, 0,
        0, canvas.height,
        0, canvas.height,
        canvas.width, canvas.height,
        canvas.width, 0]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(texCoordLocation);
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

// texture
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
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.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

for (let i = 0; i < imageData.data.length; i++) {
    const r = Math.round(Math.random() * 100);
    const g = Math.round(Math.random() * 100);
    const b = Math.round(Math.random() * 100);
    imageData.data[i] = (255 << 24) |    // alpha
                        (b   << 16) |    // blue
                        (g   <<  8) |    // green
                         r;              //

}
imageData.imageData.data.set(imageData.dataBuf8);

// bind texture and draw
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData.imageData);
gl.drawArrays(gl.TRIANGLES, 0, 6);
<div id="container"></div>

如何正确放置纹理?

1 个答案:

答案 0 :(得分:1)

只有两个错误,a_texCoords的错误位置类型和错误的纹理坐标应该在0到1的范围内。

请参阅下面的代码进行更正。

&#13;
&#13;
const width = 128;
const height = 128;
var createShader = function(gl, shaderSource, shaderType) {
  const shader = gl.createShader(shaderType);
  gl.shaderSource(shader, shaderSource);
  gl.compileShader(shader);
  const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  if (!compiled) {
    console.log(`Error compiling shader: ${gl.getShaderInfoLog(shader)}`);
    return;
  }

  return shader;
};

var createProgram = function(gl, shaders, opt_attribs, opt_locations) {
  const program = gl.createProgram();
  for (var ii = 0; ii < shaders.length; ++ii) {
    gl.attachShader(program, shaders[ii]);
  }
  if (opt_attribs) {
    for (var ii = 0; ii < opt_attribs.length; ++ii) {
      gl.bindAttribLocation(program, opt_locations ? opt_locations[ii] : ii, opt_attribs[ii]);
    }
  }
  gl.linkProgram(program);

  // Check the link status
  var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (!linked) {
    console.log(`Error linking shader parameter: ${gl.getProgramInfoLog(program)}`);
    gl.deleteProgram(program);
    return;
  }

  return program;
}

// create canvas
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;

// imagedata to update the texture
const imageData = {
  imageData: new ImageData(width, height),
  dataBuf: null,
  dataBuf8: null,
  data: null
};
imageData.dataBuf = new ArrayBuffer(imageData.imageData.data.length);
imageData.dataBuf8 = new Uint8ClampedArray(imageData.dataBuf);
imageData.data = new Uint32Array(imageData.dataBuf);

const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');

document.getElementById('container').appendChild(canvas);

// shaders
const vertexShaderSource = `
    attribute vec2 a_position;
    attribute vec2 a_texCoord;
    uniform vec2 u_resolution;
    varying vec2 v_texCoord;
    void main() {
       // convert the rectangle from pixels to 0.0 to 1.0
       vec2 zeroToOne = a_position / u_resolution;
       // convert from 0->1 to 0->2
       vec2 zeroToTwo = zeroToOne * 2.0;
       // convert from 0->2 to -1->+1 (clipspace)
       vec2 clipSpace = zeroToTwo - 1.0;
       gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
       // pass the texCoord to the fragment shader
       // The GPU will interpolate this value between points.
       v_texCoord = a_texCoord;
    }
`;

const fragmentShaderSource = `
    precision mediump float;
    // our texture
    uniform sampler2D u_image;
    // the texCoords passed in from the vertex shader.
    varying vec2 v_texCoord;
    void main() {
       gl_FragColor = texture2D(u_image, v_texCoord);
   }
`;
const vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = createProgram(gl, [vertexShader, fragmentShader]);
gl.useProgram(program);

// triangle and triangle buffers
var positionLocation = gl.getAttribLocation(program, "a_position");
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  0, 0,
  canvas.width, 0,
  0, canvas.height,
  0, canvas.height,
  canvas.width, canvas.height,
  canvas.width, 0
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

//  You had the wrong location type getUniformLocation a_exCoord is an attribute
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
// You had the wrong texture coords.Coords are in the range 0 to 1
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  0, 0,
  1, 0,
  0, 1,
  0, 1,
  1, 1,
  1, 0
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

// texture
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
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.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

// changed this as I thought you where indexing a 8bit array then saw you
// correctly index a 32 bit array. Id did not change the code back but yours was
// correct as well.
for (let i = 0; i < imageData.dataBuf8.length; i += 4) {

  imageData.dataBuf8[i] = Math.random() * 255;; // red
  imageData.dataBuf8[i + 1] = Math.random() * 255; // green
  imageData.dataBuf8[i + 2] = Math.random() * 255; // blue
  imageData.dataBuf8[i + 3] = Math.random() * 255; // alpha          //

}
imageData.imageData.data.set(imageData.dataBuf8);

// bind texture and draw
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData.imageData);
gl.drawArrays(gl.TRIANGLES, 0, 6);
&#13;
canvas {
  border: 2px solid black;
}
&#13;
<div id="container"></div>
&#13;
&#13;
&#13;