Skip to content

Commit 7192f6d

Browse files
authored
fix: Always vflip cubemaps (#7)
Fixes #6 (not sure if it breaks other cubemaps)
1 parent 29e5695 commit 7192f6d

File tree

2 files changed

+53
-16
lines changed

2 files changed

+53
-16
lines changed

shadertoy/NodeEditor/PipelineEditor.cpp

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ static constexpr auto initialShader = R"(void mainImage( out vec4 fragColor, in
7979
}
8080
)";
8181

82-
static constexpr auto initialCubeMap = R"(void mainCubemap( out vec4 fragColor, in vec2 fragCoord, in vec3 rayOri, in vec3 rayDir )
82+
static constexpr auto initialCubeMap =
83+
R"(void mainCubemap( out vec4 fragColor, in vec2 fragCoord, in vec3 rayOri, in vec3 rayDir )
8384
{
8485
// Ray direction as color
8586
vec3 col = 0.5 + 0.5*rayDir;
@@ -894,10 +895,14 @@ std::unique_ptr<Pipeline> PipelineEditor::buildPipeline() {
894895
[&] { HelloImGui::Log(HelloImGui::LogLevel::Error, "Failed to compile shader %s", node->name.c_str()); });
895896
pipeline->addPass(dynamic_cast<EditorShader*>(node)->editor.getText(), node->type, target, std::move(channels),
896897
node == sinkNode);
897-
if(target.front().t1)
898-
textureMap.emplace(node,
899-
DoubleBufferedTex{ target.front().t1->getTexture(), target.front().t2->getTexture(),
900-
node->type == NodeType::CubeMap ? TexType::CubeMap : TexType::Tex2D });
898+
899+
if(target.front().t1) {
900+
auto texType = node->type == NodeType::CubeMap ? TexType::CubeMap : TexType::Tex2D;
901+
902+
textureMap.emplace(
903+
node, DoubleBufferedTex{ target.front().t1->getTexture(), target.front().t2->getTexture(), texType });
904+
}
905+
901906
break;
902907
}
903908
case NodeClass::LastFrame: {
@@ -1579,18 +1584,21 @@ void PipelineEditor::loadFromShaderToy(const std::string& path) {
15791584
return &texture;
15801585
};
15811586
std::unordered_set<std::string> passIds;
1587+
// Look at any index.html at EffectPass.prototype.NewTexture if(assetID_to_cubemapBuferId)
15821588
const auto isDynamicCubeMap = [&](nlohmann::json& tex) {
15831589
const auto id = tex.at("id").get<std::string>();
1584-
return passIds.count(id) != 0;
1590+
return id == "4dX3Rr";
15851591
};
15861592
std::string common;
15871593
for(auto& pass : renderPasses) {
15881594
if(pass.at("name").get<std::string>().empty()) {
15891595
pass.at("name") = generateUniqueName(pass.at("type").get<std::string>());
15901596
}
1597+
15911598
if(pass.at("outputs").empty()) {
15921599
pass.at("outputs").push_back(nlohmann::json::object({ { "id", "tmp" + std::to_string(nextId()) } }));
15931600
}
1601+
15941602
passIds.insert(pass.at("outputs")[0].at("id").get<std::string>());
15951603
}
15961604
for(auto& pass : renderPasses) {
@@ -1601,7 +1609,9 @@ void PipelineEditor::loadFromShaderToy(const std::string& path) {
16011609
common = code + '\n';
16021610
} else if(type == "image" || type == "buffer" || type == "cubemap") {
16031611
const auto output = pass.at("outputs")[0].at("id").get<std::string>();
1604-
auto& node = spawnShader(type != "cubemap" ? NodeType::Image : NodeType::CubeMap);
1612+
auto nodeType = type == "cubemap" ? NodeType::CubeMap : NodeType::Image;
1613+
1614+
auto& node = spawnShader(nodeType);
16051615
node.editor.setText(code);
16061616
node.name = name;
16071617
newShaderNodes.emplace(output, &node);
@@ -1662,12 +1672,30 @@ void PipelineEditor::loadFromShaderToy(const std::string& path) {
16621672

16631673
for(auto& input : pass.at("inputs")) {
16641674
auto inputType = input.at("type").get<std::string>();
1665-
if(!(inputType == "buffer" || (inputType == "cubemap" && isDynamicCubeMap(input)))) {
1675+
bool dynamicCubeMap = inputType == "cubemap" && isDynamicCubeMap(input);
1676+
if(inputType != "buffer" && !dynamicCubeMap) {
16661677
continue;
16671678
}
16681679

16691680
auto channel = input.at("channel").get<uint32_t>();
16701681
auto inputId = input.at("id").get<std::string>();
1682+
1683+
// There is only one dynamic cube map in Shadertoy, so we can safely use the first one
1684+
if(dynamicCubeMap) {
1685+
for(auto& innerPass : renderPasses) {
1686+
if(innerPass.at("type").get<std::string>() != "cubemap") {
1687+
continue;
1688+
}
1689+
1690+
if(innerPass.at("outputs").empty())
1691+
continue;
1692+
1693+
inputId = innerPass.at("outputs")[0].at("id").get<std::string>();
1694+
channel = innerPass.at("outputs")[0].at("channel").get<uint32_t>();
1695+
break;
1696+
}
1697+
}
1698+
16711699
if(!newShaderNodes.count(inputId)) {
16721700
// Shadertoy doesn't fail when an input is missing, so we create a default dummy node
16731701
auto& inputNode = spawnShader(inputType != "cubemap" ? NodeType::Image : NodeType::CubeMap);

shadertoy/OpenGL.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,12 @@ constexpr Vec3 cubeMapVertexPos[8] = { { -1.0f, -1.0f, -1.0f }, { -1.0f, -1.0f,
102102
{ 1.0f, 1.0f, -1.0f }, { 1.0f, 1.0f, 1.0f } };
103103
// left-bottom left-top right-top right-bottom
104104
constexpr uint32_t cubeMapVertexIndex[6][4] = {
105-
{ 4, 6, 7, 5 }, // right
106-
{ 1, 3, 2, 0 }, // left
107-
{ 2, 3, 7, 6 }, // top
108-
{ 1, 0, 4, 5 }, // bottom
109-
{ 5, 7, 3, 1 }, // back
110-
{ 0, 2, 6, 4 } // front
105+
{ 5, 7, 6, 4 }, // +X (right face)
106+
{ 0, 2, 3, 1 }, // -X (left face)
107+
{ 0, 1, 5, 4 }, // +Y (top face)
108+
{ 3, 2, 6, 7 }, // -Y (bottom face)
109+
{ 1, 3, 7, 5 }, // +Z (back face)
110+
{ 4, 6, 2, 0 } // -Z (front face)
111111
};
112112

113113
struct VertexCubeMap final { // NOLINT(cppcoreguidelines-pro-type-member-init)
@@ -395,6 +395,15 @@ class RenderPass final {
395395
VertexCubeMap{ ImVec2{ base.x + size.x, base.y + size.y }, ImVec2{ uniformSize.x, 0.0 },
396396
cubeMapVertexPos[cubeMapVertexIndex[idx][3]] }, // right-bottom
397397
};
398+
399+
// For Y-flipped cubemaps, also flip Y coordinates of all faces
400+
// to match ShaderToy's UNPACK_FLIP_Y_WEBGL behavior
401+
// CubeMaps are always Y-flipped
402+
for(auto& [pos, coord, point] : vertices) {
403+
// Flip the 3D point's Y coordinate
404+
point[1] = -point[1];
405+
}
406+
398407
for(auto& [pos, coord, point] : vertices) {
399408
pos.x = pos.x / fbSize.x * 2.0f - 1.0f;
400409
pos.y = 1.0f - pos.y / fbSize.y * 2.0f;
@@ -578,8 +587,8 @@ class GLVolumeObject final : public TextureObject {
578587
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(std::log2(size)));
579588
GLenum internalFormat = channels == 1 ? GL_R8 : GL_RGBA;
580589
GLenum format = channels == 1 ? GL_RED : GL_RGBA;
581-
glTexImage3D(GL_TEXTURE_3D, 0, internalFormat, static_cast<GLsizei>(size), static_cast<GLsizei>(size), static_cast<GLsizei>(size),
582-
0, format, GL_UNSIGNED_BYTE, data); // R8G8B8A8
590+
glTexImage3D(GL_TEXTURE_3D, 0, internalFormat, static_cast<GLsizei>(size), static_cast<GLsizei>(size),
591+
static_cast<GLsizei>(size), 0, format, GL_UNSIGNED_BYTE, data); // R8G8B8A8
583592
glGenerateMipmap(GL_TEXTURE_3D);
584593
glBindTexture(GL_TEXTURE_3D, GL_NONE);
585594
}

0 commit comments

Comments
 (0)