python做的游戏可以导出吗_Python for RenderDoc批量导出模型和贴图

故事背景:

美术那里有需求,需要别人游戏的模型,来借鉴一下,问我是否有工具可以一键导出模型。我就搜索了一下RenderDoc批量导出图片,结果搜到了用C++改RenderDoc源码的文章。让RenderDoc批量导出纹理_专栏-CSDN博客​blog.csdn.net

然后看了一下官网,看到了可以用python写工具的(因为不会C++,而且好像很麻烦的样子),我就试着用python来写RenderDoc的工具(其实我也不会python只是这种语言应该好学)。

使用步骤:

1.在RenderDoc里面截一张图。

2.运行RenderDoc的python shell。

3.导出图片与csv(因为只能导出csv,导不出模型,我会在unity里把他转为模型)

至于RenderDoc如何写python只要看下官网就可以了,这里贴出地址。Python API - RenderDoc documentation​renderdoc.org

原理分析:

主要还是python部分的原理,怎么调用RenderDoc接口,官网虽然有解析和例子,但是并不完全,导出图片的那个例子居然是导出output的图片。就是fragment Shader return出去的那个,完全没找到input的图片,我都是自己试出来的。

其实导出顶点CSV跟导出图片,都用到个这个函数

controller.GetPipelineState()

从这个pipeline的state里面获取,就是对应RenderDoc里面的这个面板

然后用这个函数

state.GetReadOnlyResources(renderdoc.ShaderStage.Fragment)

这个里面就有所有的图片的resourceId,可以写个循环保存所有的图片。

texsave = rd.TextureSave()

texsave.resourceId = resourceId

if texsave.resourceId == rd.ResourceId.Null():

return False

filename = str(int(texsave.resourceId))

texsave.mip = 0

texsave.slice.sliceIndex = 0

texsave.alpha = rd.AlphaMapping.Preserve

texsave.destType = rd.FileType.PNG

if not os.path.exists("{0}/{1}".format(folderName,eventId)):

os.makedirs("{0}/{1}".format(folderName,eventId))

outTexPath = "{0}/{1}/{2}.png".format(folderName,eventId,filename)

controller.SaveTexture(texsave, outTexPath)

同样的vertex也是这么获取,获取vertex index的resourceId,跟vertex自身的resourceId。

ib.state.GetIBuffer()

vbs.state.GetVBuffers()

....

something

...

meshInput.indexResourceId = ib.resourceId # vertex index的resourceId

meshInput.vertexResourceId = vbs[attr.vertexBuffer].resourceId # vertex自身的resourceId

然后根据resourceId去BufferData里面去得到vertex

controller.GetBufferData(meshInput.indexResourceId, meshInput.indexByteOffset, 0)

源码:只给出python源码,C#源码可以参考这里RenderDocMeshParserForUnity​github.com

import sys

import csv

folderName = "C:/Users/Administrator/Desktop/capMesh1"

startIndex = 475

endIndex = 759

isPrint = False

# Import renderdoc if not already imported (e.g. in the UI)

if 'renderdoc' not in sys.modules and '_renderdoc' not in sys.modules:

import renderdoc

# Alias renderdoc for legibility

rd = renderdoc

# We'll need the struct data to read out of bytes objects

import struct

import os

# We base our data on a MeshFormat, but we add some properties

class MeshData(rd.MeshFormat):

indexOffset = 0

name = ''

def pySaveTexture(resourceId,eventId,controller):

texsave = rd.TextureSave()

texsave.resourceId = resourceId

if texsave.resourceId == rd.ResourceId.Null():

return False

filename = str(int(texsave.resourceId))

# texsave.alpha = rd.AlphaMapping.BlendToCheckerboard

# Most formats can only display a single image per file, so we select the

# first mip and first slice

texsave.mip = 0

texsave.slice.sliceIndex = 0

texsave.alpha = rd.AlphaMapping.Preserve

texsave.destType = rd.FileType.PNG

if not os.path.exists("{0}/{1}".format(folderName,eventId)):

os.makedirs("{0}/{1}".format(folderName,eventId))

outTexPath = "{0}/{1}/{2}.png".format(folderName,eventId,filename)

controller.SaveTexture(texsave, outTexPath)

print("保存图片{0}".format(outTexPath))

return True

def findIndexDrawLoop(d,index):

ret = None

if d.eventId == index:

return d

for c in d.children:

ret = findIndexDrawLoop(c,index)

if ret:

return ret

return ret

# Recursively search for the drawcall with the most vertices

def findIndexDraw(index,controller):

ret = None

for d in controller.GetDrawcalls():

if d.eventId == index:

ret = d

return ret

for c in d.children:

ret = findIndexDrawLoop(c,index)

if ret:

return ret

return ret

# Unpack a tuple of the given format, from the data

def unpackData(fmt, data):

if isPrint:

print(888)

# We don't handle 'special' formats - typically bit-packed such as 10:10:10:2

# raise RuntimeError("Packed formats are not supported!")

formatChars = {}

# 012345678

formatChars[rd.CompType.UInt] = "xBHxIxxxL"

formatChars[rd.CompType.SInt] = "xbhxixxxl"

formatChars[rd.CompType.Float] = "xxexfxxxd" # only 2, 4 and 8 are valid

# These types have identical decodes, but we might post-process them

formatChars[rd.CompType.UNorm] = formatChars[rd.CompType.UInt]

formatChars[rd.CompType.UScaled] = formatChars[rd.CompType.UInt]

formatChars[rd.CompType.SNorm] = formatChars[rd.CompType.SInt]

formatChars[rd.CompType.SScaled] = formatChars[rd.CompType.SInt]

# We need to fetch compCount components

vertexFormat = str(fmt.compCount) + formatChars[fmt.compType][fmt.compByteWidth]

# Unpack the data

value = struct.unpack_from(vertexFormat, data, 0)

# If the format needs post-processing such as normalisation, do that now

if fmt.compType == rd.CompType.UNorm:

divisor = float((2 ** (fmt.compByteWidth * 8)) - 1)

value = tuple(float(i) / divisor for i in value)

elif fmt.compType == rd.CompType.SNorm:

maxNeg = -float(2 ** (fmt.compByteWidth * 8)) / 2

divisor = float(-(maxNeg-1))

value = tuple((float(i) if (i == maxNeg) else (float(i) / divisor)) for i in value)

# If the format is BGRA, swap the two components

if fmt.BGRAOrder():

value = tuple(value[i] for i in [2, 1, 0, 3])

return value

# Get a list of MeshData objects describing the vertex inputs at this draw

def getMeshInputs(controller, draw):

state = controller.GetPipelineState()

# Get the index & vertex buffers, and fixed vertex inputs

ib = state.GetIBuffer()

vbs = state.GetVBuffers()

attrs = state.GetVertexInputs()

sampleList = state.GetReadOnlyResources(renderdoc.ShaderStage.Fragment)

for sample in sampleList:

for res in sample.resources:

print(res.resourceId)

if not pySaveTexture(res.resourceId,draw.eventId,controller):

break

meshInputs = []

# for i in ib:

# if isPri:nt

# print(i)

# for v in vbs:

# print(v)

#for attr in attrs:

# print(attr.name)

for attr in attrs:

# We don't handle instance attributes

if attr.perInstance:

raise RuntimeError("Instanced properties are not supported!")

meshInput = MeshData()

meshInput.indexResourceId = ib.resourceId # 2646

meshInput.indexByteOffset = ib.byteOffset # 0

meshInput.indexByteStride = draw.indexByteWidth # 0

meshInput.baseVertex = draw.baseVertex # 0

meshInput.indexOffset = draw.indexOffset # 0

meshInput.numIndices = draw.numIndices #顶点总数 18

# If the draw doesn't use an index buffer, don't use it even if bound

if not (draw.flags & rd.DrawFlags.Indexed):

meshInput.indexResourceId = rd.ResourceId.Null()

# The total offset is the attribute offset from the base of the vertex

meshInput.vertexByteOffset = attr.byteOffset + vbs[attr.vertexBuffer].byteOffset + draw.vertexOffset * vbs[attr.vertexBuffer].byteStride # 0

meshInput.format = attr.format

meshInput.vertexResourceId = vbs[attr.vertexBuffer].resourceId # 2645

meshInput.vertexByteStride = vbs[attr.vertexBuffer].byteStride # 56

meshInput.name = attr.name

meshInputs.append(meshInput)

return meshInputs

def getIndices(controller, mesh):

# Get the character for the width of index

indexFormat = 'B'

if mesh.indexByteStride == 2:

indexFormat = 'H'

elif mesh.indexByteStride == 4:

indexFormat = 'I'

# Duplicate the format by the number of indices

indexFormat = str(mesh.numIndices) + indexFormat

# If we have an index buffer

if mesh.indexResourceId != rd.ResourceId.Null():

# Fetch the data

ibdata = controller.GetBufferData(mesh.indexResourceId, mesh.indexByteOffset, 0)

# Unpack all the indices, starting from the first index to fetch

offset = mesh.indexOffset * mesh.indexByteStride

indices = struct.unpack_from(indexFormat, ibdata, offset)

# Apply the baseVertex offset

return [i + mesh.baseVertex for i in indices]

else:

# With no index buffer, just generate a range

return tuple(range(mesh.numIndices))

def printMeshData(controller, meshData,draw):

if isPrint:

print(4444)

indices = getIndices(controller, meshData[0])

csvArray = []

fileheader = []

formatxyzw = [".x",".y",".z",".w"]

if isPrint:

print("Mesh configuration:")

fileheader.append("VTX")

fileheader.append("IDX")

for attr in meshData:

if not attr.format.Special():

if isPrint:

print("\t%s:" % attr.name)

if isPrint:

print("\t\t- vertex: %s / %d stride" % (attr.vertexResourceId, attr.vertexByteStride))

if isPrint:

print("\t\t- format: %s x %s @ %d" % (attr.format.compType, attr.format.compCount, attr.vertexByteOffset))

headFormat = "{0}{1}"

for i in range(0,attr.format.compCount):

newStr = headFormat.format(attr.name,formatxyzw[i])

fileheader.append(newStr)

# We'll decode the first three indices making up a triangle

csvArray.append(fileheader)

# 写入CSV

if not os.path.exists("{0}/{1}".format(folderName,draw.eventId)):

os.makedirs("{0}/{1}".format(folderName,draw.eventId))

outPath = "{0}/{1}/model.csv".format(folderName,draw.eventId)

csvFile = open(outPath, "w",newline='')

writer = csv.writer(csvFile)

# ##########################保存图片#############################################

for inputIter in draw.outputs:

if not pySaveTexture(inputIter,draw.eventId,controller):

break

# ##########################保存图片#############################################

i = 0

for idx in indices:

# for i in range(0, 3):

# idx = indices[i]

# 每个顶点的信息

indiceArray = []

if isPrint:

print("Vertex %d is index %d:" % (i, idx))

indiceArray.append(i)

indiceArray.append(idx)

for attr in meshData:

if not attr.format.Special():

# This is the data we're reading from. This would be good to cache instead of

# re-fetching for every attribute for every index

offset = attr.vertexByteOffset + attr.vertexByteStride * idx

data = controller.GetBufferData(attr.vertexResourceId, offset, 0)

# Get the value from the data

value = unpackData(attr.format, data)

for j in range(0,attr.format.compCount):

indiceArray.append(value[j])

# if isPri:ntWe don't go into the details of semantic matching here, just

# print both

if isPrint:

print("\tAttribute '%s': %s" % (attr.name, value))

csvArray.append(indiceArray)

i = i + 1

writer.writerows(csvArray)

csvFile.close()

print("写入{0}成功".format(outPath))

def sampleCodePreDraw(controller,draw):

if draw.eventId >= startIndex and draw.eventId <= endIndex:

# Move to that draw

controller.SetFrameEvent(draw.eventId, True)

if isPrint:

print("Decoding mesh inputs at %d: %s\n\n" % (draw.eventId, draw.name))

# # Calculate the mesh input configuration

meshInputs = getMeshInputs(controller, draw)

# if isPri:nt# Fetch and

# print the data from the mesh inputs

printMeshData(controller, meshInputs,draw)

def sampleCodeRecursion(controller,draw):

sampleCodePreDraw(controller,draw)

for d in draw.children:

sampleCodeRecursion(controller,d)

def sampleCode(controller):

for draw in controller.GetDrawcalls():

sampleCodeRecursion(controller,draw)

def loadCapture(filename):

if isPrint:

print(222)

# Open a capture file handle

cap = rd.OpenCaptureFile()

# Open a particular file - see also OpenBuffer to load from memory

status = cap.OpenFile(filename, '', None)

# Make sure the file opened successfully

if status != rd.ReplayStatus.Succeeded:

raise RuntimeError("Couldn't open file: " + str(status))

# Make sure we can replay

if not cap.LocalReplaySupport():

raise RuntimeError("Capture cannot be replayed")

# Initialise the replay

status,controller = cap.OpenCapture(rd.ReplayOptions(), None)

if status != rd.ReplayStatus.Succeeded:

raise RuntimeError("Couldn't initialise replay: " + str(status))

return (cap, controller)

if 'pyrenderdoc' in globals():

if isPrint:

print(111)

pyrenderdoc.Replay().BlockInvoke(sampleCode)

else:

if isPrint:

print("aaaa")

rd.InitialiseReplay(rd.GlobalEnvironment(), [])

if len(sys.argv) <= 1:

if isPrint:

print('Usage: python3 {} filename.rdc'.format(sys.argv[0]))

sys.exit(0)

cap,controller = loadCapture(sys.argv[1])

sampleCode(controller)

controller.Shutdown()

cap.Shutdown()

rd.ShutdownReplay()

print("导出完毕!!!!")

优化:

其实还可以做优化,这样导csv文件实在太慢了,我想到两个方法优化。

1.用C++直接导出csv,这样是最快的。

2.可以只顺序的导出vertex,因为现在是导了很多重复的vertex,就是把index跟vertex分开导,在c#部分把他转成三角形,可以使得程序更快,大概能快两到三倍的样子。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/431426.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

treegrid.bootstrap使用说明

treegrid.bootstrap使用说明 这个插件是用来做有层次的表格的&#xff0c;大概如图&#xff1a; 官网 http://maxazan.github.io/jquery-treegrid/ 使用这个控件之前需要引入以下css及js&#xff08;因为用到了 bootstrap.js 所以加上了 bootstrap的样式和脚本&#xff09; bo…

matlab 条形图横坐标,Matlab条形图bar横坐标间距设置

1. 默认横坐标数据 X[x1, x2, x3, x4, x5, x6] %一行六列bar(X); %绘制基础条形图2. 修改横坐标标签#考虑横坐标标签文本较长且字体较大的情况bar(X);set(gca, xticklabels,{Apple, Orange, Banana, Pear, Pitaya, Lemon}, Fontname, Times New Roman, Fontsize, 16); %修…

成都python数据分析师职业技能_合格大数据分析师应该具备的技能

课程七、建模分析师之软技能 - 数据库技术本部分课程主要介绍MySQL数据库的安装使用及常用数据操作1、关系型数据库介绍2、MySQL的基本操作:1)数据库的操作2)数据表的操作3)备份与恢复3、常用的SQL语句:1)查询语句(SELECT)2)插入语句(INSERT)3)更新语句(UPDATE)4)删除语句(DELE…

项目属性--生成事件--后期生成事件命令行

以开源记牌器https://github.com/Epix37/Hearthstone-Deck-Tracker 为例&#xff0c;Hearthstone Deck Tracker项目中的后期生成事件命令行&#xff1a; if "$(ConfigurationName)" "Release" ( rmdir /S /Q "..\Hearthstone Deck Tracker" mkd…

大连理工优化方法matlab,大连理工大学2016年秋季优化方法大作业.pdf

优化方法期末上机大作业姓 名&#xff1a;李岚松学 部&#xff1a;电信学部电气工程学 号2016 年 11 月 9 日1最速下降法//最速下降法主函数//function llsdi1titidu(x)di1titidu(x)x0x; eps1e-4; k0; g0g(x0); s04; k0; g0g(x0); s0-g0;while (k>0)if norm(g0)break;elsela…

查看租户情况

source /root/openrc 查看keystone租户 keystone tenant-list 已知租户ID&#xff0c;获取租户名称 keystone tenant-get 5d95a18b92834ef2ada3abcf8eff1c83 查看某租户的配额及使用情况 # nova absolute-limits –-tenant ac9e6a9f-58c(租户ID)&#xff08;输出的内容不准确&a…

stm32 485和232可以用同一个串口吗_STM32的复用时钟何时开启?

STM32的AFIO时钟真的是在开启引脚复用功能的时候开启吗&#xff1f;其实并不是~什么是复用&#xff1f;我们知道&#xff0c;STM32有很多外设&#xff0c;这些外设的外部引脚都是与GPIO共用的。我们可以通过软件来配置引脚作为GPIO引脚还是作为外设引脚。当引脚配置为外设引脚时…

matlab 0-100随机数,添加到100的随机数:matlab

我经常看到这样的错误&#xff1a;要用给定的和来生成随机数&#xff0c;我们只需要使用一个一致的随机集&#xff0c;并且只需对它们进行缩放。但是&#xff0c;如果你这样做的话&#xff0c;结果真的都是随机的吗&#xff1f;在两个维度上尝试这个简单的测试。生成一个巨大的…

url中#号的作用

url中#号的作用就是本页面位置跳转 比如这个url地址&#xff1a;http://www.aaaaa.com/index.html?ad34&mc#red red就是index.html页面的依哥位置 浏览器读取这个URL后&#xff0c;会自动将red位置滚动至可视区域 位置定义方式 <a name"red">cdsc</a&…

python访问mysql_python连接mysql

首先需要导入驱动模块打开cmd导入模块 pip install mysqldb(pymysql)python2.x版本--------->mysqldbpython3.x版本---------->pymysqlpython调用MySQL数据库总共五步1、导入模块(驱动) pymysql mysqldb2、获取连接 connect3、获取游标cursor4、执行sql execute 并且返回…

php左侧菜单栏递归代码,js实现左侧菜单栏递归循环遍历

首先html布局菜单jsonconst menuList [{title: 首页,key: /home},{title: UI,key: /ui,children: [{title: 按钮,key: /ui/buttons,},{title: 弹框,key: /ui/modals,},{title: Loading,key: /ui/loadings,},{title: 通知提醒,key: /ui/notification,},{title: 全局Message,key…

重定向IO

引用自&#xff1a;http://www.cnblogs.com/liunanjava/p/4307793.html 1.三个静态变量 java.lang.System提供了三个静态变量 System.in&#xff08;默认键盘&#xff09;System.out(默认显示器)System.errSystem提供了三个重定向方法2.重写向方法 System提供了三个重定向方法 …

python三维数据本地保存_如何将3D Python/NumPy数组保存为文本文件?

如果保存文件需要是“csv”样式的文本&#xff0c;则可以使用多个savetxt和loadtxt。关键是要知道这两个都可以以打开的文件作为输入。写作示例&#xff1a;In [31]: Anp.arange(3*2*4).reshape(3,2,4)In [32]: A # normal display as 3 blocks of 2d arrayOut[32]:array([[[ 0…

php 简析对象,PHP白盒审计工具RIPS源码简析

RIPS是一款对PHP源码进行风险扫描的工具&#xff0c;其对代码扫描的方式是常规的正则匹配&#xff0c;确定sink点&#xff1b;还是如flowdroid构建全局数据流图&#xff0c;并分析存储全局数据可达路径&#xff1b;下面就从其源码上略探一二。1、扫描流程分析其源码前&#xff…

投资股权众筹项目,至少需要关注6个方面

1.股权结构去工商局查看这个公司的股权结构&#xff0c;哪些人是股东&#xff0c;历史出资情况。工商局网站上有很多信息可以查看&#xff0c;我发现北京工商局网站上可以查看的信息比较全面&#xff0c;而上海的就很稀烂。 几个查询网站&#xff1a; 北京企业信用信息网 ht…

python支持gui编程_Python GUI编程完整示例

本文实例讲述了python gui编程。分享给大家供大家参考&#xff0c;具体如下&#xff1a;import osfrom time import sleepfrom tkinter import *from tkinter.messagebox import showinfoclass dirlist(object):def __init__(self, initdirnone):self.top tk()self.label lab…

左右伸缩_冬季装修为啥要留伸缩缝?等到天热地板开裂就晚了!合肥人注意下...

后台有粉丝问&#xff1a;冬天真的不适合做装修吗&#xff1f;假的&#xff0c;这句话不要再传了。每个季节都会有利有弊&#xff0c;只不过冬季施工过程中干燥的比较快&#xff0c;装修的时候对施工要求的更严格。就拿伸缩缝来说吧&#xff0c;冬天装修时不注意&#xff0c;等…

转折点(心得)

也许是刚开学不适应&#xff1f;反正就是心不静&#xff0c;给自己一天时间调整&#xff0c;马上好过来&#xff0c;加油!!!以后每天至少一道题&#xff0c;但是要是学到东西的题&#xff0c;加油&#xff01;合理安排&#xff0c;有条不紊&#xff01;转载于:https://www.cnbl…

php进入文件目录,php文件目录操作

新建文件1、先确定要写入文件的内容$content 你好;2、打开这个文件(系统会自动建立这个空文件)//假设新建的文件叫file.txt&#xff0c;而且在上级目录下。w表示‘写文件’&#xff0c;$fp下面要用到&#xff0c;表示指向某个打开的文件。$fp fopen(../file.txt, w);3、将内容…

python设计自定义栈类_Python如何自定义模块?Python基础教程,第十讲,自定义模块...

学完此次课程&#xff0c;我能做什么&#xff1f;通过此次课程&#xff0c;我们将学会如何自定义自己的模块和包&#xff0c;以及如何引用到自己的项目中&#xff0c;从而实现代码的复用。学习此次课程&#xff0c;需要多久&#xff1f;5-10分钟课程内容什么是Python的标准库&a…