简体   繁体   English

如何在WebGL上对平面进行纹理映射?

[英]How do you texture map a plane on WebGL?

I have created a basic scene consisting of a floor(plane), table, and a cube. 我创建了一个由地板(平面),桌子和立方体组成的基本场景。 I now want to move onto texturing the floor with a wooden texture image Click to see the wooden texture. 我现在想继续使用木质纹理图像对地板进行纹理处理。单击以查看木质纹理。 I know very little about texturing and fairly new to WebGL. 我对纹理了解不多,对WebGL来说还很陌生。

I have some idea of having to load the image from my directory, but not sure on how to apply it to the floor. 我有一些必须从目录中加载图像的想法,但是不确定如何将其应用于地板。 In addition to this, I am unsure on the texture vertex coordinates needed for the plane(floor). 除此之外,我不确定平面(地板)所需的纹理顶点坐标。

I am also aware I will need to add new attributes to allow texturing. 我也知道我将需要添加新属性以允许纹理化。 Would you need to change the overall layout of the object for the texture to take place? 您是否需要更改对象的整体布局以使纹理发生?

Would appreciate any advice on where to start and how I can go about this task. 希望就从何处开始以及如何进行此任务提供任何建议。

 <!DOCTYPE HTML> <html lang="en"> <head> <title>Drawing In 3D </title> <meta charset="utf-8"> <script src="glMatrix.js"></script> <script src="webgl-debug.js"></script> <script id="shader-vs" type="x-shader/x-vertex"> attribute vec3 aVertexPosition; attribute vec4 aVertexColor; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; varying vec4 vColor; void main() { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); vColor = aVertexColor; } </script> <script id="shader-fs" type="x-shader/x-fragment"> precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; } </script> <script type="text/javascript"> var gl; var canvas; var shaderProgram; var floorVertexPositionBuffer; var floorVertexIndexBuffer; var cubeVertexPositionBuffer; var cubeVertexIndexBuffer; var modelViewMatrix; var projectionMatrix; var modelViewMatrixStack; function createGLContext(canvas) { var names = ["webgl", "experimental-webgl"]; var context = null; for (var i = 0; i < names.length; i++) { try { context = canvas.getContext(names[i]); } catch (e) { } if (context) { break; } } if (context) { context.viewportWidth = canvas.width; context.viewportHeight = canvas.height; } else { alert("Failed to create WebGL context!"); } return context; } function loadShaderFromDOM(id) { var shaderScript = document.getElementById(id); if (!shaderScript) { return null; } var shaderSource = ""; var currentChild = shaderScript.firstChild; while (currentChild) { if (currentChild.nodeType == 3) { // 3 corresponds to TEXT_NODE shaderSource += currentChild.textContent; } currentChild = currentChild.nextSibling; } var shader; if (shaderScript.type == "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER); } else if (shaderScript.type == "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER); } else { return null; } gl.shaderSource(shader, shaderSource); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert(gl.getShaderInfoLog(shader)); return null; } return shader; } function setupShaders() { var vertexShader = loadShaderFromDOM("shader-vs"); var fragmentShader = loadShaderFromDOM("shader-fs"); shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert("Failed to setup shaders"); } gl.useProgram(shaderProgram); shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor"); shaderProgram.uniformMVMatrix = gl.getUniformLocation(shaderProgram, "uMVMatrix"); shaderProgram.uniformProjMatrix = gl.getUniformLocation(shaderProgram, "uPMatrix"); // Initialise the matrices modelViewMatrix = mat4.create(); projectionMatrix = mat4.create(); modelViewMatrixStack = []; gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); } function pushModelViewMatrix() { var copyToPush = mat4.create(modelViewMatrix); modelViewMatrixStack.push(copyToPush); } function popModelViewMatrix() { if (modelViewMatrixStack.length == 0) { throw "Error popModelViewMatrix() - Stack was empty "; } modelViewMatrix = modelViewMatrixStack.pop(); } function setupFloorBuffers() { floorVertexPositionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexPositionBuffer); var floorVertexPosition = [ // Plane in y=0 5.0, 0.0, 5.0, //v0 5.0, 0.0, -5.0, //v1 -5.0, 0.0, -5.0, //v2 -5.0, 0.0, 5.0]; //v3 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(floorVertexPosition), gl.STATIC_DRAW); floorVertexPositionBuffer.itemSize = 3; floorVertexPositionBuffer.numberOfItems = 4; floorVertexIndexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, floorVertexIndexBuffer); var floorVertexIndices = [0, 1, 2, 3]; gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(floorVertexIndices), gl.STATIC_DRAW); floorVertexIndexBuffer.itemSize = 1; floorVertexIndexBuffer.numberOfItems = 4; } function setupCubeBuffers() { cubeVertexPositionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer); var cubeVertexPosition = [ 1.0, 1.0, 1.0, //v0 -1.0, 1.0, 1.0, //v1 -1.0, -1.0, 1.0, //v2 1.0, -1.0, 1.0, //v3 1.0, 1.0, -1.0, //v4 -1.0, 1.0, -1.0, //v5 -1.0, -1.0, -1.0, //v6 1.0, -1.0, -1.0, //v7 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeVertexPosition), gl.STATIC_DRAW); cubeVertexPositionBuffer.itemSize = 3; cubeVertexPositionBuffer.numberOfItems = 8; cubeVertexIndexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); var cubeVertexIndices = [ 0, 1, 2, 0, 2, 3, // Front face 4, 6, 5, 4, 7, 6, // Back face 1, 5, 6, 1, 6, 2, //left 0, 3, 7, 0, 7, 4, //right 0, 5, 1, 0, 4, 5, //top 3, 2, 6, 3, 6, 7 //bottom ]; gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); cubeVertexIndexBuffer.itemSize = 1; cubeVertexIndexBuffer.numberOfItems = 36; } function setupBuffers() { setupFloorBuffers(); setupCubeBuffers(); } function uploadModelViewMatrixToShader() { gl.uniformMatrix4fv(shaderProgram.uniformMVMatrix, false, modelViewMatrix); } function uploadProjectionMatrixToShader() { gl.uniformMatrix4fv(shaderProgram.uniformProjMatrix, false, projectionMatrix); } function drawFloor(r, g, b, a) { // Disable vertex attrib array and use constant color for the floor. gl.disableVertexAttribArray(shaderProgram.vertexColorAttribute); // Set colour gl.vertexAttrib4f(shaderProgram.vertexColorAttribute, r, g, b, a); // Draw the floor gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, floorVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, floorVertexIndexBuffer); gl.drawElements(gl.TRIANGLE_FAN, floorVertexIndexBuffer.numberOfItems, gl.UNSIGNED_SHORT, 0); } function drawCube(r, g, b, a) { // Disable vertex attrib array and use constant color for the cube. gl.disableVertexAttribArray(shaderProgram.vertexColorAttribute); // Set color gl.vertexAttrib4f(shaderProgram.vertexColorAttribute, r, g, b, a); gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numberOfItems, gl.UNSIGNED_SHORT, 0); } function drawTable() { // Draw table top pushModelViewMatrix(); mat4.translate(modelViewMatrix, [0.0, 1.0, 0.0], modelViewMatrix); mat4.scale(modelViewMatrix, [2.0, 0.1, 2.0], modelViewMatrix); uploadModelViewMatrixToShader(); // Draw the scaled cube drawCube(0.72, 0.53, 0.04, 1.0); // brown color popModelViewMatrix(); // Draw table legs for (var i = -1; i <= 1; i += 2) { for (var j = -1; j <= 1; j += 2) { pushModelViewMatrix(); mat4.translate(modelViewMatrix, [i * 1.9, -0.1, j * 1.9], modelViewMatrix); mat4.scale(modelViewMatrix, [0.1, 1.0, 0.1], modelViewMatrix); uploadModelViewMatrixToShader(); drawCube(0.72, 0.53, 0.04, 1.0); // argument sets brown color popModelViewMatrix(); } } } function draw() { gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); mat4.perspective(60, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, projectionMatrix); mat4.identity(modelViewMatrix); mat4.lookAt([8, 5, -10], [0, 0, 0], [0, 1, 0], modelViewMatrix); uploadModelViewMatrixToShader(); uploadProjectionMatrixToShader(); // Draw floor in red color drawFloor(1.0, 0.0, 0.0, 1.0); // Draw table pushModelViewMatrix(); mat4.translate(modelViewMatrix, [0.0, 1.1, 0.0], modelViewMatrix); uploadModelViewMatrixToShader(); drawTable(); //Call drawTable() function popModelViewMatrix(); // Draw box on top of the table pushModelViewMatrix(); mat4.translate(modelViewMatrix, [0.0, 2.7, 0.0], modelViewMatrix); mat4.scale(modelViewMatrix, [0.5, 0.5, 0.5], modelViewMatrix); uploadModelViewMatrixToShader(); drawCube(0.0, 0.0, 1.0, 1.0); popModelViewMatrix() } function startup() { canvas = document.getElementById("myGLCanvas"); gl = WebGLDebugUtils.makeDebugContext(createGLContext(canvas)); setupShaders(); setupBuffers(); gl.clearColor(1.0, 1.0, 1.0, 1.0); gl.enable(gl.DEPTH_TEST); draw(); } </script> </head> <body onload="startup();"> <canvas id="myGLCanvas" width="500" height="500"></canvas> </body> </html> 

You can use loadTexture() method to load textures in WebGL project. 您可以使用loadTexture()方法在WebGL项目中加载纹理。

The loadTexture() routine starts by creating a WebGL texture object texture by calling the WebGL createTexture() function. loadTexture()例程首先通过调用WebGL createTexture()函数来创建WebGL纹理对象纹理。 It then uploads a single blue pixel using texImage2D(). 然后,它使用texImage2D()上传一个蓝色像素。 This makes the texture immediately usable as a solid blue color even though it may take a few moments for our image to download. 即使下载图像可能需要一些时间,该纹理也可以立即用作纯蓝色。

To load the texture from the image file, it then creates an Image object and assigned the src to the URL for our image we wish to use as our texture. 要从图像文件加载纹理,它会创建一个Image对象,并将src分配给我们希望用作纹理的图像的URL。 The function we assign to image.onload will be called once the image has finished downloading. 图片下载完成后,将调用我们分配给image.onload的函数。 At that point, we again call texImage2D() this time using the image as the source of the texture. 到那时,我们再次使用图像作为纹理源来调用texImage2D()。 After that we setup filtering and wrapping for the texture based on whether or not the image we download was a power of 2 in both dimensions or not. 此后,我们根据下载的图像在两个维度上是否为2的幂来设置纹理的过滤和环绕。

function loadTexture(gl, url) {
  const texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);

  // Because images have to be download over the internet
  // they might take a moment until they are ready.
  // Until then put a single pixel in the texture so we can
  // use it immediately. When the image has finished downloading
  // we'll update the texture with the contents of the image.
  const level = 0;
  const internalFormat = gl.RGBA;
  const width = 1;
  const height = 1;
  const border = 0;
  const srcFormat = gl.RGBA;
  const srcType = gl.UNSIGNED_BYTE;
  const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
                width, height, border, srcFormat, srcType,
                pixel);

  const image = new Image();
  image.onload = function() {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
                  srcFormat, srcType, image);

    // WebGL1 has different requirements for power of 2 images
    // vs non power of 2 images so check if the image is a
    // power of 2 in both dimensions.
    if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
       // Yes, it's a power of 2. Generate mips.
       gl.generateMipmap(gl.TEXTURE_2D);
    } else {
       // No, it's not a power of 2. Turn of mips and set
       // wrapping to clamp to edge
       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);
    }
  };
  image.src = url;

  return texture;
}

Or have a look at this cube with texture WebGL tutorial on git hub. 或通过git hub上的带有纹理WebGL教程的多维数据集查看。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM