Skip to content

Instantly share code, notes, and snippets.

@tiagosr
Created February 28, 2013 20:39
Show Gist options
  • Save tiagosr/5059922 to your computer and use it in GitHub Desktop.
Save tiagosr/5059922 to your computer and use it in GitHub Desktop.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Exemplo 02: Primitivos básicos</title>
<script src="jquery-1.9.1.min.js"></script>
<script src="gl-matrix-min.js"></script>
<script type="text/x-glsl-vertex" id="simple-vertex">
uniform mat4 projectionMtx, modelViewMtx;
attribute vec3 inPosition;
attribute vec4 inColor;
varying vec4 fragColor;
void main() {
// gl_Position é uma das saídas padrão de vertex shaders
gl_Position = projectionMtx * modelViewMtx * vec4(inPosition, 1.0);
// fragColor é uma das informações que a gente vai passar
// do vertex shader para o fragment shader
fragColor = inColor;
}
</script>
<script type="text/x-glsl-fragment" id="simple-fragment">
precision mediump float;
varying vec4 fragColor; // entrada a ser linkada com o vertex shader
void main() {
gl_FragColor = fragColor; // gl_FragColor é uma das saídas padrão do GLSL,
// armazena o valor diretamente no buffer de cor
//gl_FragDepth = gl_FragCoord.z;
// profundidade pode ser alterada pelo shader,
// mas não no WebGL/OpenGLES.
}
</script>
<script type="text/javascript">
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
// função pra pegar código de shader de uma tag <script id="">
var getShaderFromID = function(id) {
var source = document.getElementById(id);
if (!source) {
return null;
}
var srcstr = "";
var child = source.firstChild;
while (child) {
if (child.nodeType == 3) { // se for nó de texto
srcstr += child.textContent;
}
child = child.nextSibling;
}
var shader;
if (source.type == "text/x-glsl-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (source.type == "text/x-glsl-vertex"){
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
// não existe shader de tesselation
// ou geometry pra GLES/WebGL ainda.
return null;
}
// anexa a string com o source ao shader
gl.shaderSource(shader, srcstr);
// compila o shader
gl.compileShader(shader);
// testa se foi compilado corretamente
if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
// matriz de projeção
var projectionMtx = mat4.create();
// matriz de objetos/mundo
var modelViewMtx = mat4.create();
// buffers de atributos
var vertexbuffer;
var colorsbuffer;
// programa do shader
var shaderpgm;
var setupGL = function(canvas) {
// não dá pra inicializar contexto 2D e 3D no mesmo canvas
gl = null;
try {
gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
} catch (e) {}
if (!gl) {
alert("bzzzt! no support for webgl here.");
}
}
var setup = function() {
canvas = document.getElementById("gl");
setupGL(canvas);
// seta infos básicas para as viewports
gl.clearColor(0.0,0.0,0.0,1.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearDepth(1.0);
// callback de redimensionamento da viewport
var resizefn = function(){
if ((canvas.width != canvas.clientWitdh) || (canvas.height != canvas.clientHeight)) {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
}
gl.viewportWidth = canvas.clientWidth;
gl.viewportHeight = canvas.clientHeight;
}
resizefn();
$(window).resize(resizefn);
// criando o programa dos shaders
shaderpgm = gl.createProgram();
var simple_vtx_shader = getShaderFromID("simple-vertex");
var simple_fgmt_shader = getShaderFromID("simple-fragment");
// anexando os shaders criados
gl.attachShader(shaderpgm, simple_vtx_shader);
gl.attachShader(shaderpgm, simple_fgmt_shader);
// linkando os shaders no programa
gl.linkProgram(shaderpgm);
// testa se tudo foi nos trinks
if(!gl.getProgramParameter(shaderpgm, gl.LINK_STATUS)) {
alert("Could not link shaders");
}
gl.useProgram(shaderpgm);
// seta algumas variáveis pra ajudar na hora de renderizar.
// como todo objeto normal em javascript, dá pra adicionar
// propriedades extras aos programas e shaders ...
shaderpgm.simpleVtxShader = simple_vtx_shader;
shaderpgm.simpleFragShader = simple_fgmt_shader;
// ... o que é bastante útil pra levar as localizações
// dos atributos e uniforms dos shaders
shaderpgm.inPositionLoc = gl.getAttribLocation(shaderpgm, "inPosition");
gl.enableVertexAttribArray(shaderpgm.inPositionLoc);
shaderpgm.inColorLoc = gl.getAttribLocation(shaderpgm, "inColor");
gl.enableVertexAttribArray(shaderpgm.inColorLoc);
shaderpgm.projectionMtxLoc = gl.getUniformLocation(shaderpgm, "projectionMtx");
shaderpgm.modelViewMtxLoc = gl.getUniformLocation(shaderpgm, "modelViewMtx");
// declarando os buffers de atributos
var vertices = [ // x, y, z
0.0, 0.8, 0.0,
0.8, -0.8, 0.0,
-0.8, -0.8, 0.0
];
var colors = [ // r, g, b, a
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0
];
// gerando o identificador do buffer de vértices
vertexbuffer = gl.createBuffer();
// anexando o identificador ao estado do opengl,
// para fazer modificações ao buffer
gl.bindBuffer(gl.ARRAY_BUFFER, vertexbuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// setando algumas propriedades extras pra ajudar na renderização
vertexbuffer.itemSize = 3;
vertexbuffer.numItems = 3;
// agora o mesmo com o buffer de cores
colorsbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorsbuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
colorsbuffer.itemSize = 4;
colorsbuffer.numItems = 2;
}
var render = function() {
// window.requestAnimationFrame é um callback dos navegadores mais recentes,
// praticamente o evento ENTER_FRAME do flash, mas vc tem que requisitar
// novamente o frame seguinte para ter animação contínua.
// requestAnimFrame é o esquema de compatibilidade entre os vários browsers,
// veja a linha 37.
window.requestAnimFrame(render, canvas);
// não faz mal setar a viewport várias vezes por frame.
// um sistema split-screen setaria a viewport tantas vezes
// quantas telas houverem.
gl.viewport(0.0, 0.0, gl.viewportWidth, gl.viewportHeight);
// glClear limpa a região da viewport nos buffers
gl.clear(gl.DEPTH_BUFFER_BIT|gl.COLOR_BUFFER_BIT);
// seta a matriz de projeção para um FOV vertical de 45 graus, com aspect ratio correto,
// e distância do plano próximo pra 0.1 e do plano distante para 100.0
mat4.perspective(projectionMtx, 45, gl.viewportWidth/gl.viewportHeight, 0.1, 100.0);
// seta transformação para identidade, depois faz translação pra posição correta
mat4.identity(modelViewMtx);
mat4.translate(modelViewMtx, modelViewMtx, [0.0, 0.0, -3.0]);
// manda essas matrizes pro shader de vértice
gl.uniformMatrix4fv(shaderpgm.projectionMtxLoc, false, projectionMtx);
gl.uniformMatrix4fv(shaderpgm.modelViewMtxLoc, false, modelViewMtx);
// bota os buffers de atributo pra funcionar. redundante especificar isso todo frame pra
// geometria que não muda, mas é exemplo de como fazer setup de um objeto
gl.bindBuffer(gl.ARRAY_BUFFER, vertexbuffer);
gl.vertexAttribPointer(shaderpgm.inPositionLoc, vertexbuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, colorsbuffer);
gl.vertexAttribPointer(shaderpgm.inColorLoc, colorsbuffer.itemSize, gl.FLOAT, false, 0, 0);
// a chamada do desenho propriamente dito
gl.drawArrays(gl.TRIANGLES, 0, vertexbuffer.numItems);
}
$(function(){
setup();
render();
});
</script>
<style type="text/css">
html, body {
margin: 0;
padding: 0;
height: 100%;
}
canvas#gl {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="gl"></canvas>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment