Skip to content

Commit 18a40d6

Browse files
committed
Add new CubeMapFlippedY type & fix vertex indicies
1 parent 949bd8e commit 18a40d6

File tree

3 files changed

+69
-20
lines changed

3 files changed

+69
-20
lines changed

shadertoy/NodeEditor/PipelineEditor.cpp

Lines changed: 49 additions & 10 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,16 @@ 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 || node->type == NodeType::CubeMapFlippedY) ?
901+
TexType::CubeMap :
902+
TexType::Tex2D;
903+
904+
textureMap.emplace(
905+
node, DoubleBufferedTex{ target.front().t1->getTexture(), target.front().t2->getTexture(), texType });
906+
}
907+
901908
break;
902909
}
903910
case NodeClass::LastFrame: {
@@ -906,7 +913,9 @@ std::unique_ptr<Pipeline> PipelineEditor::buildPipeline() {
906913
assert(target.t1 && target.t2);
907914
textureMap.emplace(node,
908915
DoubleBufferedTex{ target.t2->getTexture(), target.t1->getTexture(),
909-
ref->type == NodeType::CubeMap ? TexType::CubeMap : TexType::Tex2D });
916+
(ref->type == NodeType::CubeMap || ref->type == NodeType::CubeMapFlippedY) ?
917+
TexType::CubeMap :
918+
TexType::Tex2D });
910919
break;
911920
}
912921
case NodeClass::RenderOutput: {
@@ -1594,7 +1603,6 @@ void PipelineEditor::loadFromShaderToy(const std::string& path) {
15941603
pass.at("outputs").push_back(nlohmann::json::object({ { "id", "tmp" + std::to_string(nextId()) } }));
15951604
}
15961605

1597-
15981606
passIds.insert(pass.at("outputs")[0].at("id").get<std::string>());
15991607
}
16001608
for(auto& pass : renderPasses) {
@@ -1605,7 +1613,37 @@ void PipelineEditor::loadFromShaderToy(const std::string& path) {
16051613
common = code + '\n';
16061614
} else if(type == "image" || type == "buffer" || type == "cubemap") {
16071615
const auto output = pass.at("outputs")[0].at("id").get<std::string>();
1608-
auto& node = spawnShader(type != "cubemap" ? NodeType::Image : NodeType::CubeMap);
1616+
auto nodeType = NodeType::Image;
1617+
1618+
if(type == "cubemap") {
1619+
nodeType = NodeType::CubeMap;
1620+
// Check if the main image output using this CubeMap has flipped Y (see example
1621+
// https://www.shadertoy.com/view/WX3Xzs)
1622+
bool shouldBreak = false;
1623+
for(auto& r : renderPasses) {
1624+
if(shouldBreak)
1625+
break;
1626+
1627+
auto i = r.at("inputs");
1628+
if(r.at("type").get<std::string>() != "image")
1629+
continue;
1630+
if(i.empty())
1631+
continue;
1632+
1633+
for(auto& input : i) {
1634+
if(input.at("type").get<std::string>() != "cubemap" || !isDynamicCubeMap(input))
1635+
continue;
1636+
if(input["sampler"].at("vflip").get<std::string>() == "true") {
1637+
nodeType = NodeType::CubeMapFlippedY;
1638+
shouldBreak = true;
1639+
1640+
break;
1641+
}
1642+
}
1643+
}
1644+
}
1645+
1646+
auto& node = spawnShader(nodeType);
16091647
node.editor.setText(code);
16101648
node.name = name;
16111649
newShaderNodes.emplace(output, &node);
@@ -1666,7 +1704,8 @@ void PipelineEditor::loadFromShaderToy(const std::string& path) {
16661704

16671705
for(auto& input : pass.at("inputs")) {
16681706
auto inputType = input.at("type").get<std::string>();
1669-
if(!(inputType == "buffer" || (inputType == "cubemap" && isDynamicCubeMap(input)))) {
1707+
bool dynamicCubeMap = inputType == "cubemap" && isDynamicCubeMap(input);
1708+
if(inputType != "buffer" && !dynamicCubeMap) {
16701709
continue;
16711710
}
16721711

@@ -1688,7 +1727,7 @@ void PipelineEditor::loadFromShaderToy(const std::string& path) {
16881727
break;
16891728
}
16901729
}
1691-
1730+
16921731
if(!newShaderNodes.count(inputId)) {
16931732
// Shadertoy doesn't fail when an input is missing, so we create a default dummy node
16941733
auto& inputNode = spawnShader(inputType != "cubemap" ? NodeType::Image : NodeType::CubeMap);

shadertoy/OpenGL.cpp

Lines changed: 19 additions & 9 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)
@@ -265,7 +265,7 @@ class RenderPass final {
265265
: mBuffers{ std::move(buffer) }, mType{ type }, mChannels{ std::move(channels) } {
266266
std::string vertexSrc = shaderVersionDirective;
267267
std::string pixelSrc = shaderVersionDirective;
268-
if(type == NodeType::CubeMap) {
268+
if(type == NodeType::CubeMap || type == NodeType::CubeMapFlippedY) {
269269
vertexSrc += shaderCubeMapDef;
270270
pixelSrc += shaderCubeMapDef;
271271
}
@@ -352,9 +352,9 @@ class RenderPass final {
352352
ImVec2 size, base, fbSize, uniformSize;
353353
if(buffer) {
354354
base = { 0, 0 };
355-
size = mType == NodeType::CubeMap ? cubeMapSize : screenSize;
355+
size = (mType == NodeType::CubeMap || mType == NodeType::CubeMapFlippedY) ? cubeMapSize : screenSize;
356356
fbSize = size;
357-
uniformSize = mType == NodeType::CubeMap ? cubeMapSize : canvasSize;
357+
uniformSize = (mType == NodeType::CubeMap || mType == NodeType::CubeMapFlippedY) ? cubeMapSize : canvasSize;
358358
glViewport(0, 0, static_cast<GLsizei>(size.x), static_cast<GLsizei>(size.y));
359359
glDisable(GL_SCISSOR_TEST);
360360
buffer->bind(static_cast<uint32_t>(size.x), static_cast<uint32_t>(size.y));
@@ -395,6 +395,16 @@ 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+
if(mType == NodeType::CubeMapFlippedY) {
402+
for(auto& [pos, coord, point] : vertices) {
403+
// Flip the 3D point's Y coordinate
404+
point[1] = -point[1];
405+
}
406+
}
407+
398408
for(auto& [pos, coord, point] : vertices) {
399409
pos.x = pos.x / fbSize.x * 2.0f - 1.0f;
400410
pos.y = 1.0f - pos.y / fbSize.y * 2.0f;

shadertoy/STTF.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
SHADERTOY_NAMESPACE_BEGIN
2424

2525
enum class NodeClass { RenderOutput, SoundOutput, GLSLShader, Texture, CubeMap, LastFrame, Keyboard, Volume, Unknown };
26-
enum class NodeType { Image, CubeMap, Volume, Sound };
26+
enum class NodeType { Image, CubeMap, CubeMapFlippedY, Volume, Sound };
2727
enum class Filter { Mipmap, Linear, Nearest };
2828
enum class Wrap { Clamp, Repeat };
2929

0 commit comments

Comments
 (0)