日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

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

發(fā)布時(shí)間:2023/12/10 python 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python做的游戏可以导出吗_Python for RenderDoc批量导出模型和贴图 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

故事背景:

美術(shù)那里有需求,需要?jiǎng)e人游戲的模型,來借鑒一下,問我是否有工具可以一鍵導(dǎo)出模型。我就搜索了一下RenderDoc批量導(dǎo)出圖片,結(jié)果搜到了用C++改RenderDoc源碼的文章。讓RenderDoc批量導(dǎo)出紋理_專欄-CSDN博客?blog.csdn.net

然后看了一下官網(wǎng),看到了可以用python寫工具的(因?yàn)椴粫?huì)C++,而且好像很麻煩的樣子),我就試著用python來寫RenderDoc的工具(其實(shí)我也不會(huì)python只是這種語言應(yīng)該好學(xué))。

使用步驟:

1.在RenderDoc里面截一張圖。

2.運(yùn)行RenderDoc的python shell。

3.導(dǎo)出圖片與csv(因?yàn)橹荒軐?dǎo)出csv,導(dǎo)不出模型,我會(huì)在unity里把他轉(zhuǎn)為模型)

至于RenderDoc如何寫python只要看下官網(wǎng)就可以了,這里貼出地址。Python API - RenderDoc documentation?renderdoc.org

原理分析:

主要還是python部分的原理,怎么調(diào)用RenderDoc接口,官網(wǎng)雖然有解析和例子,但是并不完全,導(dǎo)出圖片的那個(gè)例子居然是導(dǎo)出output的圖片。就是fragment Shader return出去的那個(gè),完全沒找到input的圖片,我都是自己試出來的。

其實(shí)導(dǎo)出頂點(diǎn)CSV跟導(dǎo)出圖片,都用到個(gè)這個(gè)函數(shù)

controller.GetPipelineState()

從這個(gè)pipeline的state里面獲取,就是對(duì)應(yīng)RenderDoc里面的這個(gè)面板

然后用這個(gè)函數(shù)

state.GetReadOnlyResources(renderdoc.ShaderStage.Fragment)

這個(gè)里面就有所有的圖片的resourceId,可以寫個(gè)循環(huán)保存所有的圖片。

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

然后根據(jù)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 #頂點(diǎn)總數(shù) 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]

# 每個(gè)頂點(diǎn)的信息

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("導(dǎo)出完畢!!!!")

優(yōu)化:

其實(shí)還可以做優(yōu)化,這樣導(dǎo)csv文件實(shí)在太慢了,我想到兩個(gè)方法優(yōu)化。

1.用C++直接導(dǎo)出csv,這樣是最快的。

2.可以只順序的導(dǎo)出vertex,因?yàn)楝F(xiàn)在是導(dǎo)了很多重復(fù)的vertex,就是把index跟vertex分開導(dǎo),在c#部分把他轉(zhuǎn)成三角形,可以使得程序更快,大概能快兩到三倍的樣子。

總結(jié)

以上是生活随笔為你收集整理的python做的游戏可以导出吗_Python for RenderDoc批量导出模型和贴图的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。