p5.js 中消失的 3D 对象面
3D Object Faces Disappearing in p5.js
我正在尝试使用以下代码制作一个每边都有图案的 3D 盒子,但是当从某些角度观看时,当透过正面的透明部分观看时,背面会消失。我也想知道是否可以在每张脸上都有不同的图案?非常感谢!
let r = 10
let a = 0
let c = 20
let angle = 0
let art
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
art = createGraphics(800, 800)
}
function draw() {
background(0);
let x = r + c * cos(a)
let y = r + c * sin(a)
art.fill(r, a, c)
art.ellipse(x + 400, y + 400, 10, 10)
c += 0.2
a += 1.8
push()
texture(art)
rotateX(angle)
rotateY(angle)
rotateZ(angle)
box(400)
angle += 0.0003
pop()
orbitControl();
}
html, body { margin: 0; overflow: hidden; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
发生这种情况是因为在 WebGL 中,一旦绘制了一个像素,无论该像素的透明度如何,如果另一个三角形绘制到同一像素,但在更深的深度,它就会被丢弃 (我认为来自原始像素的 alpha 信息可能不再可用)。为了使透明度在 WebGL 中正常工作,有必要按深度顺序绘制所有三角形(从相机最远的开始)。即使这样,两个三角形相交也会有问题。
在你的情况下,因为你有许多完全透明的像素和其他完全不透明的像素,所以还有另一种解决方案:自定义片段着色器,如果纹理 alpha 低于某个阈值则丢弃像素。
const vert = `
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
attribute vec3 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
vTexCoord = aTexCoord;
vec4 viewModelPosition = uModelViewMatrix * vec4(aPosition, 1.0);
gl_Position = uProjectionMatrix * viewModelPosition;
}`;
const frag = `
precision mediump float;
// ranges from 0..1
varying vec2 vTexCoord;
uniform sampler2D uSampler;
void main() {
vec4 tex = texture2D(uSampler, vTexCoord);
if (tex.a < 0.05) {
discard;
}
gl_FragColor = tex;
}`;
let r = 10
let a = 0
let c = 20
let angle = 0
let art
let discardShader;
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
art = createGraphics(800, 800)
discardShader = createShader(vert, frag)
textureMode(NORMAL)
}
function draw() {
background(0);
let x = r + c * cos(a)
let y = r + c * sin(a)
art.fill(r, a, c)
art.ellipse(x + 400, y + 400, 10, 10)
c += 0.2
a += 1.8
push()
noStroke()
texture(art)
shader(discardShader)
rotateX(angle)
rotateY(angle)
rotateZ(angle)
box(400)
angle += 0.0003
pop()
orbitControl();
}
html,
body {
margin: 0;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
注意#1:使用 p5.js v1.4.1 很重要,因为在此之前有一个错误阻止用户着色器使用纹理。
注意#2:如果你的纹理有部分不透明度,那么这将不起作用,相反你会想要以正确的顺序分别渲染盒子的每个平面(最远离相机的第一个)。
我正在尝试使用以下代码制作一个每边都有图案的 3D 盒子,但是当从某些角度观看时,当透过正面的透明部分观看时,背面会消失。我也想知道是否可以在每张脸上都有不同的图案?非常感谢!
let r = 10
let a = 0
let c = 20
let angle = 0
let art
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
art = createGraphics(800, 800)
}
function draw() {
background(0);
let x = r + c * cos(a)
let y = r + c * sin(a)
art.fill(r, a, c)
art.ellipse(x + 400, y + 400, 10, 10)
c += 0.2
a += 1.8
push()
texture(art)
rotateX(angle)
rotateY(angle)
rotateZ(angle)
box(400)
angle += 0.0003
pop()
orbitControl();
}
html, body { margin: 0; overflow: hidden; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
发生这种情况是因为在 WebGL 中,一旦绘制了一个像素,无论该像素的透明度如何,如果另一个三角形绘制到同一像素,但在更深的深度,它就会被丢弃 (我认为来自原始像素的 alpha 信息可能不再可用)。为了使透明度在 WebGL 中正常工作,有必要按深度顺序绘制所有三角形(从相机最远的开始)。即使这样,两个三角形相交也会有问题。
在你的情况下,因为你有许多完全透明的像素和其他完全不透明的像素,所以还有另一种解决方案:自定义片段着色器,如果纹理 alpha 低于某个阈值则丢弃像素。
const vert = `
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
attribute vec3 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
vTexCoord = aTexCoord;
vec4 viewModelPosition = uModelViewMatrix * vec4(aPosition, 1.0);
gl_Position = uProjectionMatrix * viewModelPosition;
}`;
const frag = `
precision mediump float;
// ranges from 0..1
varying vec2 vTexCoord;
uniform sampler2D uSampler;
void main() {
vec4 tex = texture2D(uSampler, vTexCoord);
if (tex.a < 0.05) {
discard;
}
gl_FragColor = tex;
}`;
let r = 10
let a = 0
let c = 20
let angle = 0
let art
let discardShader;
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
art = createGraphics(800, 800)
discardShader = createShader(vert, frag)
textureMode(NORMAL)
}
function draw() {
background(0);
let x = r + c * cos(a)
let y = r + c * sin(a)
art.fill(r, a, c)
art.ellipse(x + 400, y + 400, 10, 10)
c += 0.2
a += 1.8
push()
noStroke()
texture(art)
shader(discardShader)
rotateX(angle)
rotateY(angle)
rotateZ(angle)
box(400)
angle += 0.0003
pop()
orbitControl();
}
html,
body {
margin: 0;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
注意#1:使用 p5.js v1.4.1 很重要,因为在此之前有一个错误阻止用户着色器使用纹理。
注意#2:如果你的纹理有部分不透明度,那么这将不起作用,相反你会想要以正确的顺序分别渲染盒子的每个平面(最远离相机的第一个)。