Zylann / godot_heightmap_module

Heightmap module for Godot Engine 3.0 [NO LONGER_MAINTAINED]
Other
64 stars 9 forks source link

Texture painting #11

Open faculezcano opened 6 years ago

faculezcano commented 6 years ago

I figured out how to get working the vertex painting and i wanted to make a height lerp vertex painting, but i haven't access to the shader params, so i moded the plugin to expose the ShaderMaterial instead of the Shader. I dont know how is going to be implemented to let the user make the vertex color blending, its correct to expose the ShaderMaterial?

Sorry for my bad english!

faculezcano commented 6 years ago

This is what i've achieved so far godot

Only vertex painting, no other mesh involved

Zylann commented 6 years ago

that looks pretty neat, nice water shader :)

However something confuses me with your post, this module doesn't support any form of "vertex painting", since the mesh is read-only and re-used for LOD. The way to paint the map currently is to paint an actual texture, and this texture is rasterized in the fragment shader, not vertex shader (LOD would destroy details). Painting textures is a feature I'm working on with a new splatting shader (which will support as many textures as you want at a fixed cost).

You can modify the shader by creating one in the inspector under the custom shader property, and it will appear with the current shader, in which you can do whatever you want. Some stuff is indeed not exposed (like, you cant set uniforms in the editor), and I was thinking about exposing a custom Material instead of a shader, however it may require good documentation because it's not going to be as simple as it sounds, because it's possible in the future that multiple instances of the material get used instead of a single one + the default shader will be more complicated in the future.

faculezcano commented 6 years ago

Sorry! Yes you pass a texture with the color info, I call it vertex painting since accomplish the same task. My cuestion was how to access shader uniforms, I exposed the shader material for testing, but I don't take in account material reusing haha.

Zylann commented 6 years ago

Yeah for now it's safe to modify the material, as long as you don't mess options that are actually used by the renderer. I dont know yet how it will be done in the future, maybe will just need more care from users... that's a point I should eventually discuss with Reduz when the time comes.

faculezcano commented 6 years ago

Excellent, i think this is priority feature, is a must have. Vertex Painting meshes in editor too. An other thing i faced was using normalmaps, since you modify the NORMAL of the shader, i dont understand why when i set NORMALMAP it doesn't work. I managed to get normalmaps textures to apply multiplying NORMAL and normal texture, like NORMAL*=normalTex. Can you explainme why is that? and if this is not the way, hoy to apply normalmaps to the heightmap shader. Thanks!!

Zylann commented 6 years ago

You're right, the way is to apply the normal maps of your textures in the shader. The module cannot use regular Godot materials, it has to be a ShaderMaterial. The current default shader is not final, it barely handles elevation and base shading, no textures at the moment. I can work on exposing a material, but it may change in the future because my splatting shader will need another feature Godot needs to have, which is texture arrays :p

faculezcano commented 6 years ago

My question is if setting the NORMAL = NORMALnormalTex is right, since NORMAL has the information of the normal of the Heightmap surface. If i'm not wrong NORMALMAP is used for normal texture and NORMAL for the normal vector of the surface. When i first try to set NORMALMAP = normalTex, it doesn't work, i got black surface. I figured it out you modifyed NORMAL, and try to play around with it and what worked was NORMAL = NORMALnormalTex; I don't know if i'm explaining myself well.

Zylann commented 6 years ago

Oh... I don't know, maybe there is a bug, or a problem with the way you get your normal? Did you unpack it? Does it work if you do this on a regular mesh with a basic shader?

faculezcano commented 6 years ago

do you want me to work in the vertex painting(the ui part that is missing)? you can guideme with the implementation way. I have to cleanup a bit my code and make a pr so you can review

Zylann commented 6 years ago

@faculezcano I don't even know how the UI should look like, it will depend a lot about how the texturing system works (I'd like to find a solution to fix those ugly bugged icons for height painting though)

darrylryan commented 6 years ago

@faculezcano @Zylann What do you have to do to expose the material so that textures can be applied?

Zylann commented 6 years ago

@darrylryan technically not much to change, but there are twists like, what if the user replaces the shader by something unexpected, what if the expected uniforms aren't there, what if something the user tries to do makes the editor side useless, what if the terrain system needs to generate shader code for performance etc. That's why it will need good documentation so that users know what they are doing (especially power users who write custom shaders).

For now I think the editor will just allow to paint on textures (heights, colors, textures, eventually diffuse map, and holes), but I'm not sure what will happen with the shader yet. At the moment it's a single one, which will get more complicated soon as I add splatting.

You should post other bugs as new issues please ;)

darrylryan commented 6 years ago

@Zylann Makes sense... but assuming I want to hack the current shader, how can I expose the uniforms to the editor so that I can set custom texture2d inputs to play with?

Zylann commented 6 years ago

Currently, you can hack with the shader by creating one from within the inspector (in the custom shader property), and it will be pre-filled with the code. There is no way to set uniforms, I may add this soon basically by exposing the material. There will be a name convention for uniforms used by the base system.

As said above in the thread, I also thought that, if the property is a ShaderMaterial, what would happen if the terrain actually needed multiple instances internally? For example, a terrain may be so big that multiple textures would be needed to render it, which means multiple materials with different textures assigned (essential for terrain streaming), thought this is a pretty advanced feature.

darrylryan commented 6 years ago

@Zylann I did manage to create a custom shader from the inspector, but I can't figure out how to actually pass in image, the uniforms aren't exposed at all... what do I need to do to actually pass in textures in that way?

Zylann commented 6 years ago

@darrylryan like I said, it's not possible in the current version. I will expose it soon by changing the property to be a ShaderMaterial instead of a Shader. I'm not sure if it will stay that way, but at least it unlocks features.

darrylryan commented 6 years ago

Ah I see, thanks. I think that will be good enough for most early adopters... if we change the shader and it breaks it should be pretty obvious why :)

Zylann commented 6 years ago

I exposed a custom material in https://github.com/Zylann/godot_heightmap_module/commit/e7e8ecc81df8aaa105c46c05f2bd55621add806f

I had to write a bit of inefficient code, hopefully it can be improved in the future with a few engine additions

darrylryan commented 6 years ago

@Zylann I've played with the shader a bit but the albedo still seems to come out white, even if i pass in a custom texture. Very odd. The same sampler code works fine on a plane.

Zylann commented 6 years ago

@darrylryan what is your shader?

What I recently added is not intented to be final, because I'm not satisfied yet, being constrained by what I want to achieve and what Godot allows me to do, so here is something important to note:

When you create a new ShaderMaterial from within the inspector, it should be pre-filled with an equivalent of the internal material + shader, allowing you to "fork" it. But, because of what I said earlier in the thread, the parameters of this material is actually copied every frame into the real internal one(s), because the way the system works is a bit more complex than what you would have with a basic MeshInstance. I copy for two reasons: 1) If procedural textures from the heightmap end up in your material, you would be unable to use it for other terrains 2) Godot could end up trying to save those textures as files, which is not intented 3) The internal terrain system may use more than a single material

Because the shader has to comply to this system, you will see a bunch of parameters appear as null (heights, normals, colors, splat etc...). You are not supposed to assign them, because they are generated procedurally and will be overriden anyways by the system. Any other param that YOU add however, should be fine.

Modifying ALBEDO should work though, it depends how you are doing it though, hence why I'd need to see your shader.

darrylryan commented 6 years ago

@Zylann I've got this at the moment but it just comes out white

shader_type spatial;

uniform sampler2D height_texture;
uniform sampler2D normal_texture;
uniform sampler2D color_texture;
uniform sampler2D splat_texture;
uniform sampler2D mask_texture;
uniform sampler2D custom_albedo : hint_albedo;

uniform vec2 heightmap_resolution;
uniform mat4 heightmap_inverse_transform;
varying vec3 unpacked_normal;
varying vec2 heightmap_uv;
varying vec2 texture_uv;

vec3 unpack_normal(vec3 rgb) {
    return rgb * 2.0 - vec3(1.0);
}

void vertex() {
    vec4 tv = heightmap_inverse_transform * WORLD_MATRIX * vec4(VERTEX, 1);
    heightmap_uv = vec2(tv.x,tv.z) / heightmap_resolution;
    texture_uv = vec2(tv.x,tv.z) / vec2(1024,1024);
    VERTEX.y = texture(height_texture, heightmap_uv).r;
    unpacked_normal = unpack_normal(texture(normal_texture, UV).rgb);
}

void fragment() {

    float mask = texture(mask_texture, UV).r;
    if(mask > 0.5)
        discard;
    NORMAL = unpacked_normal;
    ALBEDO = texture(custom_albedo,texture_uv, 1.0).rgb;
    ROUGHNESS = 1.0;
    METALLIC = 0.0;

}
Zylann commented 6 years ago

Hmm I didn't know about hint_albedo and 3-parameter texture... I don't see what's wrong with albedo here, though the default shader has an albedo using color_texture and that one works, so maybe something wrong with your texture or lighting... Ah also if you dont set the NORMAL in the vertex shader, some shading may not work (not my fault, Godot's renderer). I may try this at home though.

darrylryan commented 6 years ago

@Zylann I've tried a few textures... the default shader doesn't work for me either though...

It seems if I set the albedo to the normal texture it works, so I guess the custom_albedo just isn't getting through even though its defined in uniforms and set in the material... only the hard-coded ones are getting in.

Zylann commented 6 years ago

It doesn't seem right... as you can see here, params from your custom material are supposed to be synced https://github.com/Zylann/godot_heightmap_module/blob/master/height_map.cpp#L260 But I need to test this too

Zylann commented 6 years ago

Aaah I think I know why... try to translate the terrain, you'll see it will update

image

Looks like I forgot to actually update params every frame^^" though some actions like translate will do it

darrylryan commented 6 years ago

image Woohoo... progress :D

I got another crash when I opened the scene though - I had to delete and recreate a new terrain to do the above. I snagged a stack trace incase it is helpful:

image

Zylann commented 6 years ago

@darrylryan Could you try reproduction steps and open another issue if you find? I tried reopening my scene but I get no crash.

darrylryan commented 6 years ago

@Zylann It seems to happen whenever I load a scene that contains a terrain. If I delete the terrain from the scene file by hand it works again. Also, it crashes whenever I try to start the game with a windows "not responding" error - might be a mono issue there I think because I am using mono.

Zylann commented 6 years ago

@darrylryan I cannot reproduce this by just loading a scene (I'm not using mono though). Is it crashing anytime, even on "fixed" scenes?

darrylryan commented 6 years ago

@Zylann I just built the latest master source from godot + hterrain with mono enabled, created a new heightmap with new heightmap data and new shader, added a camera and hit play. It crashes with "Godot Engine Editor has stopped working" and nothing in the output console. I guess its probably due to the mono bindings or something, but without a useful error message its hard to know for sure.

Zylann commented 6 years ago

@darrylryan remember you have to save the HeightMapData to a .heightmap file, any other kind of save don't work (see https://github.com/Zylann/godot_heightmap_module/issues/6)

darrylryan commented 6 years ago

@Zylann Yay, that was the issue! image

I guess all thats missing to stop it being usable now is the collision

Zylann commented 6 years ago

@darrylryan feel free to try using HeightMapShape, it was recently added with Bullet, but nobody tested it yet (including me)

darrylryan commented 6 years ago

@Zylann doesnt seem to be implemented yet https://github.com/godotengine/godot/blob/master/scene/3d/collision_shape.cpp#L39

Zylann commented 6 years ago

@darrylryan the comment might be wrong, I saw HeightMapShape mentioned in the first Bullet PR https://github.com/godotengine/godot/pull/10013 However it's only available through PhysicsServer.

darrylryan commented 6 years ago

@Zylann There doesn't seem to be a class for it in the collision shapes though - if there's another way to add it directly I don't know how to do that 👶

Zylann commented 6 years ago

@darrylryan there is no resource class but the feature exists in the PhysicsServer API, nobody wrote a convenience wrapper around it: https://github.com/godotengine/godot/blob/master/servers/physics_server.h#L230 It should be accessible to GDScript as well, but you need to learn about how to use low level servers directly ;)

darrylryan commented 6 years ago

@Zylann Well I have a terrain in the game now

image

Works fine as long as you don't try to walk on it :)

I found the built in splat map texture would only let me paint in green at the moment so I had to use a custom splat map texture, but then of course it didn't match the heightmap, so I had to use a custom heightmap texture... and of course then the custom AABB and height picking won't work. Oh well, getting there 💃

Zylann commented 6 years ago

@darrylryan the splat texture is not what you think it is, the real meaning is:

R = ID of the texture to use (so you can have up to 256 different texture slots, which you can already select in the UI on bottom left) G = Weight of that texture (which is why you get green if you output it as a color) B and A are not used (and in fact dont exist in memory^^)

Problem is, that splat texture is hard to use at the moment because it needs support for texture arrays, which may be added in Godot 3.1. In the meantime I test it using an emulation with many if blocks, but I didnt submit that in the default shader because it's awful xD

If you want to use a color-based splatmap (with only 4 possible textures then), you can use the Color texture instead which is paintable in color mode using the color picker ;)

Also if your custom texture size doesn't match the heightmap size, just use a different divisor to stretch it to the correct size, you don't need to change the height texture for that.

I should really write a wiki about how these textures work tbh.

darrylryan commented 6 years ago

@Zylann If you use R for texture ID and G for weight, how can you blend 2 different materials? That way each pixel can only have 1 texture, you can't layer them.

Zylann commented 6 years ago

@darrylryan you can blend them in the shader, I've seen this technique used in Lumix Engine (which I'm working on before committing it to the default shader), and also in The Witcher 3 (within a more complex system). The reason why I chose this is that it allows a very large amount of textures to be used. I may add some optional use to B and A (B=ID2, B=weight2) for having an overlay on top of the first one, for snow or sand for example. But again, if you want to use a different splatting technique feel free to exploit other textures. The system is rough and fixed at the moment but I aim to let users customize the way textures are used if needed.