Skip to content

Bug withTexture2DConverter #238

Open

Description

@AXiX-official

Code

if __name__ == "__main__":
    filename = "22"
    env = UnityPy.load(f"assetbundles/{filename}")
    for obj in env.objects:
        if obj.type.name == "Texture2D":
            data = obj.read()
            # data.image.save(f"workspace/mod/{filename}.png")
            img = Image.open(f"workspace/mod/{filename}.png")
            data.set_image(img)
            data.save()
            break
    with open(f"workspace/mod/{filename}u", "wb") as f:
        f.write(env.file.save(packer="none"))

Error
No error message.

Bug
When I work with a series of textures in ETC2_RGBA8 format, 192*256 size, the texture in the modified file becomes blurry, however, there is no problem for other textures that are also in ETC2_RGBA8 format, but in different sizes.

To Reproduce

  • a copy of the file that causes the problem
  • following data:
    • Python version 3.8.10
    • UnityPy version 1.10.7

Activity

  1. K0lb3 commented on Aug 30, 2024

    @K0lb3
    Owner

    That sounds like it might be related to compression?
    Do you recompress the textures / assign to .image?

  2. self-assigned this
    on Aug 30, 2024
  3. AXiX-official commented on Aug 31, 2024

    @AXiX-official
    ContributorAuthor

    Does assign to .image mean something like this

    for obj in env.objects:
        if obj.type.name == “Texture2D”:
            data = obj.read()
            img = data.image
    img.save("test.png")

    Yes, the image I used above was saved to png like this
    It actually calls Texture2DConverter.image_to_texture2d and Texture2DConverter.get_image_from_texture2d

    I've also tried using ectpak directly.

    from PIL import Image
    from UnityPy.export import Texture2DConverter
    from UnityPy.enums import TextureFormat
    import etcpak
    
    img = Image.open("jialimaoxian_2_rw.png")
    
    r, g, b, a = img.split()
    raw_img = Image.merge("RGBA", (b, g, r, a)).tobytes()
    enc_img = etcpak.compress_to_etc2_rgba(raw_img, img.width, img.height)
    tex_format = TextureFormat.ETC2_RGBA8
    tex = texture_2d(enc_img, tex_format, img.width, img.height)
    new_tex = Texture2DConverter.get_image_from_texture2d(tex)
    new_tex = new_tex.transpose(Image.FLIP_TOP_BOTTOM)
    new_tex.save("new_test.png")

    Also experiencing apparent secondary compression, I'm not sure if it's a parameter issue because I didn't find the relevant parameter
    I'm guessing this might be a problem with ectpak, but I'm not sure if etcpak 2.0 is less so

    I'm using TexToolWrap.dll from UABEA as a temporary handler, for ETC2_RGBA8 UABEA uses PVRTexLib

    import ctypes
    from ctypes import c_uint, c_int, c_void_p
    
    dll = ctypes.CDLL(r"F:\Rider\UABEA\TexToolWrap\bin\x64\Release\TexToolWrap.dll")
    
    dll.DecodeByPVRTexLib.argtypes = [c_void_p, c_void_p, c_int, c_uint, c_uint]
    dll.DecodeByPVRTexLib.restype = c_uint
    
    dll.EncodeByPVRTexLib.argtypes = [c_void_p, c_void_p, c_int, c_int, c_uint, c_uint]
    dll.EncodeByPVRTexLib.restype = c_uint
    
    def DecodePVRTexLib(data, width, height, format) -> np.ndarray:
        data = (ctypes.c_ubyte * len(data)).from_buffer_copy(data)
        width = c_uint(width)
        height = c_uint(height)
        format = c_int(format)
        size = width.value * height.value * 4
        out = (ctypes.c_ubyte * size)()
        dll.DecodeByPVRTexLib(data, out, format, width, height)
        return np.frombuffer(out, dtype=np.uint8).reshape((height.value, width.value, 4))
    
    def RGBAToFormatByteSize(format, width, height) -> int:
        if format == 4 or format == 5:
            return int(width) * int(height) * 4
        elif format == 47:
            blockCountX = (width + 3) / 4
            blockCountY = (height + 3) / 4
            return int(blockCountX) * int(blockCountY) * 16
        else:
            raise Exception("Texture format is not correct")
        
    
    def EncodeByPVRTexLib(data, mode, level, width, height) -> bytes:
        data = (ctypes.c_ubyte * len(data)).from_buffer_copy(data)
        buf = (ctypes.c_ubyte * RGBAToFormatByteSize(mode, width, height))()
        mode = c_int(mode)
        level = c_int(level)
        width = c_uint(width)
        height = c_uint(height)
        size = dll.EncodeByPVRTexLib(data, buf, mode, level, width, height)
        if size == len(buf):
            return bytes(buf)
        else:
            raise Exception("Encode failed")

    This treatment does not encounter the aforementioned problem of secondary compression
    But PVRTexLib is not open source, and although he provides a Python package it only seems to support x64 and I wasn't able to run it correctly.

  4. K0lb3 commented on Sep 1, 2024

    @K0lb3
    Owner

    Thanks for the more detailed explanation.

    Looks like it's an issue with etcpak considering your explanation.
    etcpak 2 likely won't fix the issue, I'm with you on that.

    I guess the only real good overall open source solution might be basis_universal which is a bit of a pain to wrap, but I guess that I can attempt it again, as I gained quite some additional experience with it in between now and the last time I tried to make a wrapper for it.

  5. added and removed
    bugSomething isn't working
    on Sep 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions