0 votes

Hi Guys

In Godot 4, I'm trying to build a mesh from a heightmap. Using the code below, I trying to parse the image, which is a noise image.

I keep getting the error 'Nonexistent function 'lock()' in base Image.
When I go var heightmap = noiseImage.get_data() instead, i get the same error, only it reads: Nonexistent function lock() in base PackedByteArray. What am I doing wrong?

func _ready():
    var noiseImage = Image.new()
    noiseImage.load("res://231.jpg")
    width = noiseImage.get_width()
    height = noiseImage.get_height()
    var heightmap = noiseImage
    heightmap.lock()
    for x in range(width):
        for y in range(height):
            heightData[Vector2(x,y)] = heightmap.get_pixel(x,y).r*20
    heightmap.unlock()
Godot version 4.0
in Engine by (478 points)

The lock/unlock methods have been removed in Godot 4.0. Is there any issue if you just remove them?

Weird, they're still in the docs.

Anyway, removed them and the code runs through but no geometry gets created.

Also, I can see an error in debug at the line which commits the mesh, the error reads: E _ready: Required virtual method Mesh::_get_surface_count must be overridden before calling.

I'm using this code I found online, which makes sense and 'should work' when you read it:

extends Node3D

@onready var width;
@onready var height;

var heightData = {}

var vertices = PackedVector3Array()
var UVs = PackedVector2Array()
var normals = PackedVector3Array()

var tmpMesh = Mesh.new()

func _ready():
    var noiseImage = load("res://231.jpg")
    width = noiseImage.get_width()
    height = noiseImage.get_height()
    var heightmap = noiseImage

    for x in range(0,width):
        for y in range(0,height):
            heightData[Vector2(x,y)] = heightmap.get_pixel(x,y).r*20

    # generate terrain
    for x in range(0,width-1):
        for y in range(0,height-1):
            createQuad(x,y)

    var st = SurfaceTool.new()
    st.begin(Mesh.PRIMITIVE_TRIANGLES)
    st.set_material(load("res://new_standard_material_3d.tres"))

    for v in vertices.size():
        st.set_color(Color(1,1,1))
        st.set_uv(UVs[v])
        st.set_normal(normals[v])
        st.add_vertex(vertices[v])

    st.commit(tmpMesh)
    $MeshInstance3D.mesh = tmpMesh


func createQuad(x,y):
    var vert1 # vertex positions (Vector2)
    var vert2
    var vert3   
    var side1 # sides of each triangle (Vector3)
    var side2   
    var normal # normal for each triangle (Vector3)

    # triangle 1
    vert1 = Vector3(x,heightData[Vector2(x,y)],-y)
    vert2 = Vector3(x,heightData[Vector2(x,y+1)],-y-1)
    vert3 = Vector3(x+1,heightData[Vector2(x+1,y+1)],-y-1)
    vertices.push_back(vert1)
    vertices.push_back(vert2)
    vertices.push_back(vert3)

    UVs.push_back(Vector2(vert1.x/10, -vert1.z/10))
    UVs.push_back(Vector2(vert2.x/10, -vert2.z/10))
    UVs.push_back(Vector2(vert3.x/10, -vert3.z/10))

    side1 = vert2-vert1
    side2 = vert2-vert3
    normal = side1.cross(side2)

    for i in range(0,3):
        normals.push_back(normal)

    # triangle 2
    vert1 = Vector3(x,heightData[Vector2(x,y)],-y)
    vert2 = Vector3(x+1,heightData[Vector2(x+1,y+1)],-y-1)
    vert3 = Vector3(x+1,heightData[Vector2(x+1,y)],-y)
    vertices.push_back(vert1)
    vertices.push_back(vert2)
    vertices.push_back(vert3)

    UVs.push_back(Vector2(vert1.x/10, -vert1.z/10))
    UVs.push_back(Vector2(vert2.x/10, -vert2.z/10))
    UVs.push_back(Vector2(vert3.x/10, -vert3.z/10))

    side1 = vert2-vert1
    side2 = vert2-vert3
    normal = side1.cross(side2)

    for i in range(0,3):
        normals.push_back(normal)

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.