2015-10-11 2 views
0

Недавно я взял WebGL для переноса моей игры на C++ в JS. Мне удалось создать и повернуть базовый тетраэдр для кривой 3D Коха. Опять же, из-за Shaders в WebGL, я не могу перевести код. Мой подход к проблеме был таким же, как и в OpenGL, вычислять новые точки геометрии, а затем, как только образуется треугольник, я рисую его. Это не работает в WebGL. Вот код ... https://github.com/Horopter/koch-snowflake/blob/master/koch/koch3d.cpp и вот код для WebGL, пока я не преуспел. В частности мне нужна помощь с переводом функций ...Невозможно создать 3D Koch в 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> 

ответ

0

WebGL, как OpenGL ES 2.0 и выше не имеет функции фиксированного конвейера больше. Другими словами, он не поддерживает glVertex, glColor и т. Д., Где вы указываете 1 вершину за раз. Причина в том, что современные графические процессоры крайне неэффективны и медленны. Конечно, на вашем ПК это было достаточно быстро, чтобы заставить работать, но он даже не удаленно близок к тому, как работают графические процессоры, и поэтому Khronos, люди, которые разрабатывают OpenGL, решительно решили удалить этот материал, особенно для OpenGL ES, где ES = Embedded Systems = Smartphones потому что супер-неэффективные методы питают аккумулятор пользователя для одного, и поскольку на нем не работают графические процессоры, это также означает раздувание драйверов кодом с поддержкой старых неэффективных способов.

Как вы делаете это сейчас, вы создаете буферы (которые вы делаете в своем примере выше), и вы помещаете в них данные. Обычно эти данные нужно создавать только один раз. Например, если вы рисуете пирамиду, зачем задавать каждую вершину каждый кадр, когда вы можете просто указать их один раз и повторно использовать их каждый раз после этого. Гораздо эффективнее.

Итак, вам в основном необходимо перестроить старый устаревший код 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.vertices, buffers.colors, buffers.normals и т.д.

Что вы делаете с этими буферами до вы. В идеале, если они не меняют каждый кадр, вы должны создать их во время init и повторно использовать их. Смотрите код размещен выше, который создал один набор буферов для пирамиды

В противном случае, если вы хотите, чтобы делать то, что старый 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.

+0

Любопытный и любопытный ... Фракталы, такие как кривая koch поверхности Коха, требуют от нас динамического создания точек. По сути, это предложенный алгоритм. создание точек может быть сделано статически, но затем снова, собирание таких точек, присутствующих в массиве буфера, и построение графика является жестким. Кроме того, мне нужно разработать постоянно развивающуюся поверхность. Есть ли способ, которым это можно было бы сделать?
Другой подход, предложенный в то время, когда пирамида статична, заключается в добавлении к нему объектов в определенных местах. Могу ли я создать объект, а затем создать несколько его экземпляров? –

+0

Однако в новом подходе мне нужно выровнять новый экземпляр вдоль нормального присутствия в центре тяжести поверхности старого экземпляра. Итак, любое предложение, в котором я могу создать новые пирамиды с использованием модели, создать несколько экземпляров, а затем TSR разместить в новой позиции? –

+0

Если все пирамиды - это в основном одно и то же, только что перегруппированное, переориентированное и масштабированное, вы можете просто сделать один набор точек пирамиды во время init, в момент рисования установите шейдер (useProgram), установите все буферы/атрибуты, затем для каждая пирамида установила какую-то униформу, куда ее поместить, и назовем ничью. Если пирамиды не перемещаются относительно друг друга, тогда вы можете создать одну модель, содержащую все комбинации пирамид. Это будет работать быстрее всего. – gman

Смежные вопросы