一张画没有真实的前后距离,却可以让我们读出一条走廊、一排树,或桌面上前后的物体。它依靠一组相互支持的空间线索。
先辨认遮挡和相对大小,再理解透视如何把观看位置与画面联系起来。 本篇不要求你画复杂建筑;能指出画面为什么有远近、哪些线索需要条件,就足够了。
遮挡先告诉我们顺序
如果球挡住盒子的一角,我们通常会把球读成在前,盒子读成在后。被挡住的物体不需要完整露出来,画面仍可能被理解。
但遮挡主要给出前后顺序,不能直接告诉我们相隔几厘米。一张平面拼贴也可以制造相同的遮挡关系;我们在这里讨论的是图像提供了什么线索。
A 中的重叠让前后关系更清楚。B 则通过相同对象的大小变化提示距离。两种方法可以组合,但各自回答的问题不同。
更小不总是更远
在同一观看条件下,实际尺寸相同的物体,越远通常在画面里越小。例如同一种路灯沿街延伸,远处的灯柱显得更短。
如果实际尺寸未知,一枚靠近镜头的硬币也能比远处的大楼占据更大画面。不能把“画面里小”直接翻译成“现实里远”。比较熟悉物体、遮挡和地面位置,可以提供额外依据。
透视从观看位置开始
把眼前的画面想成一扇固定的窗。从眼睛向物体发出的直线与这扇窗相交,交点组成投影。观察者的位置变了,交点也会变。
在水平地面的常见场景中,视平线对应眼睛的高度。向远处延伸的一组同向平行线,在投影里可以朝同一个消失点靠拢。不同方向的平行线一般对应不同消失点;平行于画面的边,不会汇聚到画面中的有限点。
用盒子核对眼高
在下面的“单点透视”里,盒子的正面与画面平行,深度方向的边向同一消失点延伸。相机始终水平,只改变它的高度。
正在呈现知识画面
从遮挡到透视:三种空间线索遮挡显示前后关系;大小模式把同样尺寸的平面放到不同距离;透视模式固定水平观看方向,改变眼高,观察盒子与地面相对视平线的位置。平行于画面的边仍平行。
{"id":"space-and-viewpoint","title":"从遮挡到透视:三种空间线索","summary":"遮挡显示前后关系;大小模式把同样尺寸的平面放到不同距离;透视模式固定水平观看方向,改变眼高,观察盒子与地面相对视平线的位置。平行于画面的边仍平行。","height":680,"html":"<h2 data-i18n=\"heading\"></h2><p data-i18n=\"intro\"></p><svg class=\"scene\" viewBox=\"0 0 480 300\" role=\"img\" data-i18n-label=\"scene\" xmlns=\"http://www.w3.org/2000/svg\"><g id=\"world\"></g></svg><div class=\"controls\" role=\"group\" data-i18n-label=\"choices\"><button type=\"button\" data-mode=\"overlap\" aria-pressed=\"false\" data-i18n=\"overlap\"></button><button type=\"button\" data-mode=\"size\" aria-pressed=\"false\" data-i18n=\"size\"></button><button type=\"button\" data-mode=\"perspective\" aria-pressed=\"false\" data-i18n=\"perspective\"></button></div><label for=\"eye\" data-i18n=\"eye_label\"></label><input id=\"eye\" type=\"range\" min=\"100\" max=\"260\" value=\"160\" step=\"1\"><output id=\"eye-value\" for=\"eye\" class=\"readout\"></output><div class=\"status\"><p id=\"status\" role=\"status\" aria-live=\"polite\"></p></div><p class=\"readout\" data-i18n=\"note\"></p>","css":"\nbody { padding:22px; }\nh2 { font-size:20px; line-height:1.4; }\np { font-size:16px; line-height:1.65; }\n.scene { display:block; width:100%; height:auto; overflow:hidden; border-radius:4px; background:#e8e4dc; }\n.scene * { transition:none!important; }\n.controls { display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin:16px 0; }\n.controls button { flex:1 1 auto; min-height:44px; font-size:16px; }\nlabel { display:block; font-size:16px; margin:14px 0 4px; }\ninput[type=range] { width:100%; min-height:28px; }\n.readout { font-size:16px; color:var(--muted); }\n.status { display:grid; border-top:1px solid var(--rule); padding-top:12px; margin-top:16px; }\n.status p { grid-area:1/1; margin:0; }\n.status [aria-hidden=true] { visibility:hidden; }\n@media(max-width:480px) { body {padding:16px 12px;} h2 {font-size:19px;} }\n","js":"const $=s=>document.querySelector(s); const $$=s=>Array.from(document.querySelectorAll(s));\nfunction say(key){$('#status').textContent=viz.t(key);document.body.dataset.state=key;}\nfunction reserve(keys){keys.forEach(k=>{const p=document.createElement('p');p.textContent=viz.t(k);p.setAttribute('aria-hidden','true');$('.status').append(p);});}\nfunction selected(attr,value){$$('button['+attr+']').forEach(b=>b.setAttribute('aria-pressed',String(b.getAttribute(attr)===value)));}\n\nlet mode='perspective';const colors=['#8c6546','#576b73','#738162'];\nfunction project(x,y,z){return [240+220*x/z,130+220*(Number($('#eye').value)/100-y)/z];}\nfunction poly(points,fill){return `<polygon points=\"${points.map(p=>p.join(',')).join(' ')}\" fill=\"${fill}\"/>`;}\nfunction render(){let out='';const e=Number($('#eye').value)/100;\n if(mode==='overlap'){out='<rect x=\"0\" y=\"0\" width=\"480\" height=\"300\" fill=\"#e8e4dc\"/>';[0,1,2].forEach(i=>out+=`<rect x=\"${90+i*75}\" y=\"${60+i*35}\" width=\"150\" height=\"120\" rx=\"3\" fill=\"${colors[i]}\"/>`);}\n else if(mode==='size'){out='<rect x=\"0\" y=\"0\" width=\"480\" height=\"300\" fill=\"#e8e4dc\"/>';[7,5,3].forEach((z,i)=>{const a=project(-1.25,1,z),b=project(-.25,0,z);out+=`<rect x=\"${a[0]}\" y=\"${a[1]}\" width=\"${b[0]-a[0]}\" height=\"${b[1]-a[1]}\" fill=\"${colors[i]}\"/>`;});}\n else{out='<rect width=\"480\" height=\"300\" fill=\"#e8e4dc\"/><path d=\"M0 130 H480\" stroke=\"#9c6a25\" stroke-width=\"2\" stroke-dasharray=\"6 4\"/>';\n [-2,-1,0,1,2].forEach(x=>{const a=project(x,0,1.8),b=project(x,0,18);out+=`<path d=\"M${a} L${b} L240 130\" fill=\"none\" stroke=\"#afb0a7\"/>`;});\n [2,3,5,8,13].forEach(z=>{out+=`<path d=\"M${project(-2,0,z)} L${project(2,0,z)}\" stroke=\"#afb0a7\"/>`;});\n const x=-.6,z=4.2;out+=poly([project(x,0,z),project(x+1,0,z),project(x+1,1,z),project(x,1,z)],'#576b73');\n out+=poly([project(x,1,z),project(x+1,1,z),project(x+1,1,z+1),project(x,1,z+1)],'#82949a');\n out+='<circle cx=\"240\" cy=\"130\" r=\"5\" fill=\"#9c6a25\"/>';\n }\n $('#world').innerHTML=out;$('#eye').disabled=mode!=='perspective';$('#eye-value').textContent=viz.number(e,2);say('s_'+mode);selected('data-mode',mode);document.body.dataset.eye=e;\n}\nreserve(['s_overlap','s_size','s_perspective']);$('#eye').oninput=render;$$('button[data-mode]').forEach(b=>b.onclick=()=>{mode=b.dataset.mode;render();});render();\n","audio":false,"strings":{"choices":"空间线索","eye_label":"眼高 / 盒子高度","heading":"画面里的远近从哪里来?","intro":"先看遮挡,再比较相同物体的远近大小。进入透视后,提高眼高,观察盒子顶面,而不是只盯着消失点。","note":"固定焦距的理想针孔投影。滑杆单位是盒子高度;相机只升降,不俯仰。视平线固定在画面内是这组条件的结果。","overlap":"遮挡","perspective":"单点透视","s_overlap":"后画的形状遮住前面画的形状,提供前后顺序。单凭遮挡不能读出准确距离。","s_perspective":"视线保持水平,虚线是视平线。提高眼高可以看见更多盒子顶面;向深处延伸的同向边汇聚,水平横边保持平行。","s_size":"三个平面实际同宽同高,距相机分别为 7、5、3 个单位。更近的投影更大;大小比较需要实际尺寸这一条件。","scene":"遮挡、相对大小和单点透视的简化空间对照。","size":"相对大小"}}
眼睛与盒子顶面齐高时,上表面几乎压成一条线;把眼睛升高后,能看到更多顶面。实验里的视平线在画面内保持原位,是因为相机没有俯仰,并保持固定的画面投影设置。生活中把手机抬高又向下倾斜,则同时改变了两件事,不能用这里的单一变化直接套用。
地面朝远处延伸的线越来越靠近。横跨画面的平行线仍然平行,却因为距离不同而缩短。观察线的空间方向,比记住“所有线都往中间画”更可靠。
从走廊里读出三种空间线索
AI 生成观察素材。请用画面线索作具体比较;精确几何关系以文中的自绘图为准。
先暂时不画辅助线,找具体证据:左侧近处门洞更大,后面的门洞逐渐缩小;右侧柱子彼此遮挡;地面、墙面与顶面朝远处形成收束关系。它们共同帮助读出深度,任何一种都不必独自承担整个空间判断。
再沿左墙顶边、墙脚和右侧柱列的方向看过去。它们大致朝画面远处的同一区域收拢。不要把远处山的轮廓当作视平线,也不要只因为某条横线很长就称它为视平线。 视平线涉及观看高度与水平空间方向,山顶线是具体地形。
这张生成图适合寻找线索,不承担精确作图。下面换成明确构造的房间,把步骤完整走一遍。
完整示范:怎样搭出一个能继续放家具的房间?
A:先定观看条件。 本例选择相机水平、正对后墙。画一条视平线,在其上选取深度方向的消失点,再放入与画面平行的后墙矩形。将后墙四角向外延长到画框,墙、顶、地面的关系便建立起来。消失点决定方向关系,但它不是“画面重点必须放这里”的审美命令。
B:再给空间放入东西。 左墙加上几扇门。门的竖边仍竖直,沿墙向远处延伸的门顶、门底朝同一个消失点走。门越远,看起来越小,间距也受到透视压缩。不要在画面上机械地把每扇门画成等宽、等间距,那等于忽略了它们在不同深度。
C:用不一致的例子反查。 右侧这扇门有一条顶边朝错误方向走,和墙面所属的深度方向不一致。加砖缝、木纹和阴影都不能修正这条结构错误。先追踪边线属于哪一组空间方向,再改线;无需把所有线都拉向同一点。
把“等距”画出来:四块同样深的地砖
先规定地砖铺在水平地面,相机水平、正对这组砖;横跨画面的边保持水平,左右边朝 V 收拢。A 是一段长方形地面的透视外框:AB 在近处,CD 在远处。我们要把现实中的这段长度分成四等份,不能直接在纸面上等分。
B:连接 A→C、B→D,两条对角线交于 M。长方形的中心在透视投影中仍是这两条线的交点。过 M 画与 AB 平行的横线,就找到地面深度的一半。注意 M 在纸面上明显靠近远边;这正是距离压缩的结果。
C:对前后两块小长方形各重复一次“连对角线—过交点作横线”,得到四块现实等深的砖。新增两组细虚线是第二轮作图。D 却把屏幕上的间距画成一样:若坚持它是同样深的地砖,就与观看条件不符。
这套作图可转到正对的墙面:用对角线找矩形中心,再沿该平面的另一组边方向分割。两点透视时,那条分割线通常应朝对应消失点走,不能继续机械画水平线。这里解决的是重复间距;门的宽度、高度还须保持各自的方向关系。
把一个盒子转过来,为什么又要两个消失点?
刚才的后墙和盒子正面都与画面平行,因此正面横边保持水平,只有深度方向明显收拢。若让盒子在地面上转动,原来的两组水平边都会朝远处延伸,于是通常各有一个消失点。相机仍水平时,竖边保持竖直,这就是常见的两点透视。
两点可以远在画框外。强行把它们都挤在纸内,经常会使近角显得特别尖、两侧缩得特别快。真正需要检查的是观看角度与投影关系,而不是数一数图里画出了几个点。抬头拍高楼时竖边也会收束,那又改变了相机条件,不能沿用“竖线永远竖直”的说法。
不靠尺规,也能让空间更清楚
| 线索 | 可以说明什么 | 容易误用的地方 |
| 遮挡 | 谁在谁前面 | 只能粗略判断顺序,不能直接得出距离 |
| 已知同尺寸物体的大小变化 | 远近关系 | 不知道实物大小时,小并不必然远 |
| 纹理变密、间距压缩 | 表面向远处延伸 | 重复物仍需要符合共同的空间方向 |
| 远处对比与细节减少 | 常见大气条件下的距离感 | 空气、照明和材质会改变效果,室内不必照抄“远处更蓝” |
例如画雾中的山,不必像画房间那样到处加直线消失点。可以用前后遮挡、不同尺度、远处较弱的细节与反差组织层次。工具要对应对象的结构。
换成柱列:远处那根柱子出了什么问题?
三根柱子实际等高,立在同一水平面;相机水平,眼高恰好等于柱高。A 是基准,B 修改了一根柱子,C 给 A 加了一条参考线。B 能否继续描述同样条件?先指出图中证据,再说什么情况下 B 才可能成立。
先判断,再展开图解
B 把最远一根柱子的顶部抬到了共同视平线之上,底部位置却未变。柱高等于眼高时,三个顶部应都投到视平线上;A 和 C 符合此条件。B 可能表示那根柱子实际更高,或底座所在平面改变,但就不能继续声称“三根等高、同一地面”。先核对条件,再决定是否修改。
两个容易误判的地方
情境一: 一张照片里,近处小杯子比远处大水壶还小。这违反透视了吗?
展开参考思路
没有。近大远小的直接比较需要实际尺寸相同,或明确考虑实物尺寸的差别。投影大小同时取决于尺寸与距离。
情境二: 单点透视图里,盒子正面的上边和下边没有汇聚。需要改吗?
展开参考思路
如果正面平行于画面,就不需要。两条边在画面里仍平行;向深处延伸的另一组边才朝对应消失点靠拢。先判断它们属于哪一组空间方向。
可选实践:从齐桌面和高于桌面的位置看一个盒子。保持视线水平,比较可见顶面、遮挡和边线方向,再试着倾斜视线,留意条件改变了什么。
延伸阅读:Getty:从前景到背景、英国国家美术馆:消失点。