23 halp_meta(name,
"Cubemap Composer")
24 halp_meta(category,
"Visuals/3D")
25 halp_meta(c_name,
"cubemap_composer")
26 halp_meta(description,
"Combine six face textures into a cubemap and scene skybox contribution.")
29 "https://ossia.io/score-docs/processes/cubemap-composer.html")
30 halp_meta(uuid,
"a7c3e8f1-5b2d-4a9e-8f3c-1d6e9b4a2c5f")
34 halp::texture_input<
"+X", halp::custom_variable_texture> pos_x;
35 halp::texture_input<
"-X", halp::custom_variable_texture> neg_x;
36 halp::texture_input<
"+Y", halp::custom_variable_texture> pos_y;
37 halp::texture_input<
"-Y", halp::custom_variable_texture> neg_y;
38 halp::texture_input<
"+Z", halp::custom_variable_texture> pos_z;
39 halp::texture_input<
"-Z", halp::custom_variable_texture> neg_z;
44 halp::gpu_cubemap_output<
"Cubemap"> cubemap;
49 halp_meta(name,
"Scene");
50 ossia::scene_spec scene;
65 QRhiTexture* m_cubemapTex{};
68 FaceFingerprint m_lastFaces[6]{};
69 std::shared_ptr<ossia::scene_state> m_sceneState;
70 int64_t m_sceneVersion{0};
71 void* m_lastPublishedHandle{};
82 m_cubemapTex->deleteLater();
83 m_cubemapTex =
nullptr;
105 auto checkFace = [&](
auto& tex) {
106 FaceFingerprint cur{tex.texture.width, tex.texture.height};
107 const bool sizeChanged
108 = (cur.width != m_lastFaces[faceIdx].width
109 || cur.height != m_lastFaces[faceIdx].height);
110 const bool contentChanged = tex.texture.changed;
111 if(sizeChanged || contentChanged)
113 m_lastFaces[faceIdx] = cur;
116 tex.texture.changed =
false;
118 if(tex.texture.bytes && tex.texture.width > 0 && tex.texture.height > 0)
120 int s = std::max(tex.texture.width, tex.texture.height);
121 maxSize = std::max(maxSize, s);
124 checkFace(inputs.pos_x);
125 checkFace(inputs.neg_x);
126 checkFace(inputs.pos_y);
127 checkFace(inputs.neg_y);
128 checkFace(inputs.pos_z);
129 checkFace(inputs.neg_z);
135 if(maxSize != m_faceSize)
139 m_cubemapTex->deleteLater();
140 m_cubemapTex =
nullptr;
142 m_faceSize = maxSize;
146 if(!m_cubemapTex && m_faceSize > 0)
148 auto& rhi = *renderer.state.rhi;
149 m_cubemapTex = rhi.newTexture(
150 QRhiTexture::RGBA8, QSize{m_faceSize, m_faceSize}, 1,
151 QRhiTexture::CubeMap | QRhiTexture::MipMapped
152 | QRhiTexture::UsedWithGenerateMips);
153 m_cubemapTex->create();
154 outputs.cubemap.texture.handle = m_cubemapTex;
162 m_sceneState = std::make_shared<ossia::scene_state>();
163 if(m_lastPublishedHandle != m_cubemapTex)
165 m_sceneState->environment = {};
166 m_sceneState->environment.skybox_texture.native_handle = m_cubemapTex;
167 m_lastPublishedHandle = m_cubemapTex;
169 m_sceneState->version = m_sceneVersion;
170 outputs.scene_out.scene.state = m_sceneState;
171 outputs.scene_out.dirty = ossia::scene_port::dirty_environment;
179 m_cubemapTex->deleteLater();
180 m_cubemapTex =
nullptr;
183 outputs.cubemap.texture.handle =
nullptr;
186 m_sceneState->environment = {};
187 m_lastPublishedHandle =
nullptr;
189 m_sceneState->version = m_sceneVersion;
190 outputs.scene_out.dirty = ossia::scene_port::dirty_environment;
194 void runInitialPasses(
204 bool anyUploaded =
false;
207 auto uploadFace = [&](
const auto& tex,
int layer) {
208 if(!tex.texture.bytes || tex.texture.width <= 0 || tex.texture.height <= 0)
213 tex.texture.bytes, tex.texture.width, tex.texture.height,
214 QImage::Format_RGBA8888);
216 if(img.width() != m_faceSize || img.height() != m_faceSize)
218 m_faceSize, m_faceSize, Qt::IgnoreAspectRatio,
219 Qt::SmoothTransformation);
221 img = img.convertToFormat(QImage::Format_RGBA8888);
223 QRhiTextureSubresourceUploadDescription subresDesc(img);
224 QRhiTextureUploadEntry entry(layer, 0, subresDesc);
225 QRhiTextureUploadDescription desc({entry});
226 res->uploadTexture(m_cubemapTex, desc);
230 uploadFace(inputs.pos_x, 0);
231 uploadFace(inputs.neg_x, 1);
232 uploadFace(inputs.pos_y, 2);
233 uploadFace(inputs.neg_y, 3);
234 uploadFace(inputs.pos_z, 4);
235 uploadFace(inputs.neg_z, 5);