From a58b2878b23ad6d42d166cacb0f3a64f56bae073 Mon Sep 17 00:00:00 2001 From: deathcap Date: Sun, 12 Jan 2014 05:34:50 -0800 Subject: [PATCH] Add custom ShaderMaterial supporting greedy meshing + atlas texturing Fixes texture stretching when used with greedy voxel mesher (adds tiling) Squashed commit of the following: commit 3baac16ecffae7e211120c52aca7ff972a72edd6 Author: deathcap Date: Sun Jan 12 05:26:36 2014 -0800 Re-enable atlaspack tilepad. Fixes edge artifacts Ref https://github.com/deathcap/voxpopuli/issues/19 commit 0f4cf41fb89c140fd7d38ce4824e34390fb4b50a Author: deathcap Date: Sun Jan 12 05:11:42 2014 -0800 Add rotation in GLSL per side. Textures finally correct! At last, texture atlasing with greedy meshing. In summary, used the UV coordinates from three.js (may be a better way to do this?) as the starting tile texture offsets, then repeated with tile UVs from fract() of pos . n. Works but this custom shader is very basic at the moment. Ref https://github.com/deathcap/voxpopuli/issues/19 commit 02214eae9591fe163519b21d67d116685b308a84 Author: deathcap Date: Sun Jan 12 04:49:33 2014 -0800 Remove UV coord rotation - side textures are now correct, but need rotation commit c6b3079213692edd2c9ad89127ccd4c864c60439 Author: deathcap Date: Sun Jan 12 04:28:23 2014 -0800 Flip texture Y (aka V, aka T) in JS instead of GLSL commit 4430410dd2b6f02a334ca607027b82d169fbb991 Author: deathcap Date: Sun Jan 12 04:22:08 2014 -0800 Set tileCoord from passed vUv coordinate (topmost only) Gets close to proper material texturing, but not quite. Some block faces render as expected but others have the wrong texture. Still, closest I've gotten so far yet with greedy meshing + atlas uv + vjs.. commit bf7a410a0117e3660e596a73eb002769db008eb3 Author: deathcap Date: Sun Jan 12 04:04:52 2014 -0800 Restore three.js passing UV coords, though unused (commented out - texCoord=vUv stretches) commit bd3a80bab0a6279bb28cee3781b7c3b62fe0ed1a Author: deathcap Date: Sun Jan 12 03:53:49 2014 -0800 Revert "Attempt at passing UV texture coordinates from attributes, instead of uniforms" This reverts commit ce2c76c67aaf52a49cdc0c6cecc83cc752f7f606. commit ce2c76c67aaf52a49cdc0c6cecc83cc752f7f606 Author: deathcap Date: Sun Jan 12 03:53:32 2014 -0800 Attempt at passing UV texture coordinates from attributes, instead of uniforms commit 93115824a52d8408e3995687afade618cb9adfb2 Author: deathcap Date: Sat Jan 11 20:21:49 2014 -0800 Bug: tileOffsets uniform update changes all meshes commit 505e0de75f9889abbfa50ca6ac9bd8576ecf6ce6 Author: deathcap Date: Sat Jan 11 19:03:22 2014 -0800 Set tileOffsets from atlaspack top UV commit fcab71831d9af2f3ced329db922abd8203e51b1b Author: deathcap Date: Sat Jan 11 18:41:14 2014 -0800 Test setting tileOffsets uniforms from paint() commit 47c923692ab1b0d1bdc506edaeeb115a6d93681d Author: deathcap Date: Sat Jan 11 17:46:22 2014 -0800 Pass array of tileOffsets, for each of 6 faces commit 4d7bab0a0a473c0a906a7b58306cc99d6e79bb23 Author: deathcap Date: Sat Jan 11 17:13:24 2014 -0800 Use a more convenient faceIndex equation, 3-z-2x-3y commit 4710a164b891bb639699192b99bc8f484950367c Author: deathcap Date: Sat Jan 11 17:06:07 2014 -0800 Calculate face index from normal commit d702869d81c0f8728e773b46f587014bbfd0481d Author: deathcap Date: Sat Jan 11 14:13:01 2014 -0800 Pass tileOffset as uniform; cleanup commit ad3bf53e3b844d4f4a69657b69e6691868266821 Author: deathcap Date: Sat Jan 11 13:24:46 2014 -0800 Use dot product for tileUV, fixes vertical faces Formula from http://0fps.wordpress.com/2013/07/09/texture-atlases-wrapping-and-mip-mapping/ commit cf6d7210567980cf74a61685e04859d5bb0609c3 Author: deathcap Date: Sat Jan 11 12:56:23 2014 -0800 Working tiling using fract() on position, but only on horizontal faces and with hardcoded material Screenshot: http://i.imgur.com/jLKX9Np.png commit 416548cfe645b3276192a79fd618a2e2e9a46396 Author: deathcap Date: Sat Jan 11 11:59:18 2014 -0800 Back to stretched custom shader material commit fd8c2fbb2339666efcfb5d48725a5e446dbc603a Author: deathcap Date: Thu Jan 9 19:04:36 2014 -0800 Now I'm just guesisng :/ commit 1fed727edd1552873332b0e2a59f37941dbfa79d Author: deathcap Date: Thu Jan 9 18:58:57 2014 -0800 Move tile calculation to vertex shader commit 2b6120bc4ab21e16064fb7ec04bef0a657b56072 Author: deathcap Date: Thu Jan 9 18:50:07 2014 -0800 Remove unneeded scale function commit d555e2d0e87c8618c977776022c7c50bef064d17 Author: deathcap Date: Thu Jan 9 18:35:26 2014 -0800 Add scale(), but might not be needed commit 3b6fdfa243067241008584e7945203c7fb7b505b Author: deathcap Date: Thu Jan 9 18:24:46 2014 -0800 Disable tilepad for now commit 4cc5949a71b33e20516c49cf74e9ac15bf70c764 Author: deathcap Date: Thu Jan 9 18:24:04 2014 -0800 Reorganize constructor to initialize uniforms commit de992dac2021b4f3bcbc3260ba31680b0c07c05b Author: deathcap Date: Thu Jan 9 18:14:51 2014 -0800 Add atlasSize uniform for clarity commit e176a677bb9f74eadf21412b035ec551eddaacd2 Author: deathcap Date: Thu Jan 9 18:12:42 2014 -0800 Scale by 16/512 (texture/atlas), now voxel textures are sized correctly but not of the right material commit 42f118ebe2a0d64a9ec1f72e07062350c1be26ee Author: deathcap Date: Thu Jan 9 18:07:07 2014 -0800 Now each tile displays the entire texture atlas. Progress? commit e75fb66bd552415453146caea5222c248bf95556 Author: deathcap Date: Thu Jan 9 18:00:31 2014 -0800 Start porting https://github.com/mikolalysenko/ao-shader/blob/master/lib/ao.vsh . Only stripes so far commit c2188326192ad88d7c2c3761e5a09bd7262916f7 Author: deathcap Date: Thu Jan 9 17:38:00 2014 -0800 Attempt at tiling with fract(), not quite right commit d5eb246e9716542636438039f87b3f79aaa5d64a Author: deathcap Date: Thu Jan 9 13:31:56 2014 -0800 Pass normal and position varyings commit 87a33c24642acaf0a880357974894a37ff2820f9 Author: deathcap Date: Thu Jan 9 13:14:40 2014 -0800 Simple but working custom shader with textures Custom uniforms, vertex shader, and fragment shader Based on http://stackoverflow.com/questions/12627422/custom-texture-shader-in-three-js commit d4022d1f00c3ffcc97341605501271f7508d79df Author: deathcap Date: Wed Jan 8 21:28:11 2014 -0800 Test using ShaderMaterial (no texture) https://github.com/deathcap/voxel-texture/tree/shadertest --- index.js | 115 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 92 insertions(+), 23 deletions(-) diff --git a/index.js b/index.js index c6146b5..289884b 100644 --- a/index.js +++ b/index.js @@ -36,12 +36,94 @@ function Texture(game, opts) { var useFlatColors = opts.materialFlatColor === true; delete opts.materialFlatColor; + // create a canvas for the texture atlas + this.canvas = (typeof document !== 'undefined') ? document.createElement('canvas') : {}; + this.canvas.width = opts.atlasWidth || 512; + this.canvas.height = opts.atlasHeight || 512; + var ctx = this.canvas.getContext('2d'); + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + + // create core atlas and texture + this.atlas = createAtlas(this.canvas); + this.atlas.tilepad = true; + this._atlasuv = false; + this._atlaskey = false; + this.texture = new this.THREE.Texture(this.canvas); + this.options = { crossOrigin: 'Anonymous', materialParams: { ambient: 0xbbbbbb, transparent: false, - side: this.THREE.DoubleSide + side: this.THREE.DoubleSide, + + uniforms: { + tileMap: {type: 't', value: this.texture}, + tileSize: {type: 'f', value: 16.0}, // size of one individual texture tile + tileSizeUV: {type: 'f', value: 16.0 / this.canvas.width} // size of tile in UV units (0.0-1.0) + }, + vertexShader: [ +'varying vec3 vNormal;', +'varying vec3 vPosition;', +'varying vec2 vUv;', // to set from three.js's "uv" attribute passed in +'', +'void main() {', +' vNormal = normal;', +' vPosition = position;', +' vUv = uv;', +'', +' gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);', +'}' + ].join('\n'), + fragmentShader: [ +'uniform float tileSize;', +'uniform sampler2D tileMap;', +'uniform float tileSizeUV;', +'uniform vec2 tileOffsets[7];', +'', +'varying vec3 vNormal;', +'varying vec3 vPosition;', +'varying vec2 vUv;', +'', +'void main() {', +// use world coordinates to repeat [0..1] offsets, within _each_ tile face +' vec2 tileUV = vec2(dot(vNormal.zxy, vPosition),', +' dot(vNormal.yzx, vPosition));', + +' tileUV = fract(tileUV);', +'', +' // back: flip 180', +' if (vNormal.z < 0.0) tileUV.t = 1.0 - tileUV.t;', +'', +' // left: rotate 90 ccw', +' if (vNormal.x < 0.0) {', +' float r = tileUV.s;', +' tileUV.s = tileUV.t;', +' tileUV.t = 1.0 - r;', +' }', +'', +' // right: rotate 90 cw', +' if (vNormal.x > 0.0) {', +' float r = tileUV.s;', +' tileUV.s = tileUV.t;', +' tileUV.t = r;', +' }', // TODO: might technically need to mirror-image other sides? (can't really tell) +'', + +// three.js' UV coordinate is passed as tileOffset, starting point determining the texture +// material type (_not_ interpolated; same for all vertices). +' vec2 tileOffset = vUv;', + +// index tile at offset into texture atlas, see references: +// http://0fps.wordpress.com/2013/07/09/texture-atlases-wrapping-and-mip-mapping/ +// https://github.com/mikolalysenko/ao-shader/blob/master/lib/ao.fsh +// https://github.com/mikolalysenko/ao-shader/blob/master/lib/ao.vsh +' vec2 texCoord = tileOffset + tileSizeUV * tileUV;', +'', +' gl_FragColor = texture2D(tileMap, texCoord);', +'}' +].join('\n') }, materialTransparentParams: { ambient: 0xbbbbbb, @@ -49,28 +131,15 @@ function Texture(game, opts) { side: this.THREE.DoubleSide, //depthWrite: false, //depthTest: false + // TODO }, - materialType: this.THREE.MeshLambertMaterial, + materialType: this.THREE.ShaderMaterial, applyTextureParams: function(map) { map.magFilter = self.THREE.NearestFilter; map.minFilter = self.THREE.LinearMipMapLinearFilter; } }; - // create a canvas for the texture atlas - this.canvas = (typeof document !== 'undefined') ? document.createElement('canvas') : {}; - this.canvas.width = opts.atlasWidth || 512; - this.canvas.height = opts.atlasHeight || 512; - var ctx = this.canvas.getContext('2d'); - ctx.fillStyle = 'black'; - ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); - - // create core atlas and texture - this.atlas = createAtlas(this.canvas); - this.atlas.tilepad = true; - this._atlasuv = false; - this._atlaskey = false; - this.texture = new this.THREE.Texture(this.canvas); this.options.applyTextureParams(this.texture); if (useFlatColors) { @@ -80,9 +149,7 @@ function Texture(game, opts) { }); } else { var opaque = new this.options.materialType(this.options.materialParams); - opaque.map = this.texture; var transparent = new this.options.materialType(this.options.materialTransparentParams); - transparent.map = this.texture; this.material = new this.THREE.MeshFaceMaterial([ opaque, transparent @@ -290,17 +357,19 @@ Texture.prototype.paint = function(mesh, materials) { // | | // 3 -- 2 // faces on these meshes are flipped vertically, so we map in reverse - // TODO: tops need rotate if (isVoxelMesh) { - if (face.normal.z === -1 || face.normal.x === 1) { - atlasuv = uvrot(atlasuv, 90); - } atlasuv = uvinvert(atlasuv); } else { atlasuv = uvrot(atlasuv, -90); } + + // range of UV coordinates for this texture (see above diagram) + var topUV = atlasuv[0], rightUV = atlasuv[1], bottomUV = atlasuv[2], leftUV = atlasuv[3]; + + // pass texture start in UV coordinates for (var j = 0; j < mesh.geometry.faceVertexUvs[0][i].length; j++) { - mesh.geometry.faceVertexUvs[0][i][j].set(atlasuv[j][0], 1 - atlasuv[j][1]); + //mesh.geometry.faceVertexUvs[0][i][j].set(atlasuv[j][0], 1 - atlasuv[j][1]); + mesh.geometry.faceVertexUvs[0][i][j].set(topUV[0], 1.0 - topUV[1]); // set all to top (fixed tileSizeUV) } });