Team Ai
Apppublic

OpenMotionLab/MotionGPT

sourceHugging Facemitupdated 1y agoView on Hugging Face
118likes
texture.py260 linesDownload Raw Back to pyrender
1"""Textures, conforming to the glTF 2.0 standards as specified in2https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-texture3 4Author: Matthew Matl5"""6import numpy as np7 8from OpenGL.GL import *9 10from .utils import format_texture_source11from .sampler import Sampler12 13 14class Texture(object):15    """A texture and its sampler.16 17    Parameters18    ----------19    name : str, optional20        The user-defined name of this object.21    sampler : :class:`Sampler`22        The sampler used by this texture.23    source : (h,w,c) uint8 or (h,w,c) float or :class:`PIL.Image.Image`24        The image used by this texture. If None, the texture is created25        empty and width and height must be specified.26    source_channels : str27        Either `D`, `R`, `RG`, `GB`, `RGB`, or `RGBA`. Indicates the28        channels to extract from `source`. Any missing channels will be filled29        with `1.0`.30    width : int, optional31        For empty textures, the width of the texture buffer.32    height : int, optional33        For empty textures, the height of the texture buffer.34    tex_type : int35        Either GL_TEXTURE_2D or GL_TEXTURE_CUBE.36    data_format : int37        For now, just GL_FLOAT.38    """39 40    def __init__(self,41                 name=None,42                 sampler=None,43                 source=None,44                 source_channels=None,45                 width=None,46                 height=None,47                 tex_type=GL_TEXTURE_2D,48                 data_format=GL_UNSIGNED_BYTE):49        self.source_channels = source_channels50        self.name = name51        self.sampler = sampler52        self.source = source53        self.width = width54        self.height = height55        self.tex_type = tex_type56        self.data_format = data_format57 58        self._texid = None59        self._is_transparent = False60 61    @property62    def name(self):63        """str : The user-defined name of this object.64        """65        return self._name66 67    @name.setter68    def name(self, value):69        if value is not None:70            value = str(value)71        self._name = value72 73    @property74    def sampler(self):75        """:class:`Sampler` : The sampler used by this texture.76        """77        return self._sampler78 79    @sampler.setter80    def sampler(self, value):81        if value is None:82            value = Sampler()83        self._sampler = value84 85    @property86    def source(self):87        """(h,w,c) uint8 or float or :class:`PIL.Image.Image` : The image88        used in this texture.89        """90        return self._source91 92    @source.setter93    def source(self, value):94        if value is None:95            self._source = None96        else:97            self._source = format_texture_source(value, self.source_channels)98        self._is_transparent = False99 100    @property101    def source_channels(self):102        """str : The channels that were extracted from the original source.103        """104        return self._source_channels105 106    @source_channels.setter107    def source_channels(self, value):108        self._source_channels = value109 110    @property111    def width(self):112        """int : The width of the texture buffer.113        """114        return self._width115 116    @width.setter117    def width(self, value):118        self._width = value119 120    @property121    def height(self):122        """int : The height of the texture buffer.123        """124        return self._height125 126    @height.setter127    def height(self, value):128        self._height = value129 130    @property131    def tex_type(self):132        """int : The type of the texture.133        """134        return self._tex_type135 136    @tex_type.setter137    def tex_type(self, value):138        self._tex_type = value139 140    @property141    def data_format(self):142        """int : The format of the texture data.143        """144        return self._data_format145 146    @data_format.setter147    def data_format(self, value):148        self._data_format = value149 150    def is_transparent(self, cutoff=1.0):151        """bool : If True, the texture is partially transparent.152        """153        if self._is_transparent is None:154            self._is_transparent = False155            if self.source_channels == 'RGBA' and self.source is not None:156                if np.any(self.source[:,:,3] < cutoff):157                    self._is_transparent = True158        return self._is_transparent159 160    def delete(self):161        """Remove this texture from the OpenGL context.162        """163        self._unbind()164        self._remove_from_context()165 166    ##################167    # OpenGL code168    ##################169    def _add_to_context(self):170        if self._texid is not None:171            raise ValueError('Texture already loaded into OpenGL context')172 173        fmt = GL_DEPTH_COMPONENT174        if self.source_channels == 'R':175            fmt = GL_RED176        elif self.source_channels == 'RG' or self.source_channels == 'GB':177            fmt = GL_RG178        elif self.source_channels == 'RGB':179            fmt = GL_RGB180        elif self.source_channels == 'RGBA':181            fmt = GL_RGBA182 183        # Generate the OpenGL texture184        self._texid = glGenTextures(1)185        glBindTexture(self.tex_type, self._texid)186 187        # Flip data for OpenGL buffer188        data = None189        width = self.width190        height = self.height191        if self.source is not None:192            data = np.ascontiguousarray(np.flip(self.source, axis=0).flatten())193            width = self.source.shape[1]194            height = self.source.shape[0]195 196        # Bind texture and generate mipmaps197        glTexImage2D(198            self.tex_type, 0, fmt, width, height, 0, fmt,199            self.data_format, data200        )201        if self.source is not None:202            glGenerateMipmap(self.tex_type)203 204        if self.sampler.magFilter is not None:205            glTexParameteri(206                self.tex_type, GL_TEXTURE_MAG_FILTER, self.sampler.magFilter207            )208        else:209            if self.source is not None:210                glTexParameteri(self.tex_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR)211            else:212                glTexParameteri(self.tex_type, GL_TEXTURE_MAG_FILTER, GL_NEAREST)213        if self.sampler.minFilter is not None:214            glTexParameteri(215                self.tex_type, GL_TEXTURE_MIN_FILTER, self.sampler.minFilter216            )217        else:218            if self.source is not None:219                glTexParameteri(self.tex_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)220            else:221                glTexParameteri(self.tex_type, GL_TEXTURE_MIN_FILTER, GL_NEAREST)222 223        glTexParameteri(self.tex_type, GL_TEXTURE_WRAP_S, self.sampler.wrapS)224        glTexParameteri(self.tex_type, GL_TEXTURE_WRAP_T, self.sampler.wrapT)225        border_color = 255 * np.ones(4).astype(np.uint8)226        if self.data_format == GL_FLOAT:227            border_color = np.ones(4).astype(np.float32)228        glTexParameterfv(229            self.tex_type, GL_TEXTURE_BORDER_COLOR,230            border_color231        )232 233        # Unbind texture234        glBindTexture(self.tex_type, 0)235 236    def _remove_from_context(self):237        if self._texid is not None:238            # TODO OPENGL BUG?239            # glDeleteTextures(1, [self._texid])240            glDeleteTextures([self._texid])241            self._texid = None242 243    def _in_context(self):244        return self._texid is not None245 246    def _bind(self):247        # TODO HANDLE INDEXING INTO OTHER UV's248        glBindTexture(self.tex_type, self._texid)249 250    def _unbind(self):251        glBindTexture(self.tex_type, 0)252 253    def _bind_as_depth_attachment(self):254        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,255                               self.tex_type, self._texid, 0)256 257    def _bind_as_color_attachment(self):258        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,259                               self.tex_type, self._texid, 0)260