永远都不知道如何在twgl中进行纹理工作

cannot ever figure out how to do texture jobs in twgl

本文关键字:纹理 工作 twgl 不知道 永远      更新时间:2023-09-26

这是我为vs/fs编写的代码,也是我想放在画布上的一个简单立方体。为了长度起见,省略了部分。

<script id="cube-vs" type="notjs">
    precision highhp float;
    attribute vec3 vpos;
    attribute vec3 vnormal;
    attribute vec2 vtex;
    varying vec3 fColor;
    varying vec3 fNormal;
    varying vec2 fTexCoord;
    uniform mat4 view;
    uniform mat4 proj;
    uniform mat4 model;
    uniform vec3 lightdir;
    uniform vec3 cubecolor;
    void main(void) {
        gl_Position = proj * view * model * vec4(vpos, 1.0);
        vec4 normal = normalize(model * vec4(vnormal,0.0));
        float diffuse = .2 + abs(dot(normal, vec4(lightdir,0.0)));
        fColor = (cubecolor * diffuse);
        fTexCoord = vtex;
    }
</script>
<script id="cube-fs" type="notjs">
    precision highhp float;
    varying vec3 fColor;
    varying vec3 fNormal;
    varying vec2 fTexCoord;
    uniform sampler2D texSampler;
    void main(void) {
        vec4 texColor = texture2d(texSampler, fTexCoord);
        gl_FragColor = vec4(fColor*texColor.xyz,1.0);
    }
</script>

立方体

...
    Cube.prototype.init = function(drawingState) {
        var gl=drawingState.gl;
        // create the shaders once - for all cubes
        if (!shaderProgram) {
            shaderProgram = twgl.createProgramInfo(gl, ["tree-vs", "tree-fs"]);
        }
        if (!buffers) {
            var arrays = {
                vpos : { numComponents: 3, data: [...] },
                vnormal : {numComponents:3, data: [...]},
                vtex : {numComponents:2, data: [
                    1,0,0,0,0,1,1,1,
                    1,0,0,0,0,1,1,1,
                    1,0,0,0,0,1,1,1,
                    1,0,0,0,0,1,1,1,
                    1,0,0,0,0,1,1,1,
                    1,0,0,0,0,1,1,1,
                ]},
                indices : {[...]}
                };
            buffers = twgl.createBufferInfoFromArrays(gl,arrays);
        }
        if (!texture) {
            texture = twgl.createTexture(gl, {src:textures/tree.jpg});
        }    
    };
    Cube.prototype.draw = function(drawingState) {
        var modelM = twgl.m4.scaling([this.size*1.4,this.size*1.4,this.size*1.4]);
        twgl.m4.setTranslation(modelM,this.position,modelM);
        var gl = drawingState.gl;
        gl.useProgram(shaderProgram.program);
        twgl.setBuffersAndAttributes(gl,shaderProgram,buffers);
        twgl.setUniforms(shaderProgram,{
            view:drawingState.view, proj:drawingState.proj, lightdir:drawingState.sunDirection,
            cubecolor:this.color, model: modelM, texSampler: texture);
        twgl.drawBufferInfo(gl, gl.TRIANGLES, buffers);
    };

立方体没有纹理,很好用但当我尝试添加纹理时,它永远不会起作用我几乎什么都试过了,但我仍然不知道如何把纹理涂上去。那么,我该怎么做呢?

任何提示都将不胜感激。

*********编辑我已经成功上传了纹理坐标和制服但是图像没有显示,并且立方体被染成浅蓝色。任何建议都将不胜感激。

如果您能提供一个工作示例而不仅仅是部分代码,那就太好了。上面的代码中有几个拼写错误。例如,在setUniforms部分中,没有关闭}。在createTexture部分中,url上没有引号。您将highp拼写为highhp,将texture2D拼写为texture2d。我认为,如果你说它在没有纹理的情况下运行,那只是转录错误,因为如果没有,你应该在JavaScript控制台中看到非常明显的错误。

目前还不清楚哪里出了问题,但在调试WebGL时,我要做的第一件事就是检查JavaScript控制台。是否有关于不可渲染纹理的消息?

没有?然后我要做的下一件事是将碎片着色器更改为纯色

<script id="cube-fs" type="notjs">
    precision highhp float;
    varying vec3 fColor;
    varying vec3 fNormal;
    varying vec2 fTexCoord;
    uniform sampler2D texSampler;
    void main(void) {
        vec4 texColor = texture2d(texSampler, fTexCoord);
        gl_FragColor = vec4(fColor*texColor.xyz,1.0);
gl_FragColor = vec4(1,0,0,1);  // -------ADDED-------------------------
    }
</script>

如果你看到你的立方体,那么是的,这个问题与纹理有关。如果不是,问题就在其他地方。

假设你看到一个红色立方体。好的,接下来就是检查纹理坐标。我会把碎片着色器改成这个

<script id="cube-fs" type="notjs">
    precision highhp float;
    varying vec3 fColor;
    varying vec3 fNormal;
    varying vec2 fTexCoord;
    uniform sampler2D texSampler;
    void main(void) {
        vec4 texColor = texture2d(texSampler, fTexCoord);
        gl_FragColor = vec4(fColor*texColor.xyz,1.0);
gl_FragColor = vec4(fTexCoord,0,1);  // -------CHANGED-------------------------
    }
</script>

您现在应该看到带有红色->绿色阴影的立方体。如果没有,你有坏的纹理坐标。

如果这看起来是正确的,我接下来可能会尝试将着色器恢复到原来的状态,然后检查变量texture是否真的设置好了。

我有很多方法可以检查这个。

  1. 使用WebGL检查器

  2. 使用标准的JavaScript调试器。在setUniforms部件上设置断点。检查变量

  3. 做一些类似的事情

    var uniforms = {
        view:drawingState.view, 
        proj:drawingState.proj, 
        lightdir:drawingState.sunDirection,
        cubecolor:this.color, 
        model: modelM, 
        texSampler: texture,
    };
    window.u = uniforms;
    twgl.setUniforms(shaderProgram, uniforms);
    

    现在打开JavaScript控制台并键入u.texSampler。它应该打印类似的东西

    WebGLTexture {}
    

    如果不是,那么texture可能不是你认为的变量

另一个问题是,你是否像在中一样不断地使用requestAnimationFrame进行渲染

function render() {
  // draw stuff like maybe call someCube.draw(drawingState)
  ...
  requestAnimationFrame(render);
}
requestAnimationFrame(render);

我问这个问题是因为纹理是异步加载的,所以如果你只渲染一次,那么你就看不到任何纹理,因为它们还没有加载。

你有几个选择。

  1. 不断渲染(如上面的例子)

    twgl将默认为1x1像素纹理,因此渲染应该可以工作。然后图像最终加载,它将更新纹理

  2. 等待纹理加载。

    如果在纹理准备好之前不想渲染,则可以向twgl.createTexture添加回调,当纹理准备好时,它会回叫您。

另一件事是从一个工作样本开始

var m4 = twgl.m4;                                              // <!------------ ADDED
var v3 = twgl.v3;                                              // <!------------ ADDED
// not sure why these are globals?!???!
var shaderProgram;                                             // <!------------ ADDED
var texture;                                                   // <!------------ ADDED
var buffers;                                                   // <!------------ ADDED
var canvas = document.querySelector("canvas");                 // <!------------ ADDED
var drawingState = {                                           // <!------------ ADDED
  gl: canvas.getContext("webgl"),                              // <!------------ ADDED
  view: m4.inverse(m4.lookAt([3,3,6], [0, 0, 0], [0, 1, 0])),  // <!------------ ADDED
  proj: m4.perspective(                                        // <!------------ ADDED
    Math.PI * 0.3,                                             // <!------------ ADDED
    canvas.clientWidth / canvas.clientHeight,                  // <!------------ ADDED
    0.1, 10),                                                  // <!------------ ADDED
  sunDirection: v3.normalize([2,3,-2]),                        // <!------------ ADDED
};                                                             // <!------------ ADDED
function Cube() {            // <!-------------------------------------- ADDED
  this.size = 1;             // <!-------------------------------------- ADDED
  this.position = [0, 0, 0]; // <!-------------------------------------- ADDED 
  this.color = [1, 1, 1];    // <!-------------------------------------- ADDED
}                            // <!-------------------------------------- ADDED
Cube.prototype.init = function(drawingState) {
  var gl=drawingState.gl;
  // create the shaders once - for all cubes
  if (!shaderProgram) {
    shaderProgram = twgl.createProgramInfo(gl, ["cube-vs", "cube-fs"]);  // <!---- CHANGED
  }
  if (!buffers) {
    var arrays = {
      vpos: { numComponents: 3, data: [1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1], },
      vnormal:  { numComponents: 3, data:  [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1], },
      vtex: { numComponents: 2, data: [1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1], },
      indices:  [0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23],
    };
    buffers = twgl.createBufferInfoFromArrays(gl,arrays);
  }
  if (!texture) {
    texture = twgl.createTexture(gl, {
      src: "https://farm6.staticflickr.com/5795/21506301808_efb27ed699_q_d.jpg",
      crossOrigin: "", // <!--------- not needed if on same server which "texture/tree.jpg" is
    });
  }    
};
Cube.prototype.draw = function(drawingState) {
  var modelM = twgl.m4.scaling([this.size*1.4,this.size*1.4,this.size*1.4]);
  twgl.m4.setTranslation(modelM,this.position,modelM);
  var gl = drawingState.gl;
  gl.useProgram(shaderProgram.program);
  twgl.setBuffersAndAttributes(gl,shaderProgram,buffers);
  twgl.setUniforms(shaderProgram,{
    view:drawingState.view, proj:drawingState.proj, lightdir:drawingState.sunDirection,
    cubecolor:this.color, model: modelM, texSampler: texture});
  twgl.drawBufferInfo(gl, gl.TRIANGLES, buffers);
};
var cube = new Cube();               // <!------------ ADDED
cube.init(drawingState);             // <!------------ ADDED
function render() {                  // <!------------ ADDED
  var gl = drawingState.gl           // <!------------ ADDED
  gl.enable(gl.DEPTH_TEST);          // <!------------ ADDED
  cube.draw(drawingState);           // <!------------ ADDED
  requestAnimationFrame(render);     // <!------------ ADDED
}                                    // <!------------ ADDED
requestAnimationFrame(render);       // <!------------ ADDED
canvas { border: 1px solid black; }
<script id="cube-vs" type="notjs">
    //precision highp float;    <!---------------- CHANGED
    attribute vec3 vpos;
    attribute vec3 vnormal;
    attribute vec2 vtex;
    varying vec3 fColor;
    varying vec3 fNormal;
    varying vec2 fTexCoord;
    uniform mat4 view;
    uniform mat4 proj;
    uniform mat4 model;
    uniform vec3 lightdir;
    uniform vec3 cubecolor;
    void main(void) {
        gl_Position = proj * view * model * vec4(vpos, 1.0);
        vec4 normal = normalize(model * vec4(vnormal,0.0));
        float diffuse = .2 + abs(dot(normal, vec4(lightdir,0.0)));
        fColor = (cubecolor * diffuse);
        fTexCoord = vtex;
    }
</script>
<script id="cube-fs" type="notjs">
    precision highp float;  // <!--------- CHANGED (should probably use mediump though)
    varying vec3 fColor;
    varying vec3 fNormal;
    varying vec2 fTexCoord;
    uniform sampler2D texSampler;
    void main(void) {
        vec4 texColor = texture2D(texSampler, fTexCoord);  // < !-------- CHANGED
        gl_FragColor = vec4(fColor*texColor.xyz,1.0);
    }
</script>
<canvas></canvas>
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>

还有一个问题,你在运行网络服务器吗?WebGL需要一个web服务器来读取纹理。请注意,运行web服务器是很麻烦的。一个非常好的在这里。只需下载操作系统的版本,然后

path/to/devd-download/devd path/to/project

然后转到http://localhost:8000/nameOfYourHtmlFile.html

我认为这不是问题所在,因为如果是这样的话,你会在JavaScript控制台中看到一个关于无法加载纹理的明显错误,但你没有在JavaScript控制台中提到错误