You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GLSL光线步进轨道相机拖动状态变量重置问题求助

轨道相机GLSL着色器鼠标拖拽问题排查与修复

问题分析

你在Shadertoy中实现光线步进轨道相机时遇到以下问题:

  • 左键点击保存初始鼠标坐标时,startDraggingPos始终记录当前鼠标位置
  • 调试发现mainImage的第一个if分支持续触发,导致点击时屏幕变黑
  • isDragging变量被反复重置

核心原因是Shadertoy中的全局变量没有帧间持久性——每帧渲染时,isDragging、startDraggingPos这类全局变量都会被重新初始化,导致你无法用它们保存跨帧的拖拽状态。

原代码问题点

// Camera control
vec2 cameraAng = vec2(0.5, 0.5);
bool isDragging = false; // 每帧都会重置为false
vec2 startDraggingPos = vec2(-1); // 每帧都会重置为(-1,-1)

void mainImage(out vec4 c, vec2 p)
{
    vec2 uv = (gl_FragCoord.xy - 0.5*iResolution.xy) / iResolution.y;
    vec2 mouseUV = vec2(0.5);
    mouseUV = iMouse.xy/iResolution.xy;  // [0,1]

    // 因为isDragging每帧都是false,所以这个分支每帧都会触发
    if(iMouse.z > 0.0 && (iMouse.x > 0.0 || iMouse.y > 0.0) && !isDragging){
        isDragging = true;
        startDraggingPos = mouseUV;
        c = vec4(0.0,0.0, 0.0,1.0);
        return;
    }
    else if(iMouse.z < 0.0 || (iMouse.x <= 0.0 || iMouse.y <= 0.0)){
        isDragging = false;
    }

    if(isDragging){
        vec2 inc = (mouseUV - startDraggingPos) * 10.0;
        cameraAng +=  inc;
    }
    // ···
}

修复方案

利用Shadertoy提供的iMouse.w变量(鼠标按下第一帧为1.0,后续保持0.0直到释放)判断拖拽起始,同时通过Buffer通道保存跨帧状态(如相机角度)。

1. 基础修复(无需Buffer,仅实现拖拽时角度变化)

// Camera control
vec2 cameraAng = vec2(0.5, 0.5);
vec2 startDraggingPos = vec2(-1);

void mainImage(out vec4 c, vec2 p)
{
    vec2 uv = (gl_FragCoord.xy - 0.5*iResolution.xy) / iResolution.y;
    vec2 mouseUV = iMouse.xy / iResolution.xy;

    // 仅在鼠标按下的第一帧记录初始位置
    if(iMouse.z > 0.0 && iMouse.w > 0.0){
        startDraggingPos = mouseUV;
    }
    // 鼠标释放时重置初始位置标记
    else if(iMouse.z == 0.0){
        startDraggingPos = vec2(-1);
    }

    // 拖拽状态下更新相机角度
    if(iMouse.z > 0.0 && startDraggingPos.x != -1){
        vec2 inc = (mouseUV - startDraggingPos) * 10.0;
        // 这里如果需要保留角度,需用Buffer存储,否则每帧会重置为(0.5,0.5)
        cameraAng = vec2(0.5, 0.5) + inc;
    }

    // 光线步进渲染逻辑...
    // 移除原调试的return语句,避免屏幕变黑
    // ···
}

2. 持久化相机角度(使用Buffer通道)

如果需要让相机角度在拖拽停止后保持不变,必须用Buffer存储状态:

Buffer A 着色器(负责保存相机角度和初始拖拽位置)
void mainImage(out vec4 c, vec2 p)
{
    // 读取上一帧的相机角度和初始拖拽位置
    vec2 cameraAng = texture(iChannel0, vec2(0.5)).xy;
    vec2 startDragPos = texture(iChannel0, vec2(0.5)).zw;
    vec2 mouseUV = iMouse.xy / iResolution.xy;

    // 鼠标按下第一帧,记录初始位置
    if(iMouse.z > 0.0 && iMouse.w > 0.0){
        startDragPos = mouseUV;
    }
    // 拖拽中更新相机角度
    else if(iMouse.z > 0.0){
        vec2 inc = (mouseUV - startDragPos) * 10.0;
        cameraAng += inc;
    }

    // 保存状态到Buffer
    c = vec4(cameraAng, startDragPos);
}
主着色器(读取Buffer中的相机角度)
void mainImage(out vec4 c, vec2 p)
{
    vec2 uv = (gl_FragCoord.xy - 0.5*iResolution.xy) / iResolution.y;
    // 从Buffer读取持久化的相机角度
    vec2 cameraAng = texture(iChannel0, vec2(0.5)).xy;
    vec2 mouseUV = iMouse.xy / iResolution.xy;

    // 光线步进渲染逻辑,使用cameraAng计算相机射线
    // ···
}

关键知识点

  • Shadertoy的全局变量是每帧重新初始化的,无法保存跨帧状态
  • iMouse.w是判断鼠标按下起始帧的关键变量,避免重复记录初始位置
  • 跨帧状态(如相机角度)必须通过Buffer通道存储,才能在帧间保持

内容的提问来源于stack exchange,提问作者Daniel Zufrí Quesada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 04:37:51