无法沿着轴旋转在WebGL中创建3D Koch

时间:2015-10-11 14:21:06

标签: javascript c++ opengl-es webgl

最近我选择了WebGL将我的C ++游戏移植到JS。我成功地为3D Koch曲线创建和旋转基础四面体。然后,由于WebGL中的Shaders,我无法翻译代码。我对问题的解决方法与OpenGL相同,计算新的几何点,然后,一旦形成三角形,我就绘制它。这似乎不适用于WebGL。 这是代码......     https://github.com/Horopter/koch-snowflake/blob/master/koch/koch3d.cpp 在我成功之前,这是WebGL的代码。具体来说,我需要帮助翻译功能......

所以这里是index.html



//compiled by Santosh. Title : main.js
var gl;

function initGL(canvas) {
    try {
        gl = canvas.getContext("experimental-webgl");
        gl.viewportWidth = canvas.width;
        gl.viewportHeight = canvas.height;
    } catch (e) {
    }
    if (!gl) {
        alert("Could not initialise WebGL, sorry :-(");
    }
    gl.enable(gl.DEPTH_TEST);
    gl.clearColor(0.0, 0.0, 0.0, 0.0);
    gl.viewport(0, 0, canvas.width, canvas.height);
}


function getShader(gl, id) {
    var shaderScript = document.getElementById(id);
    if (!shaderScript) {
        return null;
    }

    var str = "";
    var k = shaderScript.firstChild;
    while (k) {
        if (k.nodeType == 3) {
            str += k.textContent;
        }
        k = k.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, str);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(shader));
        return null;
    }

    return shader;
}


var shaderProgram;

function initShaders() {
    var fragmentShader = getShader(gl, "shader-fs");
    var vertexShader = getShader(gl, "shader-vs");

    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
        alert("Could not initialise shaders");
    }

    gl.useProgram(shaderProgram);

    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

    shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
    gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);

    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}


var mvMatrix = mat4.create();
var mvMatrixStack = [];
var pMatrix = mat4.create();

function mvPushMatrix() {
    var copy = mat4.create();
    mat4.set(mvMatrix, copy);
    mvMatrixStack.push(copy);
}

function mvPopMatrix() {
    if (mvMatrixStack.length == 0) {
        throw "Invalid popMatrix!";
    }
    mvMatrix = mvMatrixStack.pop();
}


function setMatrixUniforms() {
    gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
    gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}


function degToRad(degrees) {
    return degrees * Math.PI / 180;
}


var pyramidVertexPositionBuffer;
var pyramidVertexColorBuffer;

function initBuffers() {
    pyramidVertexPositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
    var vertices = [
        // Front face
        1.0,  1.0,  1.0,//a
        1.0, -1.0,  -1.0,//b
        -1.0, 1.0,  -1.0,//c

        // Right face
         1.0, -1.0,  -1.0,//b
        -1.0, 1.0,  -1.0,//c
         -1.0, -1.0, 1.0,//d

        // Left face
        1.0,  1.0,  1.0,//a
        -1.0, -1.0, 1.0,//d
        1.0, -1.0,  -1.0,//b

        // Back face
        -1.0, 1.0,  -1.0,//c
        -1.0, -1.0, 1.0,//d
         1.0,  1.0,  1.0//a

        
        
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    pyramidVertexPositionBuffer.itemSize = 3;
    pyramidVertexPositionBuffer.numItems = 12;

    pyramidVertexColorBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
    var colors = [
        // Front face
        1.0, 0.0, 0.0, 1.0,//a
        0.0, 1.0, 0.0, 1.0,//b
        0.0, 0.0, 1.0, 1.0,//c

        // Right face
        0.0, 1.0, 0.0, 1.0,//b
        0.0, 0.0, 1.0, 1.0,//c
        1.0, 1.0, 1.0, 1.0,//d

        // Left face
        1.0, 0.0, 0.0, 1.0,//a
        1.0, 1.0, 1.0, 1.0,//d
        0.0, 1.0, 0.0, 1.0,//b

        // Back face
        0.0, 0.0, 1.0, 1.0,//c
        1.0, 1.0, 1.0, 1.0,//d
        1.0, 0.0, 0.0, 1.0,//a
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
    pyramidVertexColorBuffer.itemSize = 4;
    pyramidVertexColorBuffer.numItems = 12;
}


var rPyramid = 0;

function drawScene() {
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);

    mat4.identity(mvMatrix);

    mat4.translate(mvMatrix, [0.0, 2.0, -8.0]);
    mat4.scale(mvMatrix,[0.7,0.7,0.7]);

    mvPushMatrix();
    mat4.rotate(mvMatrix, degToRad(rPyramid), [0, 1, 0]);

    gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pyramidVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, pyramidVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

    setMatrixUniforms();
    gl.drawArrays(gl.TRIANGLES, 0, pyramidVertexPositionBuffer.numItems);

    mvPopMatrix();
}


var lastTime = 0;

function animate() {
    var timeNow = new Date().getTime();
    if (lastTime != 0) {
        var elapsed = timeNow - lastTime;

        rPyramid += (90 * elapsed) / 1000.0;
       
    }
    lastTime = timeNow;
}


function tick() {
    requestAnimationFrame(tick);
    drawScene();
    animate();
}


function webGLStart() {
    var canvas = document.getElementById("gameCanvas");
    initGL(canvas);
    initShaders()
    initBuffers();
    gl.clearColor(0.0, 0.0, 0.0, 0.0);
    gl.enable(gl.DEPTH_TEST);

    tick();
}

webGLStart();

<script src="http://learningwebgl.com/lessons/lesson01/glMatrix-0.9.5.min.js"></script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;

varying vec4 vColor;

void main(void) {
    gl_FragColor = vColor;
}
</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(void) {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    vColor = aVertexColor;
}
</script>
    <canvas id="gameCanvas" style="border: none;" width="800" height="500">    </canvas>       
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

像OpenGL ES 2.0及更高版本的WebGL不再具有固定的功能管道。换句话说,它不支持glVertexglColor等,一次指定1个顶点。原因在于现代GPU的效率极低且速度慢。当然在你的电脑上,它的速度足够快,但它甚至不能接近GPU的工作方式,因此设计OpenGL的人们明智地决定去除那些东西,特别是对于ES =嵌入式系统=智能手机的OpenGL ES因为超低效率的方法只会占用用户的电池,因为它实际上并不是GPU工作,这也意味着用代码来驱动驱动程序以支持旧的低效方式。

你现在的做法是创建缓冲区(你在上面的例子中做了)并将数据放入其中。通常只需要创建一次数据。例如,如果您正在绘制一个金字塔,那么为什么每一个特定的每个顶点都可以指定它们一次,然后每次重复使用它们。效率更高。

因此,您基本上需要将旧的已弃用的OpenGL C ++代码重构为新的现代OpenGL ES代码。一个简单的方法可能是制作一些缓冲区创建者助手。实施例

function OldOpenGLVertexHelper() {
  var colors = [];
  var vertices = [];
  var normals = [];

  var currentColor = [1, 1, 1, 1];
  var currentNormal = [0, 0, 0];
  var mode;

  this.color3f = function(r, g, b) {
    currentColor = [r, g, b, 1];
  }

  this.color4f = function(r, g, b, a) {
    currentColor = [r, g, b, a];
  }

  this.color3fv = function(rgb) {
    currentColor = rgb.concat(1);
  }

  this.color4fv = function(rgba) {
    currentColor = rgba.slice();
  }

  this.normal3f = function(x, y, z) {
    currentNormal = [x, y, z];
  }

  this.normal3fv = function(xyz) {
    currentNormal = xyz.slice();
  }

  var vertex3f = function(x, y, z) {
    colors.push(currentColor[0], 
                currentColor[1], 
                currentColor[2], 
                currentColor[3]);
    normals.push(currentNormal[0],
                 currentNormal[1],
                 currentNormal[2]);
    vertices.push(x, y, z);
  }

  this.vertex3f = vertex3f;

  this.vertex3fv = function(xyz) {
    vertex3f(xyz[0], xyz[1], xyz[2]);
  };

  this.end = function() {
    return {
      vertices: new Float32Array(vertices),
      normals: new Float32Array(normals),
      colors: new Float32Array(colors),
      mode: mode,
    };
  });

  this.begin = function(m) {
     mode = m;
     colors = [];
     normals = [];
     vertices = [];,
  };
}

现在你可以做这样的事情

var oldGL = new OldOpenGLVertexHelper();

oldGL.color3f(0.0,0.0,0.0); 
oldGL.begin(gl.LINES);
    oldGL.vertex3fv(a);
    oldGL.vertex3fv(b);
    oldGL.vertex3fv(b);
    oldGL.vertex3fv(c);
    oldGL.vertex3fv(c);
    oldGL.vertex3fv(d);
    oldGL.vertex3fv(d);
    oldGL.vertex3fv(a);
    oldGL.vertex3fv(a);
    oldGL.vertex3fv(c);
    oldGL.vertex3fv(b);
    oldGL.vertex3fv(d);
var buffers = oldGL.end();

现在,您可以使用buffers.verticesbuffers.colorsbuffers.normals等访问创建的缓冲区。

您对这些缓冲区的处理取决于您自己。理想情况下,如果它们没有更改每个帧,则在初始化时创建它们并重用它们。请参阅上面发布的代码,该代码为金字塔创建了一组缓冲区

否则,如果您想要执行旧的OpenGL,您可以立即绘制

 gl.bindBuffer(gl.ARRAY_BUFFER, somebufferForPositions);
 gl.bufferData(gl.ARRAY_BUFFER, buffers.vertices, gl.DYNAMIC_DRAW);
 gl.bindBuffer(gl.ARRAY_BUFFER, somebufferForColors);
 gl.bindBuffer(gl.ARRAY_BUFFER, buffers.colors, gl.DYNAMIC_DRAW);

 // set your attributes
 ...
 gl.drawArrays(buffers.mode, 0, buffers.vertices.length / 3); 
 // NOTE: you'll need to change that divided by 3 if buffers.mode
 // is lines (2) or points (1)

这基本上就是旧的OpenGL驱动程序为你做的事情

我不知道这是否足以帮助你。由于您是WebGL的新手,我建议您阅读更多教程。 For drawing multiple objects maybe this will help