Last active
August 29, 2015 14:13
-
-
Save veeenu/c4f030fc9dfd637323e4 to your computer and use it in GitHub Desktop.
Isosurface polygonization with chunked voxels
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
precision highp float; | |
varying vec3 fnormal, flight, fpos; | |
varying vec2 ftextureCoordinate; | |
varying vec3 fogv; | |
uniform sampler2D textureSampler; | |
void main(void) { | |
vec3 ldir = normalize(flight); | |
float lweight = 0.3 + 0.7 * max(dot(normalize(fnormal), ldir), 0.0); | |
vec4 texColor = texture2D(textureSampler, ftextureCoordinate); | |
float fog = length(fogv); | |
float dfo = clamp(0.6 + 64.0 / exp2(fog - 6.0), 0.0, 1.0); | |
float fogval = clamp(exp2(fog - 6.0) / 2.0, 0.0, 1.0); | |
gl_FragColor = mix( | |
vec4(0.0, 0.0, 0.0, 1.0), | |
vec4(texColor.rgb * lweight, texColor.a), | |
dfo | |
); | |
/* gl_FragColor = mix( | |
gl_FragColor, | |
vec4(127.0/255.0, 192.0/255.0, 1.0, 1.0), | |
fogval | |
);*/ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<style> | |
body { | |
margin: 0; | |
padding: 0; | |
overflow: hidden; | |
} | |
#canvas { | |
background: rgb(127, 192, 255); | |
} | |
#texture { | |
display: none; | |
} | |
</style> | |
</head> | |
<body> | |
<canvas id='canvas'></canvas> | |
<canvas width='64' height='64' id='texture'></canvas> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.1.0/gl-matrix-min.js'></script> | |
<script src='isosurface-voxels.js'></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Procedurally generated Minecraft dirt texture. | |
*/ | |
(function() { | |
var ctx, imgd; | |
ctx = document.getElementById('texture').getContext('2d'); | |
imgd = ctx.createImageData(64, 64); | |
for(var x = 0; x < 48; x++) for(var y = 0; y < 16; y++) { | |
var color, br = Math.random() * 0.5 + 0.5; | |
if(x < 16) { // Grass on the leftmost tile | |
color = 0x51D651; | |
} | |
else if(x < 32) { // Side on the center tile | |
// Behave randomly around the 7th vertical row of pixels, | |
// full grass and full dirt before and after that | |
if(y > br * 7) | |
color = 0x633402; | |
else | |
color = 0x51D651; | |
} else { // Dirt on the rightmost tile | |
color = 0x633402; | |
} | |
var idx = 4 * (y * 64 + x); | |
imgd.data[idx] = br * ((color >> 16) & 0xFF); | |
imgd.data[idx + 1] = br * ((color >> 8) & 0xFF); | |
imgd.data[idx + 2] = br * ((color) & 0xFF); | |
imgd.data[idx + 3] = 0xFF; | |
} | |
ctx.putImageData(imgd, 0, 0); | |
}()); | |
(function() { | |
var canvas, gl, prg, aspectRatio, | |
vertexAttrib, texcAttrib, normAttrib, projUniform, viewUniform, texUniform, | |
texture, viewMatrix, ortho, | |
Chunk, Voxel, voxels, easeMap, quintFn; | |
/* | |
* Initialize context, compile shaders. | |
*/ | |
canvas = document.getElementById('canvas'); | |
canvas.width = window.innerWidth; | |
canvas.height = window.innerHeight; | |
aspectRatio = canvas.clientWidth / canvas.clientHeight; | |
gl = canvas.getContext('webgl'); | |
gl.enable(gl.DEPTH_TEST); | |
gl.clearColor(0.0, 0.0, 0.0, 0.0); | |
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); | |
gl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight); | |
prg = (function(vert, frag) { | |
var prg = gl.createProgram(); | |
gl.attachShader(prg, vert); | |
gl.attachShader(prg, frag); | |
gl.linkProgram(prg); | |
gl.useProgram(prg); | |
return prg; | |
}.apply(null, ['vertex', 'fragment'] | |
.map(function(f) { | |
var xhr = new XMLHttpRequest(); | |
xhr.open('GET', f + '.glsl', false); | |
xhr.send(); | |
return { type: f, src: xhr.responseText }; | |
}) | |
.map(function(s) { | |
var sh = gl.createShader(s.type === 'vertex' ? | |
gl.VERTEX_SHADER : gl.FRAGMENT_SHADER); | |
gl.shaderSource(sh, s.src); | |
gl.compileShader(sh); | |
return sh; | |
}))); | |
Chunk = function(pos) { | |
this.vertices = gl.createBuffer(); | |
this.normals = gl.createBuffer(); | |
this.uv = gl.createBuffer(); | |
this.pos = pos; | |
} | |
Chunk.prototype.buildMesh = function() { | |
var vertices = [], | |
normals = [], | |
uvs = [], | |
hp = 1/256, | |
x, y, z, pos, | |
sideUvs = [ | |
.25 + hp, .75 + hp, .5 - hp, .75 + hp, .25 + hp, 1 - hp, | |
.5 - hp, .75 + hp, .25 + hp, 1 - hp, .5 - hp, 1 - hp | |
], | |
topUvs = [ | |
hp, .75 + hp, .25 - hp, .75 + hp, hp, 1 - hp, | |
.25 - hp, .75 + hp, hp, 1 - hp, .25 - hp, 1 - hp | |
], | |
bottomUvs = [ | |
.5 + hp, .75 + hp, .75 - hp, .75 + hp, .5 + hp, 1 - hp, | |
.75 - hp, .75 + hp, .5 + hp, 1 - hp, .75 - hp, 1 - hp | |
], | |
transformFn = function(p, i) { | |
return (p + 2 * pos[i % 3]) / 20; | |
}, | |
xDisp = 16 * this.pos[0], | |
yDisp = 8 * this.pos[1], | |
zDisp = 16 * this.pos[2], | |
xMin = -16 + xDisp, xMax = 16 + xDisp, | |
yMin = -8 + yDisp, yMax = 8 + yDisp, | |
zMin = -16 + zDisp, zMax = 16 + zDisp; | |
for(x = xMin; x < xMax; x++) | |
for(y = yMin; y < yMax; y++) | |
for(z = zMin; z < zMax; z++) { | |
if(this.density(x, y, z) === 0) continue; | |
pos = [x, y, z]; | |
if(x === xMax - 1 || this.density(x + 1, y, z) === 0) { | |
vertices.push.apply(vertices, [ | |
1, -1, -1, 1, -1, 1, 1, 1, -1, // right | |
1, -1, 1, 1, 1, -1, 1, 1, 1 | |
].map(transformFn)); | |
normals.push.apply(normals, [ | |
1, 0, 0, 1, 0, 0, 1, 0, 0, | |
1, 0, 0, 1, 0, 0, 1, 0, 0 | |
]); | |
uvs.push.apply(uvs, sideUvs); | |
} | |
if(x === xMin || this.density(x - 1, y, z) === 0) { | |
vertices.push.apply(vertices, [ | |
-1, -1, -1, -1, -1, 1, -1, 1, -1, // left | |
-1, -1, 1, -1, 1, -1, -1, 1, 1 | |
].map(transformFn)); | |
normals.push.apply(normals, [ | |
-1, 0, 0, -1, 0, 0, -1, 0, 0, | |
-1, 0, 0, -1, 0, 0, -1, 0, 0 | |
]); | |
uvs.push.apply(uvs, sideUvs); | |
} | |
if(z === zMax - 1 || this.density(x, y, z + 1) === 0) { | |
vertices.push.apply(vertices, [ | |
-1, -1, 1, 1, -1, 1, -1, 1, 1, // back | |
1, -1, 1, -1, 1, 1, 1, 1, 1 | |
].map(transformFn)); | |
normals.push.apply(normals, [ | |
0, 0, 1, 0, 0, 1, 0, 0, 1, | |
0, 0, 1, 0, 0, 1, 0, 0, 1 | |
]); | |
uvs.push.apply(uvs, sideUvs); | |
} | |
if(z === zMin || this.density(x, y, z - 1) === 0) { | |
vertices.push.apply(vertices, [ | |
-1, -1, -1, 1, -1, -1, -1, 1, -1, // front | |
1, -1, -1, -1, 1, -1, 1, 1, -1 | |
].map(transformFn)); | |
normals.push.apply(normals, [ | |
0, 0, -1, 0, 0, -1, 0, 0, -1, | |
0, 0, -1, 0, 0, -1, 0, 0, -1 | |
]); | |
uvs.push.apply(uvs, sideUvs); | |
} | |
if(y === yMax - 1 || this.density(x, y + 1, z) === 0) { | |
vertices.push.apply(vertices, [ | |
-1, 1, 1, 1, 1, 1, -1, 1, -1, // top | |
1, 1, 1, -1, 1, -1, 1, 1, -1 | |
].map(transformFn)); | |
normals.push.apply(normals, [ | |
0, 1, 0, 0, 1, 0, 0, 1, 0, | |
0, 1, 0, 0, 1, 0, 0, 1, 0 | |
]); | |
uvs.push.apply(uvs, topUvs); | |
} | |
if(y === yMin || this.density(x, y - 1, z) === 0) { | |
vertices.push.apply(vertices, [ | |
-1, -1, 1, 1, -1, 1, -1, -1, -1, // bottom | |
1, -1, 1, -1, -1, -1, 1, -1, -1 | |
].map(transformFn)); | |
normals.push.apply(normals, [ | |
0, -1, 0, 0, -1, 0, 0, -1, 0, | |
0, -1, 0, 0, -1, 0, 0, -1, 0 | |
]); | |
uvs.push.apply(uvs, bottomUvs); | |
} | |
} | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertices); | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.normals); | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW); | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.uv); | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(uvs), gl.STATIC_DRAW); | |
this.count = vertices.length / 3; | |
} | |
Chunk.prototype.draw = function() { | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertices); | |
gl.vertexAttribPointer(vertexAttrib, 3, gl.FLOAT, false, 0, 0); | |
gl.enableVertexAttribArray(vertexAttrib); | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.normals); | |
gl.vertexAttribPointer(normAttrib, 3, gl.FLOAT, false, 0, 0); | |
gl.enableVertexAttribArray(normAttrib); | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.uv); | |
gl.vertexAttribPointer(texcAttrib, 2, gl.FLOAT, false, 0, 0); | |
gl.enableVertexAttribArray(texcAttrib); | |
gl.drawArrays(gl.TRIANGLES, 0, this.count); | |
} | |
// Initialize orthographic view matrix. | |
ortho = mat4.create(); | |
mat4.ortho(ortho, -aspectRatio, aspectRatio, -1, 1, -10, 100); | |
mat4.perspective(ortho, Math.PI / 3, aspectRatio, 0.1, 100); | |
// Incremental quintic easing function - we don't map to [0, 1], we map to | |
// increments such that their sum is always 1 and we can rotate the matrix | |
// from the step before instead of reinitializing it to identity every time | |
quintFn = function(i) { | |
return Math.pow(i / 64, 5) - Math.pow((i - 1) / 64, 5); | |
} | |
// Create an easing map so we don't need to compute the rotation angle every | |
// time, just look up the table. | |
// 0 - 64 -> quintic ease out. 64 - 96 -> stay put | |
easeMap = []; | |
for(var i = 64; i < 96; i++) | |
easeMap[i] = 0; | |
for(var i = 1; i <= 64; i++) | |
easeMap[i - 1] = 0.5 * Math.PI * (quintFn(65 - i)); | |
vertexAttrib = gl.getAttribLocation(prg, 'vertex'); | |
texcAttrib = gl.getAttribLocation(prg, 'textureCoordinate'); | |
normAttrib = gl.getAttribLocation(prg, 'normal'); | |
projUniform = gl.getUniformLocation(prg, 'projection'); | |
viewUniform = gl.getUniformLocation(prg, 'view'); | |
texUniform = gl.getUniformLocation(prg, 'textureSampler'); | |
gl.uniformMatrix4fv(projUniform, false, ortho); | |
texture = gl.createTexture(); | |
gl.bindTexture(gl.TEXTURE_2D, texture); | |
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, | |
document.getElementById('texture')); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
gl.uniform1i(texUniform, 0); | |
viewMatrix = mat4.create(); | |
var counter = 0; | |
mat4.translate(viewMatrix, viewMatrix, [0, -2, -12]); | |
mat4.rotate(viewMatrix, viewMatrix, Math.PI / 24, [1, 0, 0]); | |
mat4.rotate(viewMatrix, viewMatrix, Math.PI / 6, [0, 1, 0]); | |
var dens = function(x, y, z) { | |
return Math.abs(Math.sin(Math.PI * x / 32) * | |
Math.sin(Math.PI * z / 32) * 8 - y) <= 1 ? 1 : 0; | |
} | |
var cnks = []; | |
//console.profile('Chunks'); | |
for(var _x = -4; _x < 4; _x++) | |
for(var _z = -4; _z < 4; _z++) { | |
var cnk = new Chunk([_x, 0, _z]); | |
cnk.density = dens; | |
cnk.buildMesh(); | |
cnks.push(cnk); | |
} | |
//console.profileEnd(); | |
var loop = function() { | |
// Rotate the view matrix and step the counter | |
//mat4.rotate(viewMatrix, viewMatrix, easeMap[counter], [0, 1, 0]); | |
mat4.rotate(viewMatrix, viewMatrix, Math.PI / 1024, [0, 1, 0]); | |
counter++; | |
counter %= 95; | |
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); | |
gl.uniformMatrix4fv(viewUniform, false, viewMatrix); | |
for(var i = 0; i < cnks.length; i++) | |
cnks[i].draw(); | |
requestAnimationFrame(loop); | |
} | |
loop(); | |
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
uniform mat4 projection, view; | |
attribute vec3 vertex, normal; | |
attribute vec2 textureCoordinate; | |
varying highp vec3 fnormal, flight, fpos; | |
varying highp vec2 ftextureCoordinate; | |
varying highp vec3 fogv; | |
void main(void) { | |
gl_Position = projection * view * vec4(vertex, 1.0); | |
fnormal = normal; | |
flight = vec3(0.0, 0.5, 0.5); | |
fpos = vertex; | |
fogv = gl_Position.xyz; | |
ftextureCoordinate = textureCoordinate; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment