javascript - WebGL - 导入 MD2 模型,纹理问题

标签 javascript textures webgl md2

我正在使用 md2 模型制作 webgl 演示。我知道这是一种旧格式,但我只需要使用 md2。

我阅读了 md2 的文档格式。

我看了this网站作品: 并在我的程序中使用了它的部分来源(我在评论中保存了作者的名字)

我进行了顶点加载,模型加载得很好!

但是当我尝试映射纹理时,发生了一些奇怪的事情:

Robot

首先,我认为这是片段着色器的问题,但我使用assimp2json进行了导出,使用了其中的数据,并且按照应有的方式绘制了它。

问题是assimp2json改变了三 Angular 形和uvs顺序中的顶点顺序,所以我无法使用它调试程序。

也许有人可以帮助找到错误,指出我代码中的错误?

P。 S.由于没有动画,我只使用第一帧

最有趣的是,如果我传递未索引的数据(只是文件中的 uv),它看起来比索引纹理更正确:

enter image description here

问题是有些地方是错误的,比如这里:

enter image description here

完整的源代码和模型:

ShaderProgram.js

class ShaderProgram
{
   constructor(gl, VSSource, FSSource) // VS - Vertex Shader, FS - Fragment 
Shader
       {
    this.gl = gl;
    let vertexShader = this.getShader(VSSource, gl.VERTEX_SHADER);
    let fragmentShader = this.getShader(FSSource, gl.FRAGMENT_SHADER);

    this.shaderProgram = gl.createProgram();

    gl.attachShader(this.shaderProgram, vertexShader);
    gl.attachShader(this.shaderProgram, fragmentShader);

    gl.linkProgram(this.shaderProgram);

    if (!gl.getProgramParameter(this.shaderProgram, gl.LINK_STATUS)) {
        alert("Can't load shaders");
    }

    this.enableAttributes();
    this.getUniforms();

}

getShader(source, type)
{
    let gl = this.gl;

    let shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert("Error compilation: " + gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);
        return null;
    }

    return shader;
}

getUniforms()
{
    this.model = gl.getUniformLocation(this.shaderProgram, "model");
    this.view = gl.getUniformLocation(this.shaderProgram, "view");
    this.projection = gl.getUniformLocation(this.shaderProgram, "projection");

}

enableAttributes()
{
    let gl = this.gl;
    let shaderProgram  = this.shaderProgram;


}

use()
{
    this.gl.useProgram(this.shaderProgram);
}


}

纹理.js

function initTexture(filename) {
let texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));

let image = new Image();
image.onload = function() { handleTextureLoaded(image, texture); }
image.src = filename;

return texture;
}

function handleTextureLoaded(image, texture) {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}

MD2 导入:

// BinaryReader
// Refactored by Vjeux <vjeuxx@gmail.com>
// http://blog.vjeux.com/2010/javascript/javascript-binary-reader.html

// Original
//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/classes/binary-parser [rev. #1]

BinaryReader = function (data) {
this._buffer = data;
this._pos = 0;
};

BinaryReader.prototype = {

/* Public */

readInt8:   function (){ return this._decodeInt(8, true); },
readUInt8:  function (){ return this._decodeInt(8, false); },
readInt16:  function (){ return this._decodeInt(16, true); },
readUInt16: function (){ return this._decodeInt(16, false); },
readInt32:  function (){ return this._decodeInt(32, true); },
readUInt32: function (){ return this._decodeInt(32, false); },

readFloat:  function (){ return this._decodeFloat(23, 8); },
readDouble: function (){ return this._decodeFloat(52, 11); },

readChar:   function () { return this.readString(1); },
readString: function (length) {
    this._checkSize(length * 8);
    var result = this._buffer.substr(this._pos, length);
    this._pos += length;
    return result;
},

seek: function (pos) {
    this._pos = pos;
    this._checkSize(0);
},

getPosition: function () {
    return this._pos;
},

getSize: function () {
    return this._buffer.length;
},


/* Private */

_decodeFloat: function(precisionBits, exponentBits)
{

    return this._decodeFloat2(precisionBits, exponentBits);


    var length = precisionBits + exponentBits + 1;
    var size = length >> 3;
    this._checkSize(length);

    var bias = Math.pow(2, exponentBits - 1) - 1;
    var signal = this._readBits(precisionBits + exponentBits, 1, size);
    var exponent = this._readBits(precisionBits, exponentBits, size);
    var significand = 0;
    var divisor = 2;
    var curByte = length + (-precisionBits >> 3) - 1;

    do
    {
        var byteValue = this._readByte(++curByte, size);
        var startBit = precisionBits % 8 || 8;
        var mask = 1 << startBit;

        while (mask >>= 1)
        {
            if (byteValue & mask)
            {
                significand += 1 / divisor;
            }
            divisor *= 2;
        }
    } while (precisionBits -= startBit);

    this._pos += size;

    return exponent == (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity
        : (1 + signal * -2) * (exponent || significand ? !exponent ? Math.pow(2, -bias + 1) * significand
        : Math.pow(2, exponent - bias) * (1 + significand) : 0);
},

// I added this because _decodeFloat gave me some real inaccuarate results? -Terry Butler
_decodeFloat2: function(precisionBits, exponentBits)
{
    var length = precisionBits + exponentBits + 1;
    var value = this._decodeInt(length);

    var sign = (value >> 31) & 0x1;
    var allZero = 1;
    var mantissa = 0.0;
    var exponent = 0.0;

    // Mantissa
    for (var i = 22; i > -1; i--)
    {

        var test = 1.0 / Math.pow(2, 23-i);

        if ((value >> i & 0x1) == 1)
        {

            mantissa += test;

            allZero = 0;
        }

    }

    if (allZero == 0)
        mantissa += 1.0;

    // Exponent
    for (var i = 30; i > 22; i--)
    {

        var test = Math.pow(2, i - 23);

        if ((value >> i & 0x1) == 1)
        {
            exponent += test;
        }

    }

    exponent -= 127.0;

    //
    var total = Math.pow(2.0, exponent) * mantissa;

    //
    if (sign == 1)
    {
        total *= -1.0;
    }

    return total;

},

_decodeInt: function(bits, signed){
    var x = this._readBits(0, bits, bits / 8), max = Math.pow(2, bits);
    var result = signed && x >= max / 2 ? x - max : x;

    this._pos += bits / 8;
    return result;
},

//shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
_shl: function (a, b){
    for (++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1);
    return a;
},

_readByte: function (i, size) {
    return this._buffer.charCodeAt(this._pos + size - i - 1) & 0xff;
},

_readBits: function (start, length, size) {
    var offsetLeft = (start + length) % 8;
    var offsetRight = start % 8;
    var curByte = size - (start >> 3) - 1;
    var lastByte = size + (-(start + length) >> 3);
    var diff = curByte - lastByte;

    var sum = (this._readByte(curByte, size) >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1);

    if (diff && offsetLeft) {
        sum += (this._readByte(lastByte++, size) & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight;
    }

    while (diff) {
        sum += this._shl(this._readByte(lastByte++, size), (diff-- << 3) - offsetRight);
    }

    return sum;
},

_checkSize: function (neededBits) {
    if (!(this._pos + Math.ceil(neededBits / 8) < this._buffer.length)) {
        throw new Error("Index out of bound");
    }
}
};


/**
 * @author oosmoxiecode
 * based on http://www.terrybutler.co.uk/web-development/html5-canvas-md2-    renderer/
 * and
 * http://tfc.duke.free.fr/coding/md2-specs-en.html
 *
 * dependant on binaryReader.js
 *
 * Returns a object like: {string: json_string, info: {status: "Success",     faces: 10, vertices: 10, frames: 5 }}
 *
 **/

// Library is modified for this program by me

function MD2_converter (file) {

    var scope = this;

    // Create the Binary Reader
    var reader = new BinaryReader(file);

    // Setup
    var header = {};
    var frames = [];
    var st = [];
    var triag = [];

    var string = "";
    var info = {};
    var returnObject = {string: string, info: info};

// Ident and version
header.ident = reader.readString(4);
header.version = reader.readInt32();

// Valid MD2 file?
if (header.ident != "IDP2" || header.version != 8) {
    info.status = "Not a valid MD2 file";
    return returnObject;
}

// header
header.skinwidth        = reader.readInt32(); // texture width
header.skinheight       = reader.readInt32(); // texture height

header.framesize        = reader.readInt32(); // size in bytes of a frame

header.num_skins        = reader.readInt32(); // number of skins
header.num_vertices     = reader.readInt32(); // number of vertices per frame
header.num_st           = reader.readInt32(); // number of texture coordinates
header.num_tris         = reader.readInt32(); // number of triangles
header.num_glcmds       = reader.readInt32(); // number of opengl commands
header.num_frames       = reader.readInt32(); // number of frames

header.offset_skins     = reader.readInt32(); // offset skin data
header.offset_st        = reader.readInt32(); // offset texture coordinate data
header.offset_tris      = reader.readInt32(); // offset triangle data
header.offset_frames    = reader.readInt32(); // offset frame data
header.offset_glcmds    = reader.readInt32(); // offset OpenGL command data
header.offset_end       = reader.readInt32(); // offset end of file

// faulty size
if (reader.getSize() != header.offset_end) {
    info.status = "Corrupted MD2 file";
    return returnObject;
}

// texture coordinates
let count = 0;
reader.seek(header.offset_st);
for (var i = 0; i < header.num_st; i++) {
    var s = reader.readInt16();
    var t = reader.readInt16();

    st[i] = {
        s: s / header.skinwidth,
        t: t / header.skinheight
    };
}

reader.seek(header.offset_tris);
for (var i = 0; i < header.num_tris; i++) {
    var a = reader.readInt16();
    var b = reader.readInt16();
    var c = reader.readInt16();

    var uva_i = reader.readUInt16();
    var uvb_i = reader.readUInt16();
    var uvc_i = reader.readUInt16();

    triag[i] = {};
    triag[i].vertex = [];
    triag[i].st = [];

    triag[i].vertex[0] = a;
    triag[i].vertex[1] = b;
    triag[i].vertex[2] = c;

    triag[i].st[0] = uva_i;
    triag[i].st[1] = uvb_i;
    triag[i].st[2] = uvc_i;
}

// frames
reader.seek(header.offset_frames);
for (var f = 0; f < header.num_frames; f++) {
    var frame = {};

    frame.name = "";
    frame.scale = {};
    frame.translate = {};

    frame.scale.x = reader.readFloat();
    frame.scale.y = reader.readFloat();
    frame.scale.z = reader.readFloat();

    frame.translate.x = reader.readFloat();
    frame.translate.y = reader.readFloat();
    frame.translate.z = reader.readFloat();

    frame.vertices = [];

    frame.name = reader.readString(16).replace(/[^a-z0-9]/gi,''); // 4+4+4 4+4+4 (12 + 12) = 24 + 16 = 40

    for (var v = 0; v < header.num_vertices; v++) {
        var tempX = reader.readUInt8();
        var tempY = reader.readUInt8();
        var tempZ = reader.readUInt8();
        var normal = reader.readUInt8();

        var xx = frame.scale.x * tempX + frame.translate.x;
        var yy = frame.scale.z * tempZ + frame.translate.z;
        var zz = frame.scale.y * tempY + frame.translate.y;

        let vertex = [];

        vertex[0] = xx;
        vertex[1] = yy;
        vertex[2] = zz;

        frame.vertices.push(vertex);
    }

    frames.push(frame);
}

let res = {};

res.st = st;
res.triag = triag;

res.frame = [];
for (var i=0; i<frames.length; ++i )
    res.frame[i]=frames[i];


res.faces_count = header.num_tris;
res.vertices_count = header.num_vertices;
res.frames_count = header.num_frames;

return res;

}

main.js

let gl;
let shaderProgram;

let firstMouse = true;
let mouseDown = false;

let lastTime = 0;
let deltaTime;

let test;

let lastX= 0;
let lastY = 0;


let DIRS = {
    Forward: 0,
    Backward: 1,
    Left: 2,
    Right: 3
};

let KeyCodes = 
{
    Up: 38,
    Down : 40,
    Left : 37,
    Right : 39,

    W : 87,
    S : 83,
    A : 65,
    D : 68,

    Q : 81,
    E : 69,

    PageDown : 34,
    PageUp : 33
};

let pressedKeys = [];


let vertexShaderSource = `
precision highp float;

attribute vec3 aPos;
attribute vec2 aTexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

varying vec2 vTexCoord;


void main(void)
{
     gl_Position = projection * view * model * vec4(aPos, 1.0);
     vTexCoord = aTexCoord;
}
`;

let fragmentShaderSource = `
precision highp float;

varying highp vec2 vTexCoord;
uniform sampler2D uSampler;
void main(void)
{
  gl_FragColor = texture2D(uSampler, vec2(vTexCoord.s,1.0-vTexCoord.t));
}
`;

let camera;
function initGL()
{
let canvas = document.getElementById("Canvas3D");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
try
{
    gl = canvas.getContext("webgl2") || canvas.getContext("experimental-webgl2");
}
catch(e)
{
    alert("Your browser don't support WebGL");
}

gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);

gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LESS);

shaderProgram = new     ShaderProgram(gl,vertexShaderSource,fragmentShaderSource);
shaderProgram.use();

camera = {
    Init(shaderProgram)
    {
        this.shaderProgram = shaderProgram;
        this.pos = vec3.create();
        this.up = vec3.create();
        this.front = vec3.create();
        this.right = vec3.create();

        this.WorldUp = vec3.create();

        this.pos = [51.656294013839215, 36.9293564686086, -28.23351748054847];
        this.front = [-0.7667674915573891, -0.6401096994849556, 0.04824092159224934];
        this.up = [-0.6388465891741784, 0.7682835235935235, 0.040192821190338686];

        this.WorldUp = [0,1,0];

        this.yaw = 176.39999999999998;
        this.pitch = -39.8;

        this.speed = 25;
        this.sensivity = 0.1;
        this.zoom = 100;

        this.view = mat4.create();
        this.projection = mat4.create();
        mat4.perspective(this.projection, Math.PI/180.0*this.zoom,     gl.viewportWidth/gl.viewportHeight, 0.1, 200);
            this.shaderProgram.gl.uniformMatrix4fv(this.shaderProgram.projection, false,     this.projection);

        this.updateCameraVectors();
        this.updateView();

    },

    updateView: function()
    {
        let tmp = vec3.create();
        vec3.add(tmp, this.pos, this.front);
        mat4.lookAt(this.view, this.pos, tmp, this.up);
        this.shaderProgram.gl.uniformMatrix4fv(this.shaderProgram.view, false, this.view);
    },

    processKeyboard(deltaTime)
    {
        let velocity = this.speed * deltaTime;
        let tmp = vec3.create();

        if (pressedKeys[KeyCodes.W] || pressedKeys[KeyCodes.Up]) {
            vec3.scale(tmp, this.front, velocity);
            vec3.add(this.pos,this.pos,tmp);
        }
        if (pressedKeys[KeyCodes.S] || pressedKeys[KeyCodes.Down]) {
            velocity *=(-1);
            vec3.scale(tmp, this.front, velocity);
            vec3.add(this.pos,this.pos,tmp);
        }
        if (pressedKeys[KeyCodes.A] || pressedKeys[KeyCodes.Left]) {
            velocity *=(-1);
            vec3.scale(tmp, this.right, velocity);
            vec3.add(this.pos,this.pos,tmp);
        }
        if (pressedKeys[KeyCodes.D] || pressedKeys[KeyCodes.Right]) {
            vec3.scale(tmp, this.right, velocity);
            vec3.add(this.pos,this.pos,tmp);
        }
    },

    processMouseMovement(xoffset, yoffset)
    {
        this.yaw   += (xoffset*this.sensivity);
        this.pitch += (yoffset*this.sensivity);

        if (this.pitch > 89.0)
        this.pitch = 89.0;
        if (this.pitch < -89.0)
        this.pitch = -89.0;

        this.updateCameraVectors();
    },

    updateCameraVectors()
    {
        let ToRads = Math.PI/180;
        let yaw = this.yaw;
        let pitch = this.pitch;
        this.front[0] = Math.cos(ToRads*yaw) * Math.cos(ToRads*pitch);
        this.front[1] = Math.sin(ToRads*pitch);
        this.front[2] = Math.sin(ToRads*yaw) * Math.cos(ToRads*pitch);
        vec3.normalize(this.front, this.front);


        vec3.cross(this.right, this.front, this.WorldUp);
        vec3.normalize(this.right, this.right);

        vec3.cross(this.up, this.right, this.front);
        vec3.normalize(this.up, this.up);
    }
};

function load_binary_resource(url) {
    let req = new XMLHttpRequest();
    req.open('GET', url, false);
    req.overrideMimeType('text/plain; charset=x-user-defined'); // No unicode data
    req.send(null);
    if (req.status != 200) return '';
    return req.responseText;
}

let file = load_binary_resource('../models/rhino/Tris.md2');
let res = MD2_converter(file);

let texture = initTexture("../models/rhino/rhino.png");

let verts = [];
let inds = [];

let uvs = [];

for (let i =0;i<res.frame[0].vertices.length;i++)
{
    let vert = res.frame[0].vertices[i];
    verts.push(vert[0]);
    verts.push(vert[1]);
    verts.push(vert[2]);
}

for (let i =0;i<res.triag.length;i++)
{
    let triag = res.triag[i];
    inds.push(triag.vertex[0]);
    inds.push(triag.vertex[1]);
    inds.push(triag.vertex[2]);

    uvs.push(res.st[triag.st[0]].s);
    uvs.push(res.st[triag.st[0]].t);

    uvs.push(res.st[triag.st[1]].s);
    uvs.push(res.st[triag.st[1]].t);

    uvs.push(res.st[triag.st[2]].s);
    uvs.push(res.st[triag.st[2]].t);
}

test = new Drawable(shaderProgram,  verts, inds, uvs, texture);

camera.Init(shaderProgram);

requestAnimationFrame(gameCycle);
}

function recalculateFPS(gotTime)
{
    deltaTime = (gotTime - lastTime)/1000;
lastTime = gotTime;
}
function gameCycle(gotTime)
{
    recalculateFPS(gotTime);
    gl.clearColor(0,0,0,1);
    gl.clear(gl.COLOR_BUFFER_BIT);
    camera.processKeyboard(deltaTime);
    camera.updateView();
    test.draw();


    requestAnimationFrame(gameCycle);
}

window.onload=function()
{
    initGL();
};


document.onkeydown = function(e)
{
    pressedKeys[e.keyCode]=true;
};

document.onkeyup = function(e)
{
    pressedKeys[e.keyCode]=false;
};

document.body.onmousedown = function(event)
{
    mouseDown = true;
    lastX = event.clientX;
    lastY = event.clientY;
};

document.body.onmouseup = function(event)
{
    mouseDown = false;
};

document.body.onmouseout = function(event)
{
    mouseDown = false;
};

document.body.onmousemove = function (e)
{
if (!mouseDown)
    return;
let xpos = e.clientX;
let ypos = e.clientY;
if(firstMouse) {
    lastX = xpos;
    lastY = ypos;
    firstMouse = false;
}

    let xoffset = xpos - lastX;
    let yoffset = lastY - ypos;

lastX = xpos;
lastY = ypos;

camera.processMouseMovement(xoffset,yoffset);


}

main.html

    <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body scroll="no" style="overflow: hidden">
<canvas id="Canvas3D"></canvas>
<script src="../js/glmatrix/dist/gl-matrix.js"></script>

<script src="../js/MD2Import.js"></script>
<script src="../js/ShaderProgram.js"></script>
<script src="../js/Textures.js"></script>
<script src="../js/Drawable.js"></script>

<script src="../js/main.js"></script>
</body>
</html>

Drawable.js

class Drawable {
constructor(shaderProgram, vertices, indices, texCoords, texture) {
    this.gl = shaderProgram.gl;
    let gl = shaderProgram.gl;
    this.shaderProgram = shaderProgram;

    shaderProgram.aTexCoord = gl.getAttribLocation(shaderProgram.shaderProgram, "aTexCoord");
    shaderProgram.aPos = gl.getAttribLocation(shaderProgram.shaderProgram, "aPos");

    this.VAO = gl.createVertexArray();
    this.texture = texture;
    gl.bindVertexArray(this.VAO);

    this.vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    gl.vertexAttribPointer(shaderProgram.aPos, 3, gl.FLOAT, false, 12, 0);
    gl.enableVertexAttribArray(shaderProgram.aPos);

    this.EBO = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.EBO);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

    this.VBOTexCoords = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.VBOTexCoords);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords),gl.STATIC_DRAW);
    gl.vertexAttribPointer(shaderProgram.aTexCoord, 2, gl.FLOAT, false, 8, 0);
    gl.enableVertexAttribArray(shaderProgram.aTexCoord);








    gl.bindVertexArray(null);

    this.pos = vec3.create();
    this.rot = vec3.create(); // в Градусах
    this.scale = vec3.create();

    this.pos = [0,0,0];
    this.rot = [0,0,0];
    this.scale=[1,1,1];

    this.vertCount = indices.length;

    this.model = mat4.create();
}

updateModel() {
    mat4.identity(this.model);
    mat4.translate(this.model, this.model, this.pos);

    mat4.rotateX(this.model, this.model, Math.PI / 180 * this.rot[0]);
    mat4.rotateY(this.model, this.model, Math.PI / 180 * this.rot[1]);
    mat4.rotateZ(this.model, this.model, Math.PI / 180 * this.rot[2]);

    mat4.scale(this.model, this.model, this.scale);

}

translate(transX, transY, transZ)
{
    this.pos[0] += transX;
    this.pos[1] += transY;
    this.pos[2] += transZ;

}

rotate(rotX, rotY, rotZ)
{
    this.rot[0] += rotX;
    this.rot[1] += rotY;
    this.rot[2] += rotZ;
}

draw() {
    this.updateModel();
    let gl =this.gl;

    gl.uniformMatrix4fv(this.shaderProgram.model, false, this.model);

    gl.bindVertexArray(this.VAO);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.texture);
    gl.uniform1i(gl.getUniformLocation(shaderProgram.shaderProgram, "uSampler"), 0);
    //gl.drawArrays(gl.TRIANGLES, 0, this.vertCount);
    gl.drawElements(gl.TRIANGLES, this.vertCount,gl.UNSIGNED_SHORT,0);
}
}

尝试使用 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true),结果: Picture with flip

顺便说一句,它不应该工作,因为我已经翻转了着色器中的纹理:

gl_FragColor =texture2D(uSampler, vec2(vTexCoord.s,1.0 - vTexCoord.t));

rhino.png(纹理)textures

md2 文件:http://dropmefiles.com/zhQFU

当我删除索引缓冲区并将顶点和 uv 放入一个巨大的缓冲区中时,问题就解决了。它可能是什么?

最佳答案

解决方案是删除索引缓冲区并将所有内容放入顶点缓冲区中。它对我有用

关于javascript - WebGL - 导入 MD2 模型,纹理问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46435911/

相关文章:

ios - SceneKit - 纹理显示不正确

opengl-es - 将透明纹理与深度混合

javascript - 如何对从 blender 导出的动画 js 模型进行纹理处理? [三.js]

javascript - 大型SVG渲染期间的DOM操作

javascript - Google map 纹理 map

three.js - 如何在三个js中的自定义着色器上创建带有镜面反射贴图的镜面反射?

javascript - 带有着色器的背景平面与 Three.js 中的所有内容重叠

javascript - 测试 xml 中是否有空文本节点

javascript - 注册ProtocolHandler和ServiceWorker

javascript - 我的 jquery 代码没有动画