Godot 城市模拟 – 008 为建筑物添加贴图
本文最后更新于11 天前

效果预览

下图展示了使用自定义材质创建的3D建筑物效果,墙面纹理清晰可见,建筑物结构完整:

file

贴图资源获取

  1. 访问 ​​AmbientCG​​ 纹理资源网站:
    网站:https://ambientcg.com/list?q=building&sort=popular

  2. 在搜索栏输入”building”筛选建筑类纹理:

    file

  3. 选择一个喜欢的下载
    下载后放在 res://assets/texttures/ 文件夹中

    file

制作材质

新建材质

res://assets/materials/ 文件夹右键 新建资源

file

file

选择 standard_material_3d 创建

添加贴图

双击 res://assets/materials/building_standard_material_3d.tres 打开材质属性,把贴图拖动到 Texture 属性上

file

修改创建建筑物的方法

侧面设置贴图参数

# 创建侧面(连接底部和顶部的四边形面)
    for i in range(point_count):
        var next_i = (i + 1) % point_count  # 下一个点的索引(循环)

        # 侧面四边形分解为两个三角形
        # 第一个三角形
        surface_tool.set_uv(Vector2(0, 0))
        surface_tool.add_vertex(prism_points[i])

        surface_tool.set_uv(Vector2(1, 0))
        surface_tool.add_vertex(prism_points[next_i])

        surface_tool.set_uv(Vector2(0, 1))
        surface_tool.add_vertex(prism_points[point_count + i])

        # 第二个三角形
        surface_tool.set_uv(Vector2(1, 0))
        surface_tool.add_vertex(prism_points[next_i])

        surface_tool.set_uv(Vector2(1, 1))
        surface_tool.add_vertex(prism_points[point_count + next_i])

        surface_tool.set_uv(Vector2(0, 1))
        surface_tool.add_vertex(prism_points[point_count + i])

修复原来的bug

原来创建建筑物的方法存在的问题是,建筑物有内凹部分时,上下底面会有多于的三角形面被创建。

   # 使用Godot内置的三角剖分算法
    var triangles = Geometry2D.triangulate_polygon(points_2d)
    if triangles.size() == 0:
        print("错误:无法对多边形进行三角剖分")
        return null

完整代码


static func create_building_from_base_and_height(base_points: Array, height: float, material: StandardMaterial3D) -> MeshInstance3D:
    # 验证输入
    if base_points.size() < 3:
        print("错误:至少需要3个点来构成多边形")
        return null

    # 将3D点投影到2D平面进行三角剖分
    var points_2d = []
    for point in base_points:
        points_2d.append(Vector2(point.x, point.z))

    # 使用Godot内置的三角剖分算法
    var triangles = Geometry2D.triangulate_polygon(points_2d)
    if triangles.size() == 0:
        print("错误:无法对多边形进行三角剖分")
        return null

    var point_count = base_points.size()

    # 计算建筑物尺寸用于UV缩放
    var min_point = base_points[0]
    var max_point = base_points[0]
    for point in base_points:
        min_point = min_point.min(point)
        max_point = max_point.max(point)
    var building_size = max_point - min_point
    material.uv1_scale = Vector3(building_size.x / 10, building_size.y / 10, building_size.z / 10)

    # 计算棱柱体的所有顶点
    var prism_points = []

    # 底部点(底面多边形)
    for i in range(point_count):
        prism_points.append(base_points[i])

    # 顶部点(底面多边形加上高度)
    for i in range(point_count):
        var top_point = base_points[i] + Vector3(0, height, 0)
        prism_points.append(top_point)

    # 使用SurfaceTool创建棱柱体
    var surface_tool = SurfaceTool.new()
    surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES)

    # 创建底面(使用三角剖分结果)
    for i in range(0, triangles.size(), 3):
        var index1 = triangles[i]
        var index2 = triangles[i + 1]
        var index3 = triangles[i + 2]

        surface_tool.set_uv(Vector2.ZERO)
        surface_tool.add_vertex(prism_points[index1])

        surface_tool.set_uv(Vector2.ZERO)
        surface_tool.add_vertex(prism_points[index2])

        surface_tool.set_uv(Vector2.ZERO)
        surface_tool.add_vertex(prism_points[index3])

    # 创建顶面(使用相同的三角剖分)
    for i in range(0, triangles.size(), 3):
        var index1 = triangles[i] + point_count
        var index2 = triangles[i + 1] + point_count
        var index3 = triangles[i + 2] + point_count

        surface_tool.set_uv(Vector2.ZERO)
        surface_tool.add_vertex(prism_points[index1])

        surface_tool.set_uv(Vector2.ZERO)
        surface_tool.add_vertex(prism_points[index2])

        surface_tool.set_uv(Vector2.ZERO)
        surface_tool.add_vertex(prism_points[index3])

    # 创建侧面(连接底部和顶部的四边形面)
    for i in range(point_count):
        var next_i = (i + 1) % point_count  # 下一个点的索引(循环)

        # 侧面四边形分解为两个三角形
        # 第一个三角形
        surface_tool.set_uv(Vector2(0, 0))
        surface_tool.add_vertex(prism_points[i])

        surface_tool.set_uv(Vector2(1, 0))
        surface_tool.add_vertex(prism_points[next_i])

        surface_tool.set_uv(Vector2(0, 1))
        surface_tool.add_vertex(prism_points[point_count + i])

        # 第二个三角形
        surface_tool.set_uv(Vector2(1, 0))
        surface_tool.add_vertex(prism_points[next_i])

        surface_tool.set_uv(Vector2(1, 1))
        surface_tool.add_vertex(prism_points[point_count + next_i])

        surface_tool.set_uv(Vector2(0, 1))
        surface_tool.add_vertex(prism_points[point_count + i])

    # 生成法线(确保法线方向正确)
    surface_tool.generate_normals()

    # 生成网格
    var array_mesh = surface_tool.commit()

    # 创建节点和材质
    var prism_mesh_instance = MeshInstance3D.new()
    prism_mesh_instance.mesh = array_mesh

    material.cull_mode = BaseMaterial3D.CULL_DISABLED  # 禁用背面剔除
    material.albedo_color = Color(0.9,0.9,0.9)
    material.uv1_scale = Vector3(2,1,2)

    # 正确应用材质
    prism_mesh_instance.material_override = material

    print("基于不规则多边形底面创建棱柱体完成!点数:", point_count)
    return prism_mesh_instance

修改 res://scripts/environment.gd 中创建建筑物方法

材质加载方法


var material : StandardMaterial3D = load("res://assets/materials/building_standard_material_3d.tres")

func create_buildings():
    var material = load("res://assets/materials/building_standard_material_3d.tres")

    for way in ways:
        # 检查是否为建筑物
        if way.tags.get("building") and way.node_ids.size() > 2:
            # 确保路径是闭合的
            if way.node_ids[0] != way.node_ids[-1]:
                continue

            # 获取建筑物高度
            var height = 5.0
            if way.tags.get("height"):
                height = float(way.tags.height)
            elif way.tags.get("building:levels"):
                height = float(way.tags["building:levels"]) * 3.0

            # 收集建筑物顶点
            var base_points = []
            for i in range(way.node_ids.size() - 1):
                var node_id = way.node_ids[i]
                var node = nodes.get(str(node_id))
                if node:
                    var point = functions.latlon_to_vector3(node.lat, node.lon)
                    point.y += 0.1  # 增加抬高量
                    base_points.append(point)

            if base_points.size() < 3:
                continue

            var building = functions.create_building_from_base_and_height(base_points,height,material)

            add_child(building)


扫码关注,及时关注技术动态


暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇