def __enter__(self): """Loads the image data using OpenGL""" # Set image active in OpenGL ownit = self._blimg.bindcode[0] == 0 if ownit: if self._blimg.gl_load() != 0: raise RuntimeError("failed to load image") previous_texture = self._get_integer(bgl.GL_TEXTURE_BINDING_2D) changed_state = (previous_texture != self._blimg.bindcode[0]) if changed_state: bgl.glBindTexture(bgl.GL_TEXTURE_2D, self._blimg.bindcode[0]) # Grab the image data self._width = self._get_tex_param(bgl.GL_TEXTURE_WIDTH, 0) self._height = self._get_tex_param(bgl.GL_TEXTURE_HEIGHT, 0) size = self._width * self._height * 4 buf = bgl.Buffer(bgl.GL_BYTE, size) fmt = bgl.GL_BGRA if self._bgra else bgl.GL_RGBA bgl.glGetTexImage(bgl.GL_TEXTURE_2D, 0, fmt, bgl.GL_UNSIGNED_BYTE, buf) # OpenGL returns the images upside down, so we're going to rotate it in memory. # ... But only if requested... :) if self._image_inverted: self._image_data = bytes(buf) else: self._image_data = self._invert_image(self._width, self._height, buf) # Restore previous OpenGL state if changed_state: bgl.glBindTexture(bgl.GL_TEXTURE_2D, previous_texture) if ownit: self._blimg.gl_free() return self
def get_all_mipmaps(image, mm_offset=0): import bgl images = [] image.gl_load() image_id = image.bindcode[0] if image_id == 0: return images level = mm_offset # denetii - change this to shift the largest exported size down bgl.glBindTexture(bgl.GL_TEXTURE_2D, image_id) while level < 16: # LOG.debug('') buf = bgl.Buffer(bgl.GL_INT, 1) bgl.glGetTexLevelParameteriv(bgl.GL_TEXTURE_2D, level, bgl.GL_TEXTURE_WIDTH, buf) width = buf[0] # LOG.debug(width) if width < 8: break bgl.glGetTexLevelParameteriv(bgl.GL_TEXTURE_2D, level, bgl.GL_TEXTURE_HEIGHT, buf) height = buf[0] if height < 8: break del buf buf_size = width * height * 4 # LOG.debug(buf_size) buf = bgl.Buffer(bgl.GL_BYTE, buf_size) bgl.glGetTexImage(bgl.GL_TEXTURE_2D, level, bgl.GL_RGBA, bgl.GL_UNSIGNED_BYTE, buf) images.append((width, height, buf)) if level == 0: pass # LOG.debug(images[0][:16]) # del buf level += 1 return images
def get_level_data(self, level=0, calc_alpha=False, bgra=False, quiet=False, fast=False): """Gets the uncompressed pixel data for a requested mip level, optionally calculating the alpha channel from the image color data """ width = self._get_tex_param(bgl.GL_TEXTURE_WIDTH, level) height = self._get_tex_param(bgl.GL_TEXTURE_HEIGHT, level) if not quiet: print(" Level #{}: {}x{}".format(level, width, height)) # Grab the image data size = width * height * 4 buf = bgl.Buffer(bgl.GL_BYTE, size) fmt = bgl.GL_BGRA if bgra else bgl.GL_RGBA bgl.glGetTexImage(bgl.GL_TEXTURE_2D, level, fmt, bgl.GL_UNSIGNED_BYTE, buf); if fast: return bytes(buf) # OpenGL returns the images upside down, so we're going to rotate it in memory. finalBuf = bytearray(size) row_stride = width * 4 for i in range(height): src, dst = i * row_stride, (height - (i+1)) * row_stride finalBuf[dst:dst+row_stride] = buf[src:src+row_stride] # Do we need to calculate the alpha component? if calc_alpha: for i in range(0, size, 4): finalBuf[i+3] = int(sum(finalBuf[i:i+3]) / 3) return bytes(finalBuf)
def get_image_buffer(path): img = load_image(path) if not img: return None sx, sy = img.size buf = bgl.Buffer(bgl.GL_FLOAT, 4 * sx * sy) img.gl_load(filter=bgl.GL_LINEAR, mag=bgl.GL_LINEAR) bgl.glBindTexture(bgl.GL_TEXTURE_2D, img.bindcode[0]) bgl.glGetTexImage(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA, bgl.GL_FLOAT, buf) img.gl_free() img.user_clear() bpy.data.images.remove(img) return buf, sx, sy
def get_level_data(self, level=0, calc_alpha=False, bgra=False, report=None, fast=False): """Gets the uncompressed pixel data for a requested mip level, optionally calculating the alpha channel from the image color data """ width = self._get_tex_param(bgl.GL_TEXTURE_WIDTH, level) height = self._get_tex_param(bgl.GL_TEXTURE_HEIGHT, level) if report is not None: report.msg("Level #{}: {}x{}", level, width, height, indent=2) # Grab the image data size = width * height * 4 buf = bgl.Buffer(bgl.GL_BYTE, size) fmt = bgl.GL_BGRA if bgra else bgl.GL_RGBA bgl.glGetTexImage(bgl.GL_TEXTURE_2D, level, fmt, bgl.GL_UNSIGNED_BYTE, buf) if fast: return bytes(buf) # OpenGL returns the images upside down, so we're going to rotate it in memory. finalBuf = bytearray(size) row_stride = width * 4 for i in range(height): src, dst = i * row_stride, (height - (i + 1)) * row_stride finalBuf[dst:dst + row_stride] = buf[src:src + row_stride] # If this is a detail map, then we need to bake that per-level here. if self._texkey.is_detail_map: detail_blend = self._texkey.detail_blend if detail_blend == TEX_DETAIL_ALPHA: self._make_detail_map_alpha(finalBuf, level) elif detail_blend == TEX_DETAIL_ADD: self._make_detail_map_alpha(finalBuf, level) elif detail_blend == TEX_DETAIL_MULTIPLY: self._make_detail_map_mult(finalBuf, level) # Do we need to calculate the alpha component? if calc_alpha: for i in range(0, size, 4): finalBuf[i + 3] = int(sum(finalBuf[i:i + 3]) / 3) return bytes(finalBuf)
def get_level_data(self, level=0, calc_alpha=False, bgra=False, quiet=False): """Gets the uncompressed pixel data for a requested mip level, optionally calculating the alpha channel from the image color data """ width = self._get_tex_param(bgl.GL_TEXTURE_WIDTH, level) height = self._get_tex_param(bgl.GL_TEXTURE_HEIGHT, level) if not quiet: print(" Level #{}: {}x{}".format(level, width, height)) # Grab the image data size = width * height * 4 buf = bgl.Buffer(bgl.GL_BYTE, size) fmt = bgl.GL_BGRA if bgra else bgl.GL_RGBA bgl.glGetTexImage(bgl.GL_TEXTURE_2D, level, fmt, bgl.GL_UNSIGNED_BYTE, buf); # Calculate le alphas # NOTE: the variable names are correct for GL_RGBA. We'll still get the right values for # BGRA, obviously, but red will suddenly be... blue. Yeah. if calc_alpha: for i in range(0, size, 4): r, g, b = buf[i:i+3] buf[i+3] = int((r + g + b) / 3) return bytes(buf)
def cubemap_to_equirectangular(self, imageList, outputName): # Define the vertex shader vertex_shader = ''' in vec3 aVertexPosition; in vec2 aVertexTextureCoord; out vec2 vTexCoord; void main() { vTexCoord = aVertexTextureCoord; gl_Position = vec4(aVertexPosition, 1); } ''' # Generate the OpenGL shader pos = [ (-1.0, -1.0, -1.0), # left, bottom, back (-1.0, 1.0, -1.0), # left, top, back (1.0, -1.0, -1.0), # right, bottom, back (1.0, 1.0, -1.0) ] # right, top, back coords = [ (-1.0, -1.0), # left, bottom (-1.0, 1.0), # left, top (1.0, -1.0), # right, bottom (1.0, 1.0) ] # right, top vertexIndices = [(0, 3, 1), (3, 0, 2)] shader = gpu.types.GPUShader(vertex_shader, self.frag_shader) batch = batch_for_shader(shader, 'TRIS', {"aVertexPosition": pos,\ "aVertexTextureCoord": coords},\ indices=vertexIndices) # Change the color space of all of the images to Linear # and load them into OpenGL textures for image in imageList: image.colorspace_settings.name = 'Linear' image.gl_load() # set the size of the final image width = self.image_size[0] height = self.image_size[1] # Create an offscreen render buffer and texture offscreen = gpu.types.GPUOffScreen(width, height) with offscreen.bind(): bgl.glClear(bgl.GL_COLOR_BUFFER_BIT) shader.bind() def bind_and_filter(tex, bindcode, image=None, imageNum=None): bgl.glActiveTexture(tex) bgl.glBindTexture(bgl.GL_TEXTURE_2D, bindcode) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) if image != None and imageNum != None: shader.uniform_int(image, imageNum) # Bind all of the cubemap textures and enable correct filtering and wrapping # to prevent seams bind_and_filter(bgl.GL_TEXTURE0, imageList[0].bindcode, "cubeLeftImage", 0) bind_and_filter(bgl.GL_TEXTURE1, imageList[1].bindcode, "cubeRightImage", 1) bind_and_filter(bgl.GL_TEXTURE2, imageList[2].bindcode, "cubeBottomImage", 2) bind_and_filter(bgl.GL_TEXTURE3, imageList[3].bindcode, "cubeTopImage", 3) bind_and_filter(bgl.GL_TEXTURE4, imageList[4].bindcode, "cubeFrontImage", 4) if not self.no_back_image: bind_and_filter(bgl.GL_TEXTURE5, imageList[5].bindcode, "cubeBackImage", 5) # Bind the resulting texture bind_and_filter(bgl.GL_TEXTURE6, offscreen.color_texture) # Render the image batch.draw(shader) # Unload the textures for image in imageList: image.gl_free() # Read the resulting pixels into a buffer buffer = bgl.Buffer(bgl.GL_FLOAT, width * height * 4) bgl.glGetTexImage(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA, bgl.GL_FLOAT, buffer) # Unload the offscreen texture offscreen.free() # Remove the cubemap textures: for image in imageList: bpy.data.images.remove(image) # Copy the pixels from the buffer to an image object if not outputName in bpy.data.images.keys(): bpy.data.images.new(outputName, width, height) imageRes = bpy.data.images[outputName] imageRes.scale(width, height) imageRes.pixels = buffer return imageRes
def read_tex(reader, printer): import bgl global name_format r = reader p = printer p("tex file version: {}", r.i32()) num_textures = p("num textures: {}", r.i32()) already_seen = set() for i in range(num_textures): p("texture #{}", i) checksum = p(" checksum: {}", to_hex_string(r.u32())) if checksum in already_seen: p("Duplicate checksum!", None) else: already_seen.add(checksum) create_image = (checksum not in bpy.data.images) if not create_image: p("Image {} already exists, will not be created!", checksum) # tex_map[checksum] = i img_width = p(" width: {}", r.u32()) img_height = p(" height: {}", r.u32()) levels = p(" levels: {}", r.u32()) texel_depth = p(" texel depth: {}", r.u32()) pal_depth = p(" palette depth: {}", r.u32()) dxt_version = p(" dxt version: {}", r.u32()) pal_size = p(" palette depth: {}", r.u32()) if dxt_version == 2: dxt_version = 1 if pal_size > 0: if pal_depth == 32: pal_colors = [] for j in range(pal_size // 4): cb, cg, cr, ca = r.read("4B") pal_colors.append( (cr / 255.0, cb / 255.0, cb / 255.0, ca / 255.0)) else: r.read(str(pal_size) + "B") for j in range(levels): data_size = r.u32() if not create_image: r.offset += data_size continue if j == 0 and dxt_version == 0: data_bytes = r.buf[r.offset:r.offset + data_size] if pal_size > 0 and pal_depth == 32 and texel_depth == 8: data_bytes = swizzle(data_bytes, img_width, img_height, 8, 0, True) blend_img = bpy.data.images.new(str(checksum), img_width, img_height, alpha=True) blend_img.pixels = [ pal_col for pal_idx in data_bytes for pal_col in pal_colors[pal_idx] ] elif j == 0 and dxt_version in (1, 5): data_bytes = r.buf[r.offset:r.offset + data_size] blend_img = bpy.data.images.new(str(checksum), img_width, img_height, alpha=True) blend_img.gl_load() blend_img.thug_image_props.compression_type = "DXT5" if dxt_version == 5 else "DXT1" image_id = blend_img.bindcode[0] if image_id == 0: print("Got 0 bindcode for " + blend_img.name) else: buf = bgl.Buffer(bgl.GL_BYTE, len(data_bytes)) buf[:] = data_bytes bgl.glBindTexture(bgl.GL_TEXTURE_2D, image_id) bgl.glCompressedTexImage2D( bgl.GL_TEXTURE_2D, 0, COMPRESSED_RGBA_S3TC_DXT5_EXT if dxt_version == 5 else COMPRESSED_RGBA_S3TC_DXT1_EXT, img_width, #level_img_width, img_height, #level_img_height, 0, len(data_bytes), buf) del buf buf_size = img_width * img_height * 4 # LOG.debug(buf_size) buf = bgl.Buffer(bgl.GL_FLOAT, buf_size) bgl.glGetTexImage(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA, bgl.GL_FLOAT, buf) blend_img.pixels = buf blend_img.pack(as_png=True) del buf r.offset += data_size
def get_texture(name): """nameが'icons'なら全体のテクスチャを返す :type name: str """ if name in textures: return textures[name] if name in internal_icons: textures[name] = internal_icons[name] return textures[name] if name == 'icons': icon_type = 'icons' elif name in icons and icons[name] < 780: # 780は'BRUSH_ADD': icon_type = 'icon' elif name in brush_icons: icon_type = 'brush' elif name in matcap_icons: icon_type = 'matcap' elif '.' in name: icon_type = 'image' else: return None dirname = os.path.dirname(os.path.abspath(__file__)) if name == 'icons': filepath = os.path.join(dirname, ICON_FILE_NAME) img = load_image(filepath) if not img: return None sx, sy = img.size buf = bgl.Buffer(bgl.GL_FLOAT, 4 * sx * sy) img.gl_load(filter=bgl.GL_LINEAR, mag=bgl.GL_LINEAR) # TODO: 仕様変更があったので動作確認 -> img.bindcode bgl.glBindTexture(bgl.GL_TEXTURE_2D, img.bindcode[0]) bgl.glGetTexImage(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA, bgl.GL_FLOAT, buf) img.gl_free() img.user_clear() bpy.data.images.remove(img) x = y = 0 w = sx h = sy elif icon_type == 'icon': if 'icons' not in textures: get_texture('icons') tex, buf, sx, sy, _x, _y, _w, _h = textures['icons'] row, col = divmod(icons[name], 26) x = 10 + (40 + 2) * col y = 10 + (40 + 2) * row w = h = 32 elif icon_type in ('brush', 'matcap'): if icon_type == 'brush': filepath = os.path.join(dirname, 'brushicons', brush_icons[name]) else: filepath = os.path.join(dirname, 'matcaps', matcap_icons[name]) buf, sx, sy = get_image_buffer(filepath) if not buf: return None x = y = 0 w, h = sx, sy else: buf, sx, sy = get_image_buffer(name) if not buf: return None x = y = 0 w, h = sx, sy if icon_type == 'icon': textures[name] = [tex, buf, sx, sy, x, y, w, h] else: texture = bgl.Buffer(bgl.GL_INT, 1) # GLuint bgl.glGenTextures(1, texture) bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture[0]) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP) bgl.glTexImage2D(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA, sx, sy, 0, bgl.GL_RGBA, bgl.GL_FLOAT, buf) textures[name] = [texture[0], buf, sx, sy, x, y, w, h] return textures[name]
def cubemap_to_equirectangular(self, imageList, outputName): # Define the vertex shader vertex_shader = ''' in vec3 aVertexPosition; in vec2 aVertexTextureCoord; out vec2 vTexCoord; void main() { vTexCoord = aVertexTextureCoord; gl_Position = vec4(aVertexPosition, 1); } ''' # Define the fragment shader for the 360 degree conversion fragment_shader_360 = ''' #define PI 3.1415926535897932384626 // Input cubemap textures uniform sampler2D cubeLeftImage; uniform sampler2D cubeRightImage; uniform sampler2D cubeBottomImage; uniform sampler2D cubeTopImage; uniform sampler2D cubeBackImage; uniform sampler2D cubeFrontImage; in vec2 vTexCoord; out vec4 fragColor; void main() { // Calculate the pointing angle float azimuth = vTexCoord.x * PI; float elevation = vTexCoord.y * PI / 2.0; // Calculate the pointing vector vec3 pt; pt.x = cos(elevation) * sin(azimuth); pt.y = sin(elevation); pt.z = cos(elevation) * cos(azimuth); // Select the correct pixel if ((abs(pt.x) >= abs(pt.y)) && (abs(pt.x) >= abs(pt.z))) { if (pt.x <= 0.0) { fragColor = texture(cubeLeftImage, vec2(((-pt.z/pt.x)+1.0)/2.0,((-pt.y/pt.x)+1.0)/2.0)); } else { fragColor = texture(cubeRightImage, vec2(((-pt.z/pt.x)+1.0)/2.0,((pt.y/pt.x)+1.0)/2.0)); } } else if (abs(pt.y) >= abs(pt.z)) { if (pt.y <= 0.0) { fragColor = texture(cubeBottomImage, vec2(((-pt.x/pt.y)+1.0)/2.0,((-pt.z/pt.y)+1.0)/2.0)); } else { fragColor = texture(cubeTopImage, vec2(((pt.x/pt.y)+1.0)/2.0,((-pt.z/pt.y)+1.0)/2.0)); } } else { if (pt.z <= 0.0) { fragColor = texture(cubeBackImage, vec2(((pt.x/pt.z)+1.0)/2.0,((-pt.y/pt.z)+1.0)/2.0)); } else { fragColor = texture(cubeFrontImage, vec2(((pt.x/pt.z)+1.0)/2.0,((pt.y/pt.z)+1.0)/2.0)); } } } ''' # Define the fragment shader for the 180 degree conversion fragment_shader_180 = ''' #define PI 3.1415926535897932384626 // Input cubemap textures uniform sampler2D cubeLeftImage; uniform sampler2D cubeRightImage; uniform sampler2D cubeBottomImage; uniform sampler2D cubeTopImage; uniform sampler2D cubeFrontImage; in vec2 vTexCoord; out vec4 fragColor; void main() {{ // Calculate the pointing angle float fovd = {0}; float fovfrac = fovd/360.0; float sidefrac = (fovd-90.0)/180; float azimuth = vTexCoord.x * PI * fovfrac; float elevation = vTexCoord.y * PI / 2.0; // Calculate the pointing vector vec3 pt; pt.x = cos(elevation) * sin(azimuth); pt.y = sin(elevation); pt.z = cos(elevation) * cos(azimuth); // Select the correct pixel if ((abs(pt.x) >= abs(pt.y)) && (abs(pt.x) >= abs(pt.z))) {{ if (pt.x <= 0.0) {{ fragColor = texture(cubeLeftImage, vec2((((-pt.z/pt.x))+(2.0*sidefrac-1.0))/(2.0*sidefrac),((-pt.y/pt.x)+1.0)/2.0)); }} else {{ fragColor = texture(cubeRightImage, vec2(((-pt.z/pt.x)+1.0)/(2.0*sidefrac),((pt.y/pt.x)+1.0)/2.0)); }} }} else if (abs(pt.y) >= abs(pt.z)) {{ if (pt.y <= 0.0) {{ fragColor = texture(cubeBottomImage, vec2(((-pt.x/pt.y)+1.0)/2.0,((-pt.z/pt.y)+(2.0*sidefrac-1.0))/(2.0*sidefrac))); }} else {{ fragColor = texture(cubeTopImage, vec2(((pt.x/pt.y)+1.0)/2.0,((-pt.z/pt.y)+1.0)/(2.0*sidefrac))); }} }} else {{ fragColor = texture(cubeFrontImage, vec2(((pt.x/pt.z)+1.0)/2.0,((pt.y/pt.z)+1.0)/2.0)); }} }} '''.format(self.FOV) # Define the fragment shader for the dome conversion fragment_shader_dome = ''' #define PI 3.1415926535897932384626 // Input cubemap textures uniform sampler2D cubeLeftImage; uniform sampler2D cubeRightImage; uniform sampler2D cubeBottomImage; uniform sampler2D cubeTopImage; uniform sampler2D cubeFrontImage; uniform sampler2D cubeBackImage; in vec2 vTexCoord; out vec4 fragColor; void main() {{ float fovd = {0}; float fovfrac = fovd/360.0; float sidefrac = (fovd-90.0)/180; float hfov = fovfrac*PI; vec2 d = vTexCoord.xy; float r = length( d ); if( r > 1.0 ) {{ fragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }} vec2 dunit = normalize( d ); float phi = r * hfov; vec3 pt = vec3( 1.0, 1.0, 1.0 ); pt.xy = dunit * sin( phi ); pt.z = cos( phi ); // Select the correct pixel // Select the correct pixel if ((abs(pt.x) >= abs(pt.y)) && (abs(pt.x) >= abs(pt.z))) {{ if (pt.x <= 0.0) {{ fragColor = texture(cubeLeftImage, vec2((((-pt.z/pt.x))+(2.0*sidefrac-1.0))/(2.0*sidefrac),((-pt.y/pt.x)+1.0)/2.0)); }} else {{ fragColor = texture(cubeRightImage, vec2(((-pt.z/pt.x)+1.0)/(2.0*sidefrac),((pt.y/pt.x)+1.0)/2.0)); }} }} else if (abs(pt.y) >= abs(pt.z)) {{ if (pt.y <= 0.0) {{ fragColor = texture(cubeBottomImage, vec2(((-pt.x/pt.y)+1.0)/2.0,((-pt.z/pt.y)+(2.0*sidefrac-1.0))/(2.0*sidefrac))); }} else {{ fragColor = texture(cubeTopImage, vec2(((pt.x/pt.y)+1.0)/2.0,((-pt.z/pt.y)+1.0)/(2.0*sidefrac))); }} }} else {{ if (pt.z <= 0.0) {{ fragColor = texture(cubeBackImage, vec2(((pt.x/pt.z)+1.0)/2.0,((-pt.y/pt.z)+1.0)/2.0)); }} else {{ fragColor = texture(cubeFrontImage, vec2(((pt.x/pt.z)+1.0)/2.0,((pt.y/pt.z)+1.0)/2.0)); }} }} }} '''.format(self.FOV) # Generate the OpenGL shader pos = [ (-1.0, -1.0, -1.0), # left, bottom, back (-1.0, 1.0, -1.0), # left, top, back (1.0, -1.0, -1.0), # right, bottom, back (1.0, 1.0, -1.0) ] # right, top, back coords = [ (-1.0, -1.0), # left, bottom (-1.0, 1.0), # left, top (1.0, -1.0), # right, bottom (1.0, 1.0) ] # right, top vertexIndices = [(0, 3, 1), (3, 0, 2)] if self.is_dome: shader = gpu.types.GPUShader(vertex_shader, fragment_shader_dome) else: if self.no_back_image: shader = gpu.types.GPUShader(vertex_shader, fragment_shader_180) else: shader = gpu.types.GPUShader(vertex_shader, fragment_shader_360) batch = batch_for_shader(shader, 'TRIS', {"aVertexPosition": pos,\ "aVertexTextureCoord": coords},\ indices=vertexIndices) # Change the color space of all of the images to Linear # and load them into OpenGL textures imageLeft = imageList[0] imageLeft.colorspace_settings.name = 'Linear' imageLeft.gl_load() imageRight = imageList[1] imageRight.colorspace_settings.name = 'Linear' imageRight.gl_load() imageBottom = imageList[2] imageBottom.colorspace_settings.name = 'Linear' imageBottom.gl_load() imageTop = imageList[3] imageTop.colorspace_settings.name = 'Linear' imageTop.gl_load() imageFront = imageList[4] imageFront.colorspace_settings.name = 'Linear' imageFront.gl_load() if not self.no_back_image: imageBack = imageList[5] imageBack.colorspace_settings.name = 'Linear' imageBack.gl_load() # set the size of the final image width = self.image_size[0] height = self.image_size[1] # Create an offscreen render buffer and texture offscreen = gpu.types.GPUOffScreen(width, height) with offscreen.bind(): bgl.glClear(bgl.GL_COLOR_BUFFER_BIT) shader.bind() # Bind all of the cubemap textures and enable correct filtering and wrapping # to prevent seams bgl.glActiveTexture(bgl.GL_TEXTURE0) bgl.glBindTexture(bgl.GL_TEXTURE_2D, imageLeft.bindcode) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) shader.uniform_int("cubeLeftImage", 0) bgl.glActiveTexture(bgl.GL_TEXTURE1) bgl.glBindTexture(bgl.GL_TEXTURE_2D, imageRight.bindcode) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) shader.uniform_int("cubeRightImage", 1) bgl.glActiveTexture(bgl.GL_TEXTURE2) bgl.glBindTexture(bgl.GL_TEXTURE_2D, imageBottom.bindcode) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) shader.uniform_int("cubeBottomImage", 2) bgl.glActiveTexture(bgl.GL_TEXTURE3) bgl.glBindTexture(bgl.GL_TEXTURE_2D, imageTop.bindcode) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) shader.uniform_int("cubeTopImage", 3) bgl.glActiveTexture(bgl.GL_TEXTURE4) bgl.glBindTexture(bgl.GL_TEXTURE_2D, imageFront.bindcode) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) shader.uniform_int("cubeFrontImage", 4) if not self.no_back_image: bgl.glActiveTexture(bgl.GL_TEXTURE5) bgl.glBindTexture(bgl.GL_TEXTURE_2D, imageBack.bindcode) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) shader.uniform_int("cubeBackImage", 5) # Bind the resulting texture bgl.glActiveTexture(bgl.GL_TEXTURE6) bgl.glBindTexture(bgl.GL_TEXTURE_2D, offscreen.color_texture) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) # Render the image batch.draw(shader) # Unload the textures imageLeft.gl_free() imageRight.gl_free() imageBottom.gl_free() imageTop.gl_free() imageFront.gl_free() if not self.no_back_image: imageBack.gl_free() # Read the resulting pixels into a buffer buffer = bgl.Buffer(bgl.GL_FLOAT, width * height * 4) bgl.glGetTexImage(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA, bgl.GL_FLOAT, buffer) # Unload the offscreen texture offscreen.free() # Remove the cubemap textures: for image in imageList: bpy.data.images.remove(image) # Copy the pixels from the buffer to an image object if not outputName in bpy.data.images.keys(): bpy.data.images.new(outputName, width, height) imageRes = bpy.data.images[outputName] imageRes.scale(width, height) imageRes.pixels = buffer return imageRes
def render_image(self): # Render the scene and load it into the script tmp_path = self.scene.render.filepath tmp_image = 'temp_img_store' + '.png' if tmp_image in bpy.data.images: bpy.data.images.remove(bpy.data.images[tmp_image]) self.scene.render.filepath = self.path + tmp_image bpy.ops.render.render(write_still=True) renderedImage = bpy.data.images.load(self.path + tmp_image) renderedImage.colorspace_settings.name = 'Linear' # Vertex shader for cubemap frontimage to equirectangular vertex_shader = ''' in vec3 aVertexPosition; in vec2 aVertexTextureCoord; out vec2 vTexCoord; void main() { vTexCoord = aVertexTextureCoord; gl_Position = vec4(aVertexPosition, 1); } ''' # Generate the OpenGL shader pos = [(-1.0, -1.0, -1.0), (-1.0, 1.0, -1.0), \ (1.0, -1.0, -1.0), (1.0, 1.0, -1.0)] coords = [(-2.0, -1.0), (-2.0, 1.0), \ (2.0, -1.0), (2.0, 1.0)] vertexIndices = [(0, 3, 1), (3, 0, 2)] shader = gpu.types.GPUShader(vertex_shader, self.frag_shader) batch = batch_for_shader(shader, 'TRIS', {"aVertexPosition": pos, \ "aVertexTextureCoord": coords}, \ indices=vertexIndices) # Load rendered image into OpenGL textures renderedImage.gl_load() # Create an offscreen render buffer and texture offscreen = gpu.types.GPUOffScreen(self.image_size[0], self.image_size[1]) with offscreen.bind(): #bgl.glClearColor(0,0,0,1) bgl.glClear(bgl.GL_COLOR_BUFFER_BIT) shader.bind() def bind_and_filter(tex, bindcode, image=None, imageNum=None): bgl.glActiveTexture(tex) bgl.glBindTexture(bgl.GL_TEXTURE_2D, bindcode) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameterf(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) # Turn on GL_CLAMP_TO_BORDER and delete paint black codes in fragment shader # would give a transparent background #bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_BORDER) #bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_BORDER) # Really dont know how to change the border color #bgl.glTexParameterfv(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_BORDER_COLOR, color)#??? if image != None and imageNum != None: shader.uniform_int(image, imageNum) # Bind and filter the renderedImage bind_and_filter(bgl.GL_TEXTURE0, renderedImage.bindcode, "frontImage", 0) # Bind the resulting texture bind_and_filter(bgl.GL_TEXTURE1, offscreen.color_texture) # Render the image batch.draw(shader) # Unload the texture renderedImage.gl_free() # Read the resulting pixels into a buffer buffer = bgl.Buffer(bgl.GL_FLOAT, self.image_size[0] * self.image_size[1] * 4) bgl.glGetTexImage(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA, bgl.GL_FLOAT, buffer) # Unload the offscreen texture offscreen.free() # Remove the frontImage texture bpy.data.images.remove(renderedImage) # Turn on this line to delete tmp image everytime, turn off maybe will save some resource #os.remove(self.path + tmp_image) # Set file name image_name = "frameS{:06d}.png".format(self.scene.frame_current) # If it doesn't already exist, create an image object to store the resulting render if not image_name in bpy.data.images.keys(): imageResult = bpy.data.images.new(image_name, self.image_size[0], self.image_size[1]) imageResult = bpy.data.images[image_name] imageResult.scale(self.image_size[0], self.image_size[1]) # Copy the pixels from the buffer to an image object imageResult.pixels = buffer # Save to file imageResult.file_format = 'PNG' imageResult.filepath_raw = self.path + image_name imageResult.save() bpy.data.images.remove(imageResult) self.scene.render.filepath = tmp_path
def get_texture(name): """nameが"icons"なら全体のテクスチャを返す :type name: str """ if name in textures: return textures[name] if name in internal_icons: textures[name] = internal_icons[name] return textures[name] if name == "icons": icon_type = "icons" elif name in icons and icons[name] < 780: # 780は"BRUSH_ADD": icon_type = "icon" elif name in brush_icons: icon_type = "brush" elif name in matcap_icons: icon_type = "matcap" elif "." in name: # 拡張子のドット icon_type = "image" else: return None dirname = os.path.dirname(os.path.abspath(__file__)) if name == "icons": filepath = os.path.join(dirname, ICON_FILE_NAME) img = load_image(filepath) if not img: return None sx, sy = img.size buf = bgl.Buffer(bgl.GL_FLOAT, 4 * sx * sy) img.gl_load(filter=bgl.GL_LINEAR, mag=bgl.GL_LINEAR) bgl.glBindTexture(bgl.GL_TEXTURE_2D, img.bindcode[0]) bgl.glGetTexImage(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA, bgl.GL_FLOAT, buf) img.gl_free() img.user_clear() bpy.data.images.remove(img) x = y = 0 w = sx h = sy elif icon_type == "icon": if "icons" not in textures: get_texture("icons") tex, buf, sx, sy, _x, _y, _w, _h = textures["icons"] row, col = divmod(icons[name], 26) x = 10 + (40 + 2) * col y = 10 + (40 + 2) * row w = h = 32 elif icon_type in ("brush", "matcap"): if icon_type == "brush": filepath = os.path.join(dirname, "brushicons", brush_icons[name]) else: filepath = os.path.join(dirname, "matcaps", matcap_icons[name]) buf, sx, sy = get_image_buffer(filepath) if not buf: return None x = y = 0 w, h = sx, sy else: buf, sx, sy = get_image_buffer(name) if not buf: return None x = y = 0 w, h = sx, sy if icon_type == "icon": textures[name] = [tex, buf, sx, sy, x, y, w, h] else: texture = bgl.Buffer(bgl.GL_INT, 1) # GLuint bgl.glGenTextures(1, texture) bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture[0]) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP) bgl.glTexImage2D(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA, sx, sy, 0, bgl.GL_RGBA, bgl.GL_FLOAT, buf) textures[name] = [texture[0], buf, sx, sy, x, y, w, h] return textures[name]