对象的着色器线框 [英] Shader wireframe of an object
问题描述
我想看到一个没有对角线的对象的线框
目前,我根据顶点添加线,问题是在我有几个之后我遇到了严重的性能下降.
示例
这就是我使用它的方式:
const vertexShader = `不同的 vec2 vUv;无效主(){vUv = uv;gl_Position = 投影矩阵 * 模型视图矩阵 * vec4(position,1.0);}`const fragmentShader = `#version 150 兼容性在浮动漫射中平坦;在浮动镜面中平坦;在 vec3 edge_mask 中平坦;在 vec2 巴里;均匀浮动mesh_width = 1.0;统一 vec3 mesh_color = vec3(0.0, 0.0, 0.0);统一布尔照明 = 真;出 vec4 frag_color ;浮动边缘因素(){vec3 bary3 = vec3(bary.x, bary.y, 1.0 - bary.x - bary.y);vec3 d = fwidth(bary3);vec3 a3 = smoothstep(vec3(0.0, 0.0, 0.0), d * mesh_width, bary3);a3 = vec3(1.0, 1.0, 1.0) - edge_mask + edge_mask * a3;返回分钟(分钟(a3.x,a3.y),a3.z);}无效主(){float s = (lighting && gl_FrontFacing) ?1.0:-1.0;vec4 Kdiff = gl_FrontFacing ?gl_FrontMaterial.diffuse : gl_BackMaterial.diffuse;浮动 sdiffuse = s * 扩散;vec4 结果 = vec4(0.1, 0.1, 0.1, 1.0);如果 (sdiffuse > 0.0) {结果 += sdiffuse * Kdiff +高光 * gl_FrontMaterial.specular;}frag_color = (mesh_width != 0.0) ?mix(vec4(mesh_color, 1.0), result, edge_factor()) :结果;}`
...
const 制服 = {颜色: {值:新的 THREE.Vector4(0, 0, 1, 1),类型:'v4'}}const 材质 = 新的 THREE.ShaderMaterial({片段着色器:data.fragmentShader,顶点着色器:data.vertexShader,制服})this._viewer.impl.matman().addMaterial(data.name,材料,真实)const fragList = this._viewer.model.getFragmentList()this.toArray(fragIds).forEach((fragId) => {fragList.setMaterial(fragId, material)})
所以要实现这个着色器,正确的方法是基本上检查每两个顶点之间的角度,如果度数是 90 则画一条线?
如何从顶点着色器访问形状的所有顶点?
我如何告诉片段着色器在符合上述条件的两个顶点之间画一条线?(也保留其他所有内容的默认阴影)
我使用的是使用 Three.js rev 71 的 Autodesk 查看器.
//-- 顶点着色器 --精密中等浮点数;//从缓冲区输入属性 vec3 aPosition;属性 vec2 aBaryCoord;//跨像素内插的值并传递给片段着色器不同的 vec2 vBaryCoord;//制服统一 mat4 uModelMatrix;统一 mat4 uViewMatrix;统一 mat4 uProjMatrix;无效主(){vBaryCoord = aBaryCoord;gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(aPosition,1.0);}//---------------------//-- 片段着色器 --//这个着色器不执行任何光照精密中等浮点数;不同的 vec2 vBaryCoord;统一 vec3 uMeshColour;浮动边因子(){vec3 d = fwidth(vBaryCoord);vec3 a3 = smoothstep(vec3(0.0,0.0,0.0),d * 1.5,vBaryCoord);返回分钟(分钟(a3.x,a3.y),a3.z);}无效主(){gl_FragColor = vec4(uMeshColour,(1.0 - edgeFactor()) * 0.95);}//---------------------/*此代码未经测试,因此请谨慎对待想法取自http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/*/
I want to see a wireframe of an object without the diagonals like
Currently, I add lines according to the vertices, the problem is after I have several of those I experience a major performance degradation.
The examples here are either too new for my version of Three or don't work (I commented there about it).
So I want to try to implement a shader instead.
I tried to use this shader: https://stackoverflow.com/a/31610464/4279201 but it breaks the shape to parts and I'm getting WebGL errors.
That's how I use it:
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`
const fragmentShader = `
#version 150 compatibility
flat in float diffuse;
flat in float specular;
flat in vec3 edge_mask;
in vec2 bary;
uniform float mesh_width = 1.0;
uniform vec3 mesh_color = vec3(0.0, 0.0, 0.0);
uniform bool lighting = true;
out vec4 frag_color ;
float edge_factor(){
vec3 bary3 = vec3(bary.x, bary.y, 1.0 - bary.x - bary.y);
vec3 d = fwidth(bary3);
vec3 a3 = smoothstep(vec3(0.0, 0.0, 0.0), d * mesh_width, bary3);
a3 = vec3(1.0, 1.0, 1.0) - edge_mask + edge_mask * a3;
return min(min(a3.x, a3.y), a3.z);
}
void main() {
float s = (lighting && gl_FrontFacing) ? 1.0 : -1.0;
vec4 Kdiff = gl_FrontFacing ?
gl_FrontMaterial.diffuse : gl_BackMaterial.diffuse;
float sdiffuse = s * diffuse;
vec4 result = vec4(0.1, 0.1, 0.1, 1.0);
if (sdiffuse > 0.0) {
result += sdiffuse * Kdiff +
specular * gl_FrontMaterial.specular;
}
frag_color = (mesh_width != 0.0) ?
mix(vec4(mesh_color, 1.0), result, edge_factor()) :
result;
}`
...
const uniforms = {
color: {
value: new THREE.Vector4(0, 0, 1, 1),
type: 'v4'
}
}
const material = new THREE.ShaderMaterial({
fragmentShader: data.fragmentShader,
vertexShader: data.vertexShader,
uniforms
})
this._viewer.impl.matman().addMaterial(
data.name, material, true)
const fragList = this._viewer.model.getFragmentList()
this.toArray(fragIds).forEach((fragId) => {
fragList.setMaterial(fragId, material)
})
So to implement this shader, is the right approach would be to basically check the angle between every two vertices, and draw a line if the degree is 90?
How can I have access to all the vertices of the shape from the vertex shader?
And how can I tell the fragment shader to draw a line between two vertices that match the above condition? (also to leave the default shading for everything else as is)
I'm using Autodesk viewer that uses Three.js rev 71.
// -- Vertex Shader --
precision mediump float;
// Input from buffers
attribute vec3 aPosition;
attribute vec2 aBaryCoord;
// Value interpolated accross pixels and passed to the fragment shader
varying vec2 vBaryCoord;
// Uniforms
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;
void main() {
vBaryCoord = aBaryCoord;
gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(aPosition,1.0);
}
// ---------------------
// -- Fragment Shader --
// This shader doesn't perform any lighting
precision mediump float;
varying vec2 vBaryCoord;
uniform vec3 uMeshColour;
float edgeFactor() {
vec3 d = fwidth(vBaryCoord);
vec3 a3 = smoothstep(vec3(0.0,0.0,0.0),d * 1.5,vBaryCoord);
return min(min(a3.x,a3.y),a3.z);
}
void main() {
gl_FragColor = vec4(uMeshColour,(1.0 - edgeFactor()) * 0.95);
}
// ---------------------
/*
This code isn't tested so take it with a grain of salt
Idea taken from
http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/
*/
这篇关于对象的着色器线框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!