Cenas 3D
Em TypeScript, gere uma cena 3D editável com um prompt, edite-a, renderize-a em MP4 e execute a Renderização 3D Pro com client.scene3d e os nós de cena 3D.
client.scene3d faz cenas 3D editáveis: cria uma cena a partir de um prompt, edita a cena por instrução ou por operações exatas e renderiza uma revisão em MP4. Também executa a Renderização 3D Pro (3D Render Pro), uma operação que cria uma cena e a renderiza, e lê os arquivos que uma renderização entregou. Os métodos usam os nós Gerar cena 3D (Generate 3D Scene), Editar cena 3D (Edit 3D Scene), Renderizar vídeo (Render Video) e Renderização 3D Pro. Veja a API REST de cenas 3D para os endpoints.
Métodos
| Método | O que faz |
|---|---|
capabilities() | Lê quais mecanismos e opções Pro esta instalação oferece |
generate(params) e generateAndWait() | Cria uma nova cena a partir de um prompt |
edit(params) e editAndWait() | Faz uma nova revisão de uma cena |
render(params) e renderAndWait() | Renderiza uma revisão em MP4, sem etapa de criação |
applyEdits(revisionId, params) | Salva edições exatas sem etapa de criação e sem cobrança |
quotePro(params) | Calcula o preço de uma execução da Renderização 3D Pro |
runPro(params, options?) | Inicia uma execução cotada da Renderização 3D Pro |
renderProAndWait(params, options?) | Faz a cotação, executa e aguarda em uma chamada |
getDelivery(jobId) | Lê os arquivos que uma renderização entregou |
deliveryAssetBytes(jobId, asset, options?) | Baixa um arquivo entregue |
retainedRecipe(jobId, options?) | Lê a receita que uma execução Pro recusada guardou |
assetBytes(revisionId, asset, options?) | Baixa um arquivo de uma revisão de cena |
sourceBytes(revisionId, options?) | Baixa o arquivo-fonte nativo de uma revisão |
Do prompt ao MP4
const created = await client.scene3d.generateAndWait({
prompt: "Orbit a single box on a floor over four seconds",
durationSeconds: 4,
fps: 24,
aspectRatio: "16:9",
})
const edited = await client.scene3d.editAndWait({
scenePlan: created.scenePlan,
expectedRevisionId: created.scenePlan.revisionId,
operations: [{ op: "set-camera", changes: { focalLengthMm: 50 } }],
})
const clip = await client.scene3d.renderAndWait({ planType: "3d-scene", plan: edited.scenePlan })
console.log(clip.videoUrl)Os mesmos três passos funcionam com client.nodes.runAndWait() e os tipos de nó generate-3d-scene, edit-3d-scene e render-video, que têm parâmetros tipados. Para permitir que as pessoas girem e ajustem uma cena na sua página, use a incorporação da prévia 3D. Ela não precisa de uma cópia do renderizador nem de tokens nas mensagens.
client.scene3d
capabilities()
Retorna o que esta instalação consegue criar e renderizar (GET /v1/3d-scene/capabilities).
capabilities(): Promise<Scene3DCapabilities>const caps = await client.scene3d.capabilities()
if (caps.advanced) console.log(caps.advanced.engines) // for example ["blender-cloud"]
if (caps.pro) console.log("3D Render Pro is available")basicé o mecanismo determinístico:{ available, sceneSchemaVersions }.advancedlista os mecanismos opcionais, ou énullquando não há nenhum. Um mecanismo explícito que não está disponível é recusado antes de uma geração Basic ou das verificações de créditos dela.prodescreve a Renderização 3D Pro: os mecanismos, os perfis de qualidade, os estilos e as proporções que esta instalação oferece. Ofereça só esses. Quandoproestá ausente, o nó não está disponível.
generate(params) e generateAndWait(params, options?)
Cria uma nova cena a partir de um prompt. generate() retorna o job imediatamente; generateAndWait() espera por ele e resolve com scenePlan e um changeSummary opcional.
generate(params: GenerateScene3DParams): Promise<RunNodeResult>
generateAndWait(params: GenerateScene3DParams, options?: RunAndWaitOptions): Promise<Scene3DJobOutput>Prop
Type
const { scenePlan } = await client.scene3d.generateAndWait({
prompt: "A paper boat drifts across a puddle as rain starts",
references: [{ id: "look", kind: "image", role: "appearance", url: moodImageUrl }],
})inputAssets seleciona modelos GLB que você tem permissão de usar, pelos IDs imutáveis deles; references continua trazendo as imagens de aparência e os vídeos de movimento. Não envie URLs nem hashes dos arquivos: o servidor fornece os registros dos bytes. O Basic e os mecanismos que não conseguem importar recusam inputAssets antes de cobrar. Reutilize as mesmas seleções quando enviar uma cotação Pro.
edit(params) e editAndWait(params, options?)
Faz uma nova revisão de uma cena. A cena que você passa nunca é alterada. Dê uma instrução em prompt ou operations exatas, nunca os dois.
edit(params: EditScene3DParams): Promise<RunNodeResult>
editAndWait(params: EditScene3DParams, options?: RunAndWaitOptions): Promise<Scene3DJobOutput>Prop
Type
const { scenePlan: next, changeSummary } = await client.scene3d.editAndWait({
scenePlan,
expectedRevisionId: scenePlan.revisionId,
prompt: "Make the rain heavier and lower the camera",
})render(params) e renderAndWait(params, options?)
Renderiza em MP4 exatamente a revisão que você passa, sem criar nem reconstruir nada (POST /v1/render-video/plan).
render(params: { planType: "3d-scene"; plan: Scene3DPlan; workflowId?: string; nodeId?: string }): Promise<RunNodeResult>
renderAndWait(params: RenderScene3DParams, options?: RunAndWaitOptions): Promise<NodeJobOutput>Prop
Type
const { videoUrl } = await client.scene3d.renderAndWait({ planType: "3d-scene", plan: scenePlan })O preço segue a width e a height do próprio plano:
| Quadro | Créditos | Identificador de preço |
|---|---|---|
| Até 1920 pixels no lado maior | 55 | render-video |
| Maior, até 5,12 megapixels | 83 | render-video:3d-large |
| Acima de 5,12 megapixels | 138 | render-video:3d-xlarge |
Leia os preços atuais desses identificadores com client.credits.modelCosts().
applyEdits(revisionId, params)
Salva edições exatas em uma revisão guardada, sem etapa de criação e sem cobrança (POST /v1/3d-scene/revisions/:id/edits). Retorna o novo scenePlan e um changeSummary.
applyEdits(revisionId: string, params: {
newRevisionId: string
expectedContentHash: string
operations: Scene3DV2EditOperation[]
lockedObjectIds?: string[]
}): Promise<{ scenePlan: Scene3DPlanV2; changeSummary: string }>Prop
Type
const { scenePlan: saved } = await client.scene3d.applyEdits(revisionId, {
newRevisionId: crypto.randomUUID(),
expectedContentHash,
operations,
})Adote a cena retornada só se o usuário ainda estiver editando a revisão de onde você partiu. Os arquivos de geometria e de câmera são reutilizados. Os pôsteres, a validação e os downloads nativos só são anexados de novo depois de serem gerados para a nova revisão.
Renderização 3D Pro
A Renderização 3D Pro é uma única operação: entra uma source, e um único job termina com os dois resultados: o scenePlan (a composição exata) e o videoUrl (o MP4). O resultado também traz a revisão, um pôster, shotStills, a validação e os detalhes do renderizador. client.nodes.run("pro-3d-render") e runAndWait chegam à mesma rota com os mesmos parâmetros tipados.
Uma instalação sem o mecanismo responde 503 SCENE_CAPABILITY_UNAVAILABLE e nunca recorre ao Basic. Uma instalação sem preço configurado responde 503 price_not_configured antes de reservar qualquer coisa. Não há configuração de modelo nem de esforço: o servidor define o planejador.
quotePro(params)
Calcula o preço de uma execução sem iniciá-la. Não reserva nem gasta nada. A resposta tem quoteId, um teto em maxCredits, um breakdown para mostrar e o hash de entrada com o qual a execução é verificada depois.
quotePro(params: Pro3DRenderParams): Promise<Pro3DRenderQuote>Prop
Type
source tem um destes três formatos:
{ kind: "prompt", prompt, references? }cria uma nova cena.{ kind: "scene", revisionId, sourceJobId }semeditPromptexporta uma cena guardada sem cobrança de criação. AdicionareditPromptrevisa a cena antes.sourceJobIdé obrigatório para cenas Basic que existem só no histórico de jobs.{ kind: "local-export", exportId, connectionId }usa um computador pareado.
const quote = await client.scene3d.quotePro(params)
showPrice(quote.maxCredits, quote.breakdown)runPro(params, options?)
Inicia uma execução cotada. O método precisa do quoteId de quotePro(), para que nenhuma execução comece com um preço que ninguém viu. Ele envia um Idempotency-Key: um novo a cada chamada, ou o seu em options.idempotencyKey. Reutilize o seu quando repetir uma chamada que esgotou o tempo.
runPro(params: Pro3DRenderParams & { quoteId: string }, options?: { idempotencyKey?: string }): Promise<RunNodeResult>Prop
Type
await client.scene3d.runPro({ ...params, quoteId: quote.quoteId })renderProAndWait(params, options?)
Faz a cotação quando params não tem quoteId, executa e espera: a operação inteira em uma chamada. Envia no máximo duas requisições e inicia um único job pago, admitido com base em um hash exatamente do que foi cotado.
renderProAndWait(params: Pro3DRenderParams | Pro3DRenderRunParams, options?: RunAndWaitOptions & { idempotencyKey?: string }): Promise<Pro3DRenderJobOutput>Prop
Type
const caps = await client.scene3d.capabilities()
if (caps.pro?.available) {
const shot = await client.scene3d.renderProAndWait({
source: {
kind: "prompt",
prompt: "A red suitcase rolls behind a central pillar and reappears",
references: [{ id: "look", kind: "image", role: "appearance", url: appearanceImageUrl }],
},
durationSeconds: 30,
fps: 24,
aspectRatio: "21:9",
maxRepairPasses: 2,
acceptedSceneSchemaVersions: [2],
})
console.log(shot.videoUrl) // the MP4
console.log(shot.sceneRevisionId) // export it again later, with no authoring charge
}Imagens fixas das tomadas. shotStills é uma lista de { shotIndex, frame, assetId, url }, uma imagem fixa por tomada no quadro em que a tomada começa, feita pela mesma execução sem custo extra. Uma cena de uma única tomada tem uma, no quadro 0. Os resultados feitos antes de o campo existir não têm nenhuma, então leia shot.shotStills ?? [].
Cada url é um endpoint autenticado da sua instalação, não um link público. Busque-a com as mesmas credenciais que você usou na execução; uma tag img, ou um serviço de terceiros, recebe um 401:
for (const still of shot.shotStills ?? []) {
const res = await fetch(still.url, { headers: { Authorization: `Bearer ${token}` } })
const bytes = await res.arrayBuffer() // use the bytes, or store them where your pipeline can read them
}Você ainda pode usar uma imagem fixa como referência de modelo: passe a URL dela do jeito que você a leu, em referenceImageUrls ou pela saída stills do nó. A plataforma concede a essa execução uma leitura breve desse único arquivo, em seu nome. A concessão expira minutos depois, então armazene a URL autenticada, nunca a concessão.
O que uma execução Pro informa sobre si mesma
Uma execução que criou uma cena informa o que presumiu e o que fez. Trate todos os campos como opcionais: uma instalação sem mecanismo avançado, ou um resultado mais antigo, não tem nenhum deles.
const summary = shot.metadata?.summary // what the planner says it built
const repairs = shot.repairPasses // 0 means accepted the first time
const retries = shot.admissionRetries // planner retries before a build
const mechanical = shot.mechanicalPasses
const restored = shot.restoredAssertions
const assumptions = (shot.validation?.warnings ?? [])
.filter((w) => w.code === "SCENE_AUTHORING_ASSUMPTION")
.map((w) => w.message)- Os avisos
SCENE_AUTHORING_ASSUMPTIONlistam o que o prompt não disse e, por isso, a execução decidiu. Novos códigos de aviso podem ser adicionados: trate um código desconhecido como informação, não como erro. repairPassesconta reparos, não passadas de criação, então0significa que a cena foi aceita de primeira.admissionRetriesconta outra coisa: os pedidos repetidos de receita ao planejador antes de qualquer construção.mechanicalPassesconta os reparos que o mecanismo aplicou a partir da solução do próprio compilador, sem o planejador. Eles têm uma franquia cotada própria de até 2, liberada quando não é usada, e cada um adiciona um avisoREMEDY_AUTO_APPLIED. Uma execução cotada antes de essa franquia existir cobrava essas passadas como reparos; leia a cotação que você recebeu para saber.restoredAssertionslista as verificações obrigatórias que o mecanismo restaurou depois que o planejador alterou uma delas sem que isso tivesse sido pedido. Cada uma também adiciona um avisoASSERTION_RESTORED.- Uma exportação só de renderização não criou nada, então não tem contagens nem resumo. Especialmente em
mechanicalPasses, ausente não é0.
Os resultados de generateAndWait() trazem os mesmos campos quando um mecanismo avançado criou a cena. O mecanismo Basic não consulta nenhum modelo e não traz nenhum deles.
Uma entrega que o revisor visual não aprovou
Um resultado concluído pode chegar sem a aprovação do revisor visual. Nos dois casos, o vídeo é real e os créditos foram gastos. metadata.review.verdict diz qual é o caso:
"refused": o orçamento de reparos foi gasto, todas as verificações obrigatórias passaram, e o revisor ainda assim fez objeções. A cena foi entregue com a recusa anexada."unavailable": a revisão não deu um veredito utilizável.reasoné"provider"quando ela nunca chegou ao provedor, e"unusable"quando a resposta não pôde ser usada.attemptsdiz quantas vezes a revisão foi solicitada. Ninguém avaliou esta cena.
import { scene3DReviewNote, scene3DReviewVerdictOf } from "@nodaro/shared"
const review = scene3DReviewVerdictOf(shot)
if (review) {
console.log(scene3DReviewNote(review)) // one user-safe sentence for either verdict
if (review.verdict === "unavailable") console.log(`unreviewed (${review.reason}) after ${review.attempts} attempts`)
for (const objection of review.objections) console.log(objection.category, objection.what, objection.correction)
}Use os dois helpers de @nodaro/shared em vez de ler os campos você mesmo, porque três leituras parecem certas e não são:
validation.statuscontinua"passed". As verificações obrigatórias de fato passaram, e é por isso que a cena foi entregue.objectionspode estar vazio. Uma recusa que não apontou nada específico continua sendo uma recusa, então contar os avisosSCENE_REVIEW_REFUSEDnão a detecta.- As objeções sob
"unavailable"não são o veredito. Elas vêm de lotes de revisão que responderam antes de um deles falhar. Nesse caso, uma lista vazia significa silêncio, não aprovação.
Cada objeção é { category, what, correction?, frames }. No veredito "unavailable", um aviso SCENE_REVIEW_UNAVAILABLE vem primeiro em validation.warnings. Uma recusa visual sozinha não faz mais o job falhar. SCENE_QUALITY_FAILED significa que uma verificação obrigatória falhou ou que o compilador recusou a receita. Veja Renderização 3D Pro para saber o que um resultado com falha desse tipo mantém.
Entregas e arquivos
Estes métodos leem arquivos que uma execução já entregou. Eles nunca iniciam uma renderização. Toda leitura verifica de novo o seu acesso à entrega e à origem dela, mesmo depois que a revisão de origem foi excluída.
getDelivery(jobId)
Lê o registro de uma entrega (GET /v1/3d-scene/deliveries/:jobId): o sourceKind dela, a revisão de origem exata e os arquivos que ela fixou.
getDelivery(jobId: string): Promise<Scene3DDelivery>Prop
Type
const delivery = await client.scene3d.getDelivery(jobId)
const stills = delivery.assets.filter((a) => a.kind === "shot-still")Aparecem quatro tipos de arquivo: validation-report em toda entrega, poster em toda entrega que não foi recusada, shot-still uma vez por tomada, cada um com o seu shotIndex, frame, width e height, e source-json só em uma entrega refused-authoring. sourceKind é retained-revision, job-output ou refused-authoring. Em uma entrega recusada, sceneRevisionId e sourcePlanSha256 são null e não há pôster, porque nada foi compilado.
deliveryAssetBytes(jobId, asset, options?)
Baixa um arquivo listado pela entrega, com autenticação nova e um limite de tamanho.
deliveryAssetBytes(jobId: string, asset: Scene3DDeliveryAsset, options?: { signal?: AbortSignal }): Promise<ArrayBuffer>Prop
Type
const bytes = await client.scene3d.deliveryAssetBytes(jobId, stills[0])retainedRecipe(jobId, options?)
Lê a receita que uma execução recusada da Renderização 3D Pro guardou, já interpretada, ou null quando não há nenhuma. A receita de uma execução recusada nunca foi compilada, então não há revisão de cena, pôster nem arquivo-fonte; a receita é o que ela deixa para trás.
retainedRecipe(jobId: string, options?: { signal?: AbortSignal }): Promise<unknown | null>Prop
Type
const recipe = await client.scene3d.retainedRecipe(jobId)- Exige acesso de edição ao workflow do job. Um leitor com menos acesso nem chega a ver a receita, então a resposta é
null, não um erro. - O job com falha diz se vale a pena pedir. O
validation.sourceRetaineddele étruequando uma receita foi guardada. - É evidência, não entrada. Uma execução recusada não publicou nenhuma revisão, então você não pode executá-la de novo a partir da receita. Leia a receita para ver o que foi tentado e melhorar o próximo prompt. A leitura não custa créditos.
assetBytes(revisionId, asset, options?)
Baixa um arquivo de uma revisão de cena guardada: um modelo GLB, uma trilha de câmera, o pôster ou o relatório de validação. Passe o descritor exato dessa revisão. O SDK limita o download ao tamanho declarado, e o renderizador de cenas também verifica o hash SHA-256.
assetBytes(revisionId: string, asset: Scene3DAssetRef, options?: { signal?: AbortSignal }): Promise<ArrayBuffer>Prop
Type
const glb = await client.scene3d.assetBytes(scenePlan.revisionId, glbAsset)sourceBytes(revisionId, options?)
Baixa o arquivo-fonte nativo de uma revisão, como um arquivo .blend, com uma autorização própria. Exige o mesmo acesso de edição que uma receita guardada. Um arquivo nativo só está disponível quando representa exatamente aquela revisão aceita.
sourceBytes(revisionId: string, options?: { signal?: AbortSignal }): Promise<ArrayBuffer>Prop
Type
const blend = await client.scene3d.sourceBytes(revisionId)Os dois métodos de bytes usam credenciais novas, respeitam o cancelamento e lançam os erros tipados de sempre.
Perguntas frequentes
Páginas relacionadas
Gerar cena 3D
Renderização 3D Pro
Incorporar o viewport de cena 3D
Cenas 3D
Cenas 3D
Última atualização
Edição
Edite podcasts e vídeos longos em TypeScript. Detecte silêncio, sincronize gravações, planeje cortes a partir de uma transcrição e renderize uma EDL.
Personagens
Crie personagens, gere candidatos a retrato, aprove um deles e adicione expressões, poses e clipes de movimento em TypeScript com client.characters.