Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terrain3DStorage: Add get_normal() utility function #246

Merged
merged 1 commit into from
Nov 20, 2023

Conversation

lw64
Copy link
Contributor

@lw64 lw64 commented Nov 12, 2023

Fixes #142

src/terrain_3d_storage.cpp Outdated Show resolved Hide resolved
@lw64 lw64 force-pushed the normal branch 4 times, most recently from 9b7d4da to a7dc731 Compare November 19, 2023 01:40
real_t left = get_height(p_global_position + Vector3(-_region_size, 0.0f, 0.0f));
real_t right = get_height(p_global_position + Vector3(_region_size, 0.0f, 0.0f));
real_t back = get_height(p_global_position + Vector3(0.0f, 0.0f, -_region_size));
real_t front = get_height(p_global_position + Vector3(0.0f, 0.0f, _region_size));
Copy link
Owner

@TokisanGames TokisanGames Nov 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original formula from the shader added _region_pixel_size to UV. The value of that is 1/1024. Here, replace _region_size with 1.0f/_region_size.

Also you can remove the tangent and binormal options, and consolidate get_normal_simple into this function. Thanks for the idea for two options, but it's not necessary.

Copy link
Owner

@TokisanGames TokisanGames Nov 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the note above. We need make sure the offset for get_height is big enough so that it moves to the next pixel in the map image. 1/region_size should do it as it's the same size as in the shader, and region_size will change in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way it still didnt work as expected. I experimented a bit and came with something else, but I am not sure at all if its correct.

@TokisanGames
Copy link
Owner

TokisanGames commented Nov 20, 2023

I looked closer at the shader and this is how it's calculated:

get_height(uv + vec2(_region_texel_size, 0));

get_height((vertex.xz + 0.5)/1024 + vec2(1/1024, 0));

That get_height is using 0-1 UV coordinates. Our C++ get_height uses full range values, so if we multiply the above by 1024 we get vertex.xz + 0.5 + vec2(1, 0). However the 0.5 is a texel offset specifically for the shader because of the weird way glsl works, and makes no difference here (I tested it to confirm). So we have this:

	real_t left = get_height(p_global_position + Vector3(-1.0f, 0.0f, 0.0f));
	real_t right = get_height(p_global_position + Vector3(1.0f, 0.0f, 0.0f));
	real_t back = get_height(p_global_position + Vector3(0.f, 0.f, -1.0f));
	real_t front = get_height(p_global_position + Vector3(0.f, 0.f, 1.0f));

I then tested this by adding an MMI to DemoScene._ready()

	var count: int = 1024
	var mmi := MultiMeshInstance3D.new()
	mmi.multimesh = MultiMesh.new()
	mmi.multimesh.transform_format = MultiMesh.TRANSFORM_3D
	mmi.multimesh.instance_count = count*count
	mmi.multimesh.mesh = PrismMesh.new()
	mmi.multimesh.mesh.size = Vector3(.25, 1, .25)
	add_child(mmi)
	
	for x in count:
		for z in count:
			var xform := Transform3D()
			#xform.origin = Vector3(x, 0, z) * $Terrain3D.get_mesh_vertex_spacing()
			xform.origin = Vector3(x, 0, z)
			var normal: Vector3 = $Terrain3D.storage.get_normal(xform.origin)
			if is_nan(normal.x):
				normal = Vector3.UP
			normal = normal.normalized()
			xform.basis.y = normal
			xform.basis.x = -xform.basis.z.cross(normal)
			xform.basis = xform.basis.orthonormalized()
			var height: float = $Terrain3D.storage.get_height(xform.origin) 
			if is_nan(height):
				xform.origin.y = -100
			else:
				xform.origin.y = height
				xform.origin += normal * .5
			mmi.multimesh.set_instance_transform(z*count + x, xform)
                

It looks pretty good.

image

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add some utility functions
2 participants