英文:
WebGPU. How to draw the Triangle Strip with different color for each Triangle?
问题
第一个三角形必须是红色,
第二个三角形必须是绿色。
但它们都是绿色(((
如何在 'triangle-strip' 基本拓扑中为每个子三角形设置不同的颜色?
我的最终目标是:在 'triangle-strip' 模式下,在鼠标点击点创建新的三角形并设置新的颜色。
这是我用于简化的两个三角形的代码:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-css -->
body{ background-color: #000 }
canvas{ display: block; width: 600px; height: 400px; outline: 1px solid #666 }
<!-- language: lang-html -->
<canvas width=900 height=600></canvas>
<script type="module">
let C = document.querySelector('canvas').getContext('webgpu'),
code=`
var<private> fi: i32; // fragment_index ( current triangle )
@vertex
fn vs( @builtin(vertex_index) vi: u32 ) -> @builtin(position) vec4f {
if(vi<3){ fi = 1;
var T = array<vec2f, 3>( vec2f(0,0), vec2f(.4,.7), vec2f(.8,0) );
return vec4f(T[vi],0,1);
};
fi = 2;
return vec4f(.6,-.5,0,1);
}
@fragment
fn fs() -> @location(0) vec4f {
if(fi == 1){ return vec4f(.7,.2,.2,.5); }; // color for 1st triangle 🌆;
return vec4f(.3,.6,.4,.5); // color for 2nd triangle
}`,
format = `bgra8unorm`,
adapter = await navigator.gpu.requestAdapter(),
device = await adapter.requestDevice(),
Q = device.queue,
A = {loadOp: 'clear', storeOp: 'store'}, // Attachments
O = {colorAttachments: [ A ]}, // Render Pass Descriptor
E, R,
module = device.createShaderModule({ code }),
P = device.createRenderPipeline({ layout: 'auto', primitive: { topology: 'triangle-strip' },
vertex: { module, entryPoint: 'vs', },
fragment: { module, entryPoint: 'fs', targets: [{ format }] }
});
C.configure({ device, format });
function F(){
A.view = C.getCurrentTexture().createView();
E = device.createCommandEncoder();
R = E.beginRenderPass(O);
R.setPipeline(P);
R.draw(4);
R.end();
Q.submit([E.finish()]);
requestAnimationFrame(F)
}
F()
</script>
<!-- end snippet -->
希望这对你有所帮助!
英文:
The first triangle must be RED,
the second triangle must be GREEN.
But both are GREEN (((
How to set different colors for each sub-triangle in 'triangle-strip' primitive topology ?
My final goal is: Creating new triangles with new colors at mouse click point in 'triangle-strip' mode.
This is my code for 2 triangles for simplicity:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-css -->
body{ background-color: #000 }
canvas{ display: block; width: 600px; height: 400px; outline: 1px solid #666 }
<!-- language: lang-html -->
<canvas width=900 height=600></canvas>
<script type="module">
let C = document.querySelector('canvas').getContext(`webgpu`),
code=`
var<private> fi: i32; // fragment_index ( current triangle )
@vertex
fn vs( @builtin(vertex_index) vi: u32 ) -> @builtin(position) vec4f {
if(vi<3){ fi = 1;
var T = array<vec2f, 3>( vec2f(0,0), vec2f(.4,.7), vec2f(.8,0) );
return vec4f(T[vi],0,1);
};
fi = 2;
return vec4f(.6,-.5,0,1);
}
@fragment
fn fs() -> @location(0) vec4f {
if(fi == 1){ return vec4f(.7,.2,.2,.5); }; // color for 1st triangle 🔺
return vec4f(.3,.6,.4,.5); // color for 2nd triangle
}`,
format = `bgra8unorm`,
adapter = await navigator.gpu.requestAdapter(),
device = await adapter.requestDevice(),
Q = device.queue,
A = {loadOp: `clear`, storeOp: `store`}, // Attachments
O = {colorAttachments: [ A ]}, // Render Pass Descriptor
E, R,
module = device.createShaderModule({ code }),
P = device.createRenderPipeline({ layout: `auto`, primitive: { topology: `triangle-strip` },
vertex: { module, entryPoint: `vs`, },
fragment: { module, entryPoint: `fs`, targets: [{ format }] }
});
C.configure({ device, format });
function F(){
A.view = C.getCurrentTexture().createView();
E = device.createCommandEncoder();
R = E.beginRenderPass(O);
R.setPipeline(P);
R.draw(4);
R.end();
Q.submit([E.finish()]);
requestAnimationFrame(F)
}
F()
</script>
<!-- end snippet -->
答案1
得分: 1
我不认为 var<private> fi: i32
正在执行你认为它在执行的操作。
顶点着色器和片段着色器没有共享的部分。你可以将它们视为完全独立的。你的顶点着色器是:
var<private> fi: i32;
@vertex
fn vs(...) -> ...
而你的片段着色器是:
var<private> fi: i32;
@fragment
fn fs(...) -> ...
fi
变量并没有被共享。
要从顶点着色器传递数据到片段着色器,你需要使用跨阶段变量。
因此,下面我将 fi
更改为一个跨阶段变量,将其放入一个结构体中,并从顶点着色器返回该结构体。需要注意的是,就像我上面说的,片段着色器和顶点着色器并不共享结构体中的实际数据。数据是通过 @location(0)
连接的,而不是通过结构体本身。
此外,跨阶段变量通常会被插值处理。你可以通过添加 @interpolate(flat)
来关闭插值,这样,传递到片段着色器的值将是三角形的第一个顶点的值。在这种情况下,第一个三角形的第一个顶点是顶点 0。第二个三角形的第一个顶点是顶点 1。
英文:
I don't think var<private> fi: i32
is doing what you think it's doing.
vertex shaders and fragment shaders share nothing. You can consider them entirely separate. Your vertex shader is
var<private> fi: i32;
@vertex
fn vs(...) -> ...
and your fragment shader is
var<private> fi: i32;
@fragment
fn fs(...) -> ...
The fi
variable is not shared.
To pass data from a vertex shader to a fragment shader you need to use inter-stage variables
So, below I changed fi
to an inter-stage variable by putting it a struct, returning that struct from the vertex shader. It's important to note, just like I said above, the fragment shader and vertex shader are not sharing the actual data in the struct. The data is connected by @location(0)
not by the struct itself.
Further, inter-stage variables normally get interpolated. You can turn off the interpolation by adding @interpolate(flat)
in which case, the value passed to the fragment shader will be the value of the 1st vertex of the triangle. In this case the first vertex of the first triangle is vertex 0. The first vertex of the 2nd triangle is vertex 1
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-css -->
body{ background-color: #000 }
canvas{ display: block; width: 600px; height: 400px; outline: 1px solid #666 }
<!-- language: lang-html -->
<canvas width=900 height=600></canvas>
<script type="module">
let C = document.querySelector('canvas').getContext(`webgpu`),
code=`
struct VSOut {
@builtin(position) pos: vec4f,
@location(0) @interpolate(flat) fi: i32,
};
@vertex
fn vs( @builtin(vertex_index) vi: u32 ) -> VSOut {
// inter-stage variables are interpolated. In flat interpolation mode,
// the values passed to the fragment shader are from the "provoking vertex"
// which is the value set on the 1st vertex of the triangle
var vsOut: VSOut;
vsOut.fi = 1;
if (vi > 0) {
vsOut.fi = 2;
}
if(vi<3){
var T = array<vec2f, 3>( vec2f(0,0), vec2f(.4,.7), vec2f(.8,0) );
vsOut.pos = vec4f(T[vi],0,1);
return vsOut;
};
vsOut.pos = vec4f(.6,-.5,0,1);
return vsOut;
}
@fragment
fn fs(vsOut: VSOut) -> @location(0) vec4f {
if(vsOut.fi == 1){ return vec4f(.7,.2,.2,.5); }; // color for 1st triangle 🔺
return vec4f(.3,.6,.4,.5); // color for 2nd triangle
}`,
format = `bgra8unorm`,
adapter = await navigator.gpu.requestAdapter(),
device = await adapter.requestDevice(),
Q = device.queue,
A = {loadOp: `clear`, storeOp: `store`}, // Attachments
O = {colorAttachments: [ A ]}, // Render Pass Descriptor
E, R,
module = device.createShaderModule({ code }),
P = device.createRenderPipeline({ layout: `auto`, primitive: { topology: `triangle-strip` },
vertex: { module, entryPoint: `vs`, },
fragment: { module, entryPoint: `fs`, targets: [{ format }] }
});
C.configure({ device, format });
function F(){
A.view = C.getCurrentTexture().createView();
E = device.createCommandEncoder();
R = E.beginRenderPass(O);
R.setPipeline(P);
R.draw(4);
R.end();
Q.submit([E.finish()]);
requestAnimationFrame(F)
}
F()
</script>
<!-- end snippet -->
with blending
<!-- begin snippet: js hide: true console: true babel: false -->
<!-- language: lang-css -->
body{ background-color: #000 }
canvas{ display: block; width: 600px; height: 400px; outline: 1px solid #666 }
<!-- language: lang-html -->
<canvas width=900 height=600></canvas>
<script type="module">
let C = document.querySelector('canvas').getContext(`webgpu`),
code=`
struct VSOut {
@builtin(position) pos: vec4f,
@location(0) @interpolate(flat) fi: i32,
};
@vertex
fn vs( @builtin(vertex_index) vi: u32 ) -> VSOut {
// inter-stage variables are interpolated. In flat interpolation mode,
// the values passed to the fragment shader are from the "provoking vertex"
// which is the value set on the 1st vertex of the triangle
var vsOut: VSOut;
vsOut.fi = 1;
if (vi > 0) {
vsOut.fi = 2;
}
if(vi<3){
var T = array<vec2f, 3>( vec2f(0,0), vec2f(.4,.7), vec2f(.8,0) );
vsOut.pos = vec4f(T[vi],0,1);
return vsOut;
};
vsOut.pos = vec4f(.6,-.5,0,1);
return vsOut;
}
@fragment
fn fs(vsOut: VSOut) -> @location(0) vec4f {
if(vsOut.fi == 1){ return vec4f(.7,.2,.2,.5); }; // color for 1st triangle 🔺
return vec4f(.3,.6,.4,.5); // color for 2nd triangle
}`,
format = `bgra8unorm`,
adapter = await navigator.gpu.requestAdapter(),
device = await adapter.requestDevice(),
Q = device.queue,
A = {loadOp: `clear`, storeOp: `store`}, // Attachments
O = {colorAttachments: [ A ]}, // Render Pass Descriptor
E, R,
module = device.createShaderModule({ code }),
P = device.createRenderPipeline({ layout: `auto`, primitive: { topology: `triangle-strip` },
vertex: { module, entryPoint: `vs`, },
fragment: { module, entryPoint: `fs`, targets: [{ format, blend: {
color: {
srcFactor: 'one',
dstFactor: 'one-minus-src-alpha',
operation: 'add',
},
alpha: {
srcFactor: 'one',
dstFactor: 'one-minus-src-alpha',
operation: 'add',
},
}, }] }
});
C.configure({ device, format });
function F(){
A.view = C.getCurrentTexture().createView();
E = device.createCommandEncoder();
R = E.beginRenderPass(O);
R.setPipeline(P);
R.draw(4);
R.end();
Q.submit([E.finish()]);
requestAnimationFrame(F)
}
F()
</script>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论