curl --request POST \
--url https://apis.viggle.ai/v1/scenes/generate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sessionId": "living-room-01",
"referenceBatchIds": [
"<string>"
],
"targetC2w": [
[
1,
0,
0,
0
],
[
0,
1,
0,
0
],
[
0,
0,
1,
0
],
[
0,
0,
0,
1
]
],
"projection": "perspective",
"fov": 80,
"seed": 1,
"spzOutputUrl": "<string>",
"outputUris": {
"spz": "<string>",
"preview": "<string>",
"panorama": "<string>"
}
}
'import requests
url = "https://apis.viggle.ai/v1/scenes/generate"
payload = {
"sessionId": "living-room-01",
"referenceBatchIds": ["<string>"],
"targetC2w": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
"projection": "perspective",
"fov": 80,
"seed": 1,
"spzOutputUrl": "<string>",
"outputUris": {
"spz": "<string>",
"preview": "<string>",
"panorama": "<string>"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
sessionId: 'living-room-01',
referenceBatchIds: ['<string>'],
targetC2w: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
projection: 'perspective',
fov: 80,
seed: 1,
spzOutputUrl: '<string>',
outputUris: {spz: '<string>', preview: '<string>', panorama: '<string>'}
})
};
fetch('https://apis.viggle.ai/v1/scenes/generate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://apis.viggle.ai/v1/scenes/generate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sessionId' => 'living-room-01',
'referenceBatchIds' => [
'<string>'
],
'targetC2w' => [
[
1,
0,
0,
0
],
[
0,
1,
0,
0
],
[
0,
0,
1,
0
],
[
0,
0,
0,
1
]
],
'projection' => 'perspective',
'fov' => 80,
'seed' => 1,
'spzOutputUrl' => '<string>',
'outputUris' => [
'spz' => '<string>',
'preview' => '<string>',
'panorama' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://apis.viggle.ai/v1/scenes/generate"
payload := strings.NewReader("{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"targetC2w\": [\n [\n 1,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 1,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 1,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 1\n ]\n ],\n \"projection\": \"perspective\",\n \"fov\": 80,\n \"seed\": 1,\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://apis.viggle.ai/v1/scenes/generate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"targetC2w\": [\n [\n 1,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 1,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 1,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 1\n ]\n ],\n \"projection\": \"perspective\",\n \"fov\": 80,\n \"seed\": 1,\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/scenes/generate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"targetC2w\": [\n [\n 1,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 1,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 1,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 1\n ]\n ],\n \"projection\": \"perspective\",\n \"fov\": 80,\n \"seed\": 1,\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"sessionId": "<string>",
"operation": "pano",
"status": "processing",
"createdAt": 123,
"completedAt": 123,
"result": {
"operation": "pano",
"sessionId": "<string>",
"spz": {
"url": "<string>"
},
"preview": {
"url": "<string>"
},
"panorama": {
"url": "<string>"
},
"outputBatch": {
"batchId": "<string>",
"createdAt": 123,
"manifest": {
"url": "<string>"
},
"kind": "initial",
"views": [
{
"index": 1,
"url": "<string>",
"c2w": [
[
1,
0,
0,
0
],
[
0,
1,
0,
0
],
[
0,
0,
1,
0
],
[
0,
0,
0,
1
]
],
"intrinsic": [
123
]
}
]
},
"referenceViewCount": 123,
"newViewCount": 123,
"seconds": {}
},
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}生成场景视图
从你选定的相机位姿生成场景的新图像,作为新的图像批次。
curl --request POST \
--url https://apis.viggle.ai/v1/scenes/generate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sessionId": "living-room-01",
"referenceBatchIds": [
"<string>"
],
"targetC2w": [
[
1,
0,
0,
0
],
[
0,
1,
0,
0
],
[
0,
0,
1,
0
],
[
0,
0,
0,
1
]
],
"projection": "perspective",
"fov": 80,
"seed": 1,
"spzOutputUrl": "<string>",
"outputUris": {
"spz": "<string>",
"preview": "<string>",
"panorama": "<string>"
}
}
'import requests
url = "https://apis.viggle.ai/v1/scenes/generate"
payload = {
"sessionId": "living-room-01",
"referenceBatchIds": ["<string>"],
"targetC2w": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
"projection": "perspective",
"fov": 80,
"seed": 1,
"spzOutputUrl": "<string>",
"outputUris": {
"spz": "<string>",
"preview": "<string>",
"panorama": "<string>"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
sessionId: 'living-room-01',
referenceBatchIds: ['<string>'],
targetC2w: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
projection: 'perspective',
fov: 80,
seed: 1,
spzOutputUrl: '<string>',
outputUris: {spz: '<string>', preview: '<string>', panorama: '<string>'}
})
};
fetch('https://apis.viggle.ai/v1/scenes/generate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://apis.viggle.ai/v1/scenes/generate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sessionId' => 'living-room-01',
'referenceBatchIds' => [
'<string>'
],
'targetC2w' => [
[
1,
0,
0,
0
],
[
0,
1,
0,
0
],
[
0,
0,
1,
0
],
[
0,
0,
0,
1
]
],
'projection' => 'perspective',
'fov' => 80,
'seed' => 1,
'spzOutputUrl' => '<string>',
'outputUris' => [
'spz' => '<string>',
'preview' => '<string>',
'panorama' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://apis.viggle.ai/v1/scenes/generate"
payload := strings.NewReader("{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"targetC2w\": [\n [\n 1,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 1,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 1,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 1\n ]\n ],\n \"projection\": \"perspective\",\n \"fov\": 80,\n \"seed\": 1,\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://apis.viggle.ai/v1/scenes/generate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"targetC2w\": [\n [\n 1,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 1,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 1,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 1\n ]\n ],\n \"projection\": \"perspective\",\n \"fov\": 80,\n \"seed\": 1,\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/scenes/generate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"targetC2w\": [\n [\n 1,\n 0,\n 0,\n 0\n ],\n [\n 0,\n 1,\n 0,\n 0\n ],\n [\n 0,\n 0,\n 1,\n 0\n ],\n [\n 0,\n 0,\n 0,\n 1\n ]\n ],\n \"projection\": \"perspective\",\n \"fov\": 80,\n \"seed\": 1,\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"sessionId": "<string>",
"operation": "pano",
"status": "processing",
"createdAt": 123,
"completedAt": 123,
"result": {
"operation": "pano",
"sessionId": "<string>",
"spz": {
"url": "<string>"
},
"preview": {
"url": "<string>"
},
"panorama": {
"url": "<string>"
},
"outputBatch": {
"batchId": "<string>",
"createdAt": 123,
"manifest": {
"url": "<string>"
},
"kind": "initial",
"views": [
{
"index": 1,
"url": "<string>",
"c2w": [
[
1,
0,
0,
0
],
[
0,
1,
0,
0
],
[
0,
0,
1,
0
],
[
0,
0,
0,
1
]
],
"intrinsic": [
123
]
}
]
},
"referenceViewCount": 123,
"newViewCount": 123,
"seconds": {}
},
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}referenceBatchIds 中列出的图像批次,渲染出从 targetC2w 看到的新图像,这些图像成为会话中一个新的 generated 批次。可以用它们补全现有视图没有覆盖到的场景部分,再把新的 batchId 连同之前的批次一起传给重建场景,得到更新后的 .spz。
接口是异步的:返回 processing 状态的场景任务,轮询直到任务结束。
请求参数
使用application/json,最大 1 MiB。不接受未知字段。
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
sessionId | string | 是 | — | 要扩展其场景的会话,见创建场景中的“会话”一节。 |
referenceBatchIds | string[] | 是 | — | 1–35 个本会话的批次 ID,即 result.outputBatch.batchId 中返回的值。小写 UUID,不能重复。 |
targetC2w | number[4][4] | 是 | — | 渲染所用的相机到世界矩阵(c2w),与视图的 c2w 处于同一坐标系。最后一行必须为 [0, 0, 0, 1]。 |
projection | string | 否 | perspective | perspective 生成普通相机图像,pano 生成位于 targetC2w 的 360° 全景图。 |
fov | number | 否 | 模型默认值 | 视场角,单位为度,20–140。 |
seed | integer | 否 | 1 | 0–4294967295。相同输入和 seed 会得到相同图像。 |
spzOutputUrl | string | 否 | — | 与所有场景操作一样接受此字段,见创建场景中的“上传到自己的存储”一节。 |
outputUris | object | 否 | — | 按文件指定你自己的上传地址:spz、preview、panorama。不能与 spzOutputUrl 同时使用。 |
targetC2w 最简单的方法,是从已有批次中某个视图的 c2w 出发,对其平移或旋转。相机离现有视图越近,生成的图像越一致。响应参数
返回200 OK 和 processing 状态的场景任务:
{
"id": "scn_0199f0c4-1b2c-7d3e-8f4a-5b6c7d8e9f0a.living-room-01",
"sessionId": "living-room-01",
"operation": "generate",
"status": "processing",
"createdAt": 1791856900000,
"completedAt": null,
"result": null,
"error": null
}
ready 后,result.outputBatch 即新的 generated 批次,views 中包含每张新图像及其相机,result.newViewCount 为新图像数量。result.spz 为 null——请运行重建场景把新视图并入场景。
常见错误
| 错误 | 原因 |
|---|---|
400 INVALID_REQUEST | 字段缺失、不合法或未知,例如 referenceBatchIds 为空、超过 35 个 ID 或有重复,或 targetC2w 不是最后一行为 [0, 0, 0, 1] 的 4 × 4 矩阵。 |
401 UNAUTHENTICATED | 缺少或无效的 API 密钥。 |
409 INVALID_REQUEST | 该会话已有任务处于 processing,见 error.details.running_task_id。 |
503 SERVICE_BUSY | 场景模型暂时不可用,可重试。 |
INVALID_REQUEST 失败。
示例
curl -X POST https://apis.viggle.ai/v1/scenes/generate \
-H "Authorization: Bearer $VIGGLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "living-room-01",
"referenceBatchIds": ["3f0a6c1e-8d2b-4b7a-9e5c-1a2b3c4d5e6f"],
"targetC2w": [[1, 0, 0, 0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
"projection": "perspective",
"fov": 75,
"seed": 7
}'
import os, requests
response = requests.post(
"https://apis.viggle.ai/v1/scenes/generate",
headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"},
json={
"sessionId": "living-room-01",
"referenceBatchIds": ["3f0a6c1e-8d2b-4b7a-9e5c-1a2b3c4d5e6f"],
"targetC2w": [[1, 0, 0, 0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
"projection": "perspective",
"fov": 75,
"seed": 7,
},
)
response.raise_for_status()
task = response.json()
const response = await fetch("https://apis.viggle.ai/v1/scenes/generate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VIGGLE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
sessionId: "living-room-01",
referenceBatchIds: ["3f0a6c1e-8d2b-4b7a-9e5c-1a2b3c4d5e6f"],
targetC2w: [[1, 0, 0, 0.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
projection: "perspective",
fov: 75,
seed: 7,
}),
});
const task = await response.json();
快速入门:场景模型
授权
服务端 SDK 使用项目 API 密钥,Remote MCP 使用 OAuth 访问令牌。不要在浏览器代码中暴露项目密钥。
请求头
可选的调用者自定义关联 ID,最长 128 字符。服务会在响应头返回实际使用的值,便于追踪和支持排查。
1 - 128可选来源标签,最长 128 字符,用于识别 SDK、集成、产品入口或内部工作流。
1 - 128请求体
POST /v1/scenes/generate 的请求体。spzOutputUrl 与 outputUris 不能同时使用。
调用方自定的会话 ID,按账户隔离。一个会话对应一个场景及其全部图像批次,同一时间只运行一个任务;已有任务 processing 时再提交会返回 409,error.details.running_task_id 为正在运行的任务。
1 - 128^[A-Za-z0-9_-]+$"living-room-01"
同一会话内的 1–35 个不重复批次 ID,即 result.outputBatch.batchId。格式正确但属于其他会话的 ID 会让任务以 INVALID_REQUEST 失败。
1 - 35 elements^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$4 × 4 相机到世界(camera-to-world)矩阵,按行写成 4 行、每行 4 个有限数值;最后一行必须为 [0, 0, 0, 1]。
4 elements4 elements[
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
]
perspective 生成普通相机视角图像,pano 在 targetC2w 处生成 360° 全景图。
perspective, pano 视场角(度)。不传或为 null 时使用模型默认值。
20 <= x <= 1400 <= x <= 4294967295等同于 outputUris.spz。
调用方自己的上传地址,Viggle 完成后用 PUT 把对应文件上传过去;值为 null 的项会被忽略。上传到这里的 .spz Viggle 不再保留,结果中的 spz.url 即该地址;预览图和全景图上传后 Viggle 仍保留一份,结果中链接指向 Viggle 的副本。每个地址必须是 http(s)、不含账号密码、且主机只解析到公网地址。
Show child attributes
Show child attributes
响应
场景任务已启动。
场景任务(以 scn_ 开头),所有 /v1/scenes 提交接口和 GET /v1/scenes/{task_id} 都返回它。ready、failed、cancelled 为终态。任务结束后约 72 小时内可查询。
任务 ID,格式为 scn_{runId}.{sessionId}。
custom-pano 任务也返回 pano。
pano, generate, reconstruct processing, ready, failed, cancelled 开始时间,Unix 毫秒。
结束时间,Unix 毫秒;processing 时为 null。
只在 ready 时有值。
Show child attributes
Show child attributes
只在 failed 时有值。code 为 INVALID_REQUEST(不可重试,模型拒绝了输入,例如引用了其他会话的批次)或 PROCESSING_FAILED(可重试)。
Show child attributes
Show child attributes

