Dad72 Posted April 19, 2015 Share Posted April 19, 2015 Hello, Do you think that would be appropriate to paint decals roads on terrain?I think decal because it seems the easiest to achieve, but I told myself that this is not the best ways to do this (can be).I use the basic WorldMonger (demo available at BabylonJS) that automatically painted textures, but I would like an option to make manual adjustments, but I do not really know how. Thank you in advance for your advice, support ... Quote Link to comment Share on other sites More sharing options...
joshcamas Posted April 19, 2015 Share Posted April 19, 2015 Decals is not. Using a canvas is much better! By using dynamic texture! If you use a chunk system such as below, (I'll explain more in a PM) then each chunk will contain this function. The _x and _y is calculated as such: var _x = pickInfo.pickedPoint.x* (this.chunk.texSize.width / this.chunk.parent.chunkSize);var _y = pickInfo.pickedPoint.z* (this.chunk.texSize.height / this.chunk.parent.chunkSize); Here's an example of chunks:http://i.imgur.com/xcJKauG.pngBasically many different meshes, each with seperate textures and vertices.this.paint = function(_x,_y) { this.chunk.parent.unsavedChanges.texture = true; var size = this.options.brushSize; var _width = Game.data.brushes[this.options.selectedBrush].img.width; var _height = Game.data.brushes[this.options.selectedBrush].img.height; this.chunk.textureContext.save(); //Mask this.chunk.maskcontext.clearRect(0,0,this.chunk.texSize.width,this.chunk.texSize.height); this.chunk.maskcontext.save(); var wx = _x - (this.chunk.x*this.chunk.texSize.width); var wy = _y - (this.chunk.y*this.chunk.texSize.height); wy = this.chunk.texSize.height - wy; this.chunk.maskcontext.drawImage(Game.data.masks[this.options.selectedMask].img,0,0,Game.data.masks[this.options.selectedMask].img.width,Game.data.masks[this.options.selectedMask].img.height,wx-(size),wy-(size),size*2,size*2); this.chunk.maskcontext.globalCompositeOperation = 'source-in'; //Paint Mode this.chunk.brushcontext.clearRect(0,0,this.chunk.texSize.width,this.chunk.texSize.height); this.chunk.brushcontext.save(); if(this.options.paintType == "texture") { if (this.options.paintMode == "Tiled") { var scale = 1; var _x = (Math.ceil(_x/_width) -1)*_width var _y = (Math.ceil(_y/_height) -1)*_height //After... _x = _x - (this.chunk.x*this.chunk.texSize.width); _y = _y - (this.chunk.y*this.chunk.texSize.height); _y = this.chunk.texSize.height - Game.data.brushes[this.options.selectedBrush].img.height - _y; //Compute the width and height of the looper var mx = Math.ceil(size/_width) + 1; var my = Math.ceil(size/_height) + 1; //Back for(lx=0;lx<mx;lx++) { for(ly=0;ly<my;ly++) { this.chunk.brushcontext.drawImage(Game.data.brushes[this.options.selectedBrush].img,0,0,_width,_height,_x-(lx*_width),_y-(ly*_height),_width,_height); this.chunk.brushcontext.drawImage(Game.data.brushes[this.options.selectedBrush].img,0,0,_width,_height,_x+(lx*_width),_y-(ly*_height),_width,_height); this.chunk.brushcontext.drawImage(Game.data.brushes[this.options.selectedBrush].img,0,0,_width,_height,_x-(lx*_width),_y+(ly*_height),_width,_height); this.chunk.brushcontext.drawImage(Game.data.brushes[this.options.selectedBrush].img,0,0,_width,_height,_x+(lx*_width),_y+(ly*_height),_width,_height); } } } } else if (this.options.paintType == "color") { this.chunk.brushcontext.fillStyle= this.options.brushColor; this.chunk.brushcontext.fillRect(0,0,this.chunk.texSize.width,this.chunk.texSize.height); } //Now transfer to mask the image this.chunk.maskcontext.drawImage(this.chunk.brushcanvas,0,0); this.chunk.maskcontext.restore(); this.chunk.textureContext.drawImage(this.chunk.maskcanvas,0,0); this.chunk.textureContext.restore(); this.chunk.texture.update(); }Basically each chunk has two contexts, and a dynamic texture.One context contains the mask - a transparent image with a black shape. This shape is what shape the brush is:http://i.imgur.com/FCZo2Gi.png The other context contains the actual image you painting. So the editor gets where you clicked, realigns the area so it fits relative to the chunk, and draws squares of texture.My version is a bit complex, in that if the texture is super small and smaller than the mask, it repeats so it fills it. Then, on the mask context, it enables globalCompositeOperation = 'source-in'. This makes so whatever is painted next, will only be visible where there is black.Then the texture context is painted on the mask context, and then the texture is saved to the dynamic texture! (And if the mode is painting color, it just draws a colored box quickly instead of textures) Pretty complex, sadly. :S Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 20, 2015 Author Share Posted April 20, 2015 Josh. Can you take the WorldMonger demo babylon (download) and create your approach (simpler). I do not manage to understand the code you send me that is specific to your editor. This would help me a lot to have a more concrete example from a base I use. Thank you in advance. I really appreciate. Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 20, 2015 Author Share Posted April 20, 2015 I feel that having made WorldMonger use as a base for my terrain editor was a very bad idea in terms paint textures on the ground.Or I have not understood how to paint a texture on it existing. I do not understand as drawImage and textureDynamic and masks. I am total newbie on that. any help would be appreciated. Quote Link to comment Share on other sites More sharing options...
joshcamas Posted April 21, 2015 Share Posted April 21, 2015 EDIT: THIS TUTORIAL DOES NOT WORK DUE TO CROSS ORIGIN STUFF. IF SOMEONE COULD ADD THIS IMAGE TO THE PLAYGROUND:http://steinhauer.x10.mx/links/mask_1.pngI COULD GET IT WORKING THANKS Sadly I do not have time to actually make a demo... but if you want I can explain how canvas works... So, first off: dynamic texture is a canvas. You can draw "stuff" onto a canvas. Here are some examples:http://www.w3schools.com/html/html5_canvas.asp Ok, so first you create a dynamic texture, like so:var texture = new BABYLON.DynamicTexture("dynamic texture", 500, scene, true);var textureContext = texture.getContext();Sweet! So now you can draw stuff! Here's a simple example of that:http://www.babylonjs-playground.com/#1OQFOC Ok, so now we need to detect clicks, and draw a square there. After this, we need to change things up. To do this, we need to create 2 new canvases - brushCanvas and maskCanvas. brushCanvas holds whatever new changes we're adding - a square of color, some texture, whatever. This needs to be done in case we have several steps, like sevreal images.maskCanvas simply at first holds a black circle - and then we paste everything on the brushCanvas on top - whatever is black will show brushCanvas. So in other words, we'll end up with a circleof texture/color! Then, finally, we copy and paste whatever's on the mask onto the actual dynamic texture. Example of mask: (Doesn't work)http://www.babylonjs-playground.com/#1OQFOC#4 aWeirdo and Dad72 2 Quote Link to comment Share on other sites More sharing options...
Temechon Posted April 21, 2015 Share Posted April 21, 2015 Great explanations Josh ! For your mask, just put it in a dropbox public folder (or google drive) : http://www.babylonjs-playground.com/#1OQFOC#5, and it will work Dad72 1 Quote Link to comment Share on other sites More sharing options...
Xeonzinc Posted April 21, 2015 Share Posted April 21, 2015 Josh, what kind of performance do you get with your chunk system? Any sign of upper limits on how many dynamic textures can be handled? How would you handle a wide open terrain stretching off into the horizon? Dad72 - I've used worldmonger as the basis for some of my work, given that it uses 4/5 textures and applys them based on GPU to height, if you were applying josh's method in a basic way (to each of the ground textures for each chunk) you would need: 4 (base textures) x 2 (fill & mask for each) x Y chunks = Lots of dynamic textures Although I think that is not a clever way to do it. A much better might be to keep worldmonger as it is, but adopt Josh's code to add a chunk system ontop (so you have 4 tiled textures for worldmonger, and then lots of chunk textures not tiled). It would only need a small re-write of the worldmonger ground shader in order to draw the chunk textures on top of the existing worldmonger logic where alpha is visible. It would be interesting to know how many chunks can be handled in this way Dad72 1 Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 21, 2015 Author Share Posted April 21, 2015 Thank you very much for your explanations Josh I think that will help me a lot. I think I begin to understand. Thank you Temechon for the fix, it helps me to have a concrete overview.If I understand correctly, you need a dynamic texture and a canvas / layer of texture? Me, after I prefer to work on a single tile/terrain and in the future when the LOD system in the terrain would be done, I would use it to make large terrain. Meanwhile I use octree allows cutting the ground also. I agreement Xeonzinc , it would be good to change this WorldMonger demo. Thank you again Josh for the explanations. Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 21, 2015 Author Share Posted April 21, 2015 I have some questions:you need a dynamic texture and a canvas / layer of texture?How to save and load the textures generate?How to have an opacity between each layer to make the mixture? (maskcontext.globalAlpha = 0.4; is ok ?)Update demo playground:http://www.babylonjs-playground.com/#1OQFOC#12 Quote Link to comment Share on other sites More sharing options...
joshcamas Posted April 21, 2015 Share Posted April 21, 2015 @Xeonzinc: Well, for my editor I have not tested having a million chunks. The reason why chunks are useful is because they can be hidden, (less rendering) or even deleted if their far away.The editor uses dynamic texture, which may be somewhat worse than in-game - within the game the chunks just have the texture image itself as a diffuse.If you added a feature where far away chunks downloaded lower resolutions, that would even be better! @dad72:1) There are three components - dynamic texture, and it's canvas. Then a textureCanvas, (Think of it as brushCanvas) and then maskCanvas.Yes, to allow transfering. So if you wanted to do several steps, (Such as a repeating texture) it won't work to paste each step onto the mask - the mask only works with a single image being pasted.Basically textureCanvas (Or brushCanvas) holds the current image. MaskCanvas holds the mask, and the dynamic texture holds the already painted stuff from before. 2) I use php: Here's how I send it, not including directory creation/cleaning and POST variablesfunction saveImg($img,$finalDir,$title) { $img = str_replace('data:image/png;base64,', '', $img); $img = str_replace(' ', '+', $img); $data = base64_decode($img); $file = $finalDir.$title.'.png'; $success = file_put_contents($file, $data); echo "Success: ".$success; }Basically you send the image data, and it saves it to a certain directory. 3) Not sure what you mean... I noticed in the newest demo there is no transparency when the mask is partly transparent, which is strange. Do you mean this? I'll try to add the mask transparency and make it so you can drag the mouse around in the next few days. Dad72 1 Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 21, 2015 Author Share Posted April 21, 2015 Thank you Josh for your help. for part 3. I mean, do textures blend. for example, a grass texture with an opacity above a ground texture. exemple: I'll try to add the mask transparency and make it so you can drag the mouse around in the next few days.Yes, it would help me. I have 1 questions.How I should do for the texture repeats this several times because this pixelated? (vScale and uScale not work) Thank you again for help Josh Quote Link to comment Share on other sites More sharing options...
joshcamas Posted April 22, 2015 Share Posted April 22, 2015 So first you need to add scaling. Here's the function to scale without blurring:var resizeImage = function( img, scale ) { // Takes an image and a scaling factor and returns the scaled image // The original image is drawn into an offscreen canvas of the same size // and copied, pixel by pixel into another offscreen canvas with the // new size. var widthScaled = img.width * scale; var heightScaled = img.height * scale; var orig = document.createElement('canvas'); orig.width = img.width; orig.height = img.height; var origCtx = orig.getContext('2d'); origCtx.drawImage(img, 0, 0); var origPixels = origCtx.getImageData(0, 0, img.width, img.height); var scaled = document.createElement('canvas'); scaled.width = widthScaled; scaled.height = heightScaled; var scaledCtx = scaled.getContext('2d'); var scaledPixels = scaledCtx.getImageData( 0, 0, widthScaled, heightScaled ); for( var y = 0; y < heightScaled; y++ ) { for( var x = 0; x < widthScaled; x++ ) { var index = (Math.floor(y / scale) * img.width + Math.floor(x / scale)) * 4; var indexScaled = (y * widthScaled + x) * 4; scaledPixels.data[ indexScaled ] = origPixels.data[ index ]; scaledPixels.data[ indexScaled+1 ] = origPixels.data[ index+1 ]; scaledPixels.data[ indexScaled+2 ] = origPixels.data[ index+2 ]; scaledPixels.data[ indexScaled+3 ] = origPixels.data[ index+3 ]; } } scaledCtx.putImageData( scaledPixels, 0, 0 ); var exported = new Image(); exported.src = scaled.toDataURL("image/png"); return exported;} To repeat texture, you basically compute the scaling of brush and the size of the texture. Here's my code for my editor://Compute the width and height of the looper var mx = Math.ceil(size/_width) + 1; var my = Math.ceil(size/_height) + 1; for(lx=0;lx<mx;lx++) { for(ly=0;ly<my;ly++) { this.chunk.brushcontext.drawImage(Game.data.brushes[this.options.selectedBrush].img,0,0,_width,_height,_x-(lx*_width),_y-(ly*_height),_width,_height); this.chunk.brushcontext.drawImage(Game.data.brushes[this.options.selectedBrush].img,0,0,_width,_height,_x+(lx*_width),_y-(ly*_height),_width,_height); this.chunk.brushcontext.drawImage(Game.data.brushes[this.options.selectedBrush].img,0,0,_width,_height,_x-(lx*_width),_y+(ly*_height),_width,_height); this.chunk.brushcontext.drawImage(Game.data.brushes[this.options.selectedBrush].img,0,0,_width,_height,_x+(lx*_width),_y+(ly*_height),_width,_height); } }(Note: The variables aren't the same, but I don't have time to implement it into the demo for now. Maybe when I find time?) And yes, adding opacity to the mask would work perfectly - draw, then switch textures. This would give the effect you wish. Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 23, 2015 Author Share Posted April 23, 2015 I do not understand where I should use resizeImage(img, scale). at what time you use it? You have a small example please. Thank you Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 24, 2015 Author Share Posted April 24, 2015 I tried your resizeImage function and this is even more pixeliser the pictures while I painted. oh and I have of masks for you : brushes.zip => I advise you to resize images in 64 * 64, the brush is faster and it also loads faster. Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 25, 2015 Author Share Posted April 25, 2015 I improve your function saveImag() Josh to compress the final image. an image of 1024 * 1024 is reduced to 2.0 MB => 1.60 MB.I also add permissions with chmod. locally it is not necessary, but once online is necessary.<?phpheader('Content-Type: text/html; charset=UTF-8');header('Content-Type: image/png');function saveImg($img, $finalDir, $nameImage) { $img = str_replace('data:image/png;base64,', '', $img); $img = str_replace(' ', '+', $img); $data = base64_decode($img); $file = $finalDir.$nameImage.'.png'; chmod($file, 0777); $success = file_put_contents($file, $data); $im = imagecreatefrompng($file); imagepng($im, $file, 9); chmod($file, 0644); }saveImg($_POST['image'], "./path/images/", $_POST['terrainName']);?> Quote Link to comment Share on other sites More sharing options...
dbawel Posted April 25, 2015 Share Posted April 25, 2015 Keep this post going! This is one of the best topics I've seen in a while, and am having a blast just trying to keep up with everything that's being covered. I was sitting down today to begin working on a multi-user creative drawing application (just for fun,) and this discussion has caused me to change my approach - and will already save me loads of time. You guys are brilliant! Dad72 1 Quote Link to comment Share on other sites More sharing options...
joshcamas Posted April 25, 2015 Share Posted April 25, 2015 How does compression work? Does it make it look fuzzier or make it so the resolution less? It sounds awesome! All the resize image function does is make it so the image isn't fuzzy when scaled. This is useful for retro, if you don't want this feature just ignore it. Even so probably a better idea to just not add that until later. Also, yeah when I uploaded the image I think it got bigger. And thanks for the brushes, their amazing!!!!! I'll get to working on the demo for a bit Quote Link to comment Share on other sites More sharing options...
joshcamas Posted April 25, 2015 Share Posted April 25, 2015 Looks like the mask link is broken, and I can't seem to get it working on my dropbox. Dad72 wanna try it on yours? EDIT: Got it working! Here's my newest version. All I added was so you can drag. http://www.babylonjs-playground.com/#1OQFOC#13 I'm not sure what's up with the opacity not working! It should... Also, we need to make it so the image doesn't overlap and stuff. If you want to see an example, hop over to this link: http://steinhauer.x10.mx/projects/editor/0.55/editor/ Instructions: Under the "project" panel, press "load project". Then select "terrainExample", and load. Now go to the "Map" on the topbar, and click "select map".Create a new map. Now you can go to "Terrain", then "New terrain". Create terrain. Now you can sculpt and paint! If you select your mask/texture, notice how it paints in a seemless texture. we need this! Note: Right click to move camera, left click to interact, middle click to select, and spacebar to move camera to selection. BTW this version seems to be very very buggy, so be warned! Stuff has been breaking a lot today! Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 25, 2015 Author Share Posted April 25, 2015 How does compression work? Does it make it look fuzzier or make it so the resolution less? It sounds awesome!The texture remains as it is. it does not become blurred or anything bad. I'll watch your link Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 25, 2015 Author Share Posted April 25, 2015 I have reproduced the problem I have at home (pixelation/zoom/big of the image) http://www.babylonjs-playground.com/#1OQFOC#14 The problem I think is that I work directly on large ground. You, you work on several small ground, which causes this problem at my huge textures. How to solve this? I like the results on your demo of your editor, this is what I seek, also with the opacity, but it is not working on your editor yet. Thanks Quote Link to comment Share on other sites More sharing options...
joshcamas Posted April 25, 2015 Share Posted April 25, 2015 Ahhh I see! What we need to implement is scaling! I haven't even added this feature to mine, LOL! Well, it's time, I guess xD For my editor I will be not working on the terrain editing, because my current project does not use terrain at all. First step is implementing repeating and seamless texture.I changed the texture to something tiny, where we can see the image repeating. Here's what I have so far. Now the texture "fits" correctly, but... everything is so wrong.http://www.babylonjs-playground.com/#1OQFOC#15 I'm having lots of trouble getting my old code merged with this new stuff.... idk why, exactly. :/ Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 26, 2015 Author Share Posted April 26, 2015 I only see a white image on your example. but I put the grass texture, it always zoom in on the image, it would have to face the opposite. the image must have a resolution more higher.I have confessed really struggling with full functionality to draw on a canvas. Quote Link to comment Share on other sites More sharing options...
joshcamas Posted April 26, 2015 Share Posted April 26, 2015 The white image has a black line around it, usually. It's the same one as my editor, the default brush.And yeah, visualizing this canvas stuff in a 3D space can be really hard, it hurts my brain too. :c Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 27, 2015 Author Share Posted April 27, 2015 I do not see black line around. http://www.babylonjs-playground.com/#1OQFOC#17 try this. you can still see the image zooms. we close track. it should be the reverse.Have you been able to continue this demo. for example I brushScale that you add is not used. Again thank you Josh. I have over this feature with the opacity of the texture by layer to finish to complete the V2.3 of my editor and start creating a game demo to finalize the editor and the site Quote Link to comment Share on other sites More sharing options...
Dad72 Posted April 28, 2015 Author Share Posted April 28, 2015 I succeeded in setting up the scale textures and alpha texture, but the pixels are large for scale. Can be that it still misses something, but I do not see what. http://www.babylonjs-playground.com/#1OQFOC#25 Thank you Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.