Forge 查看器:带文本的 3D 标记
Forge viewer: 3D markups with text
我们正在尝试在 3D 模型中每个对象顶部的特定位置(右上角)显示标记。我们还希望在 3D 标记上呈现文本。这可能吗?如果是,我们将在它上面放置一个 post 处理着色器,这样它就不会在我们四处导航时隐藏在模型中的其他东西下面。
选项 2:
在 2D 中,无论是在 Forge 中还是在 HTML 中,这将是顶部带有文本的图像,在每一帧中,这些图像+文本的位置都必须更新以匹配 3D 对象的 2D 位置,这可能可以,但可能会滞后,这就是我们更愿意使用 3D 选项的原因 - 如果可能的话。
看看我最新的PointCloud Markup demo for an example of a custom shader using a dynamic texture: High-Performance 3D markups with PointCloud in the Forge Viewer。
您可以使用类似的方法生成包含标签的纹理...
createShader (options) {
// Vertex Shader code
const vertexShader = options.vertexShader || `
attribute float pointSize;
attribute vec4 color;
varying vec4 vColor;
void main() {
vec4 vPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * vPosition;
gl_PointSize = pointSize;
vColor = color;
}
`
// Fragment Shader code
const fragmentShader = options.fragmentShader || `
uniform sampler2D texture;
varying vec4 vColor;
void main() {
vec4 tex = texture2D(texture, gl_PointCoord);
if (tex.a < 0.2) discard;
if (vColor.a == 0.0) {
gl_FragColor = vec4(tex.r, tex.g, tex.b, tex.a);
} else {
gl_FragColor = vColor;
}
}
`
const tex = options.texture || defaultTex
// Shader material parameters
const shaderParams = options.shaderParams || {
side: THREE.DoubleSide,
depthWrite: false,
depthTest: false,
fragmentShader,
vertexShader,
opacity: 0.5,
attributes: {
pointSize: {
type: 'f',
value: []
},
color: {
type: 'v4',
value: []
}
},
uniforms: {
texture: {
value: THREE.ImageUtils.loadTexture(tex),
type: 't'
}
}
}
// creates shader material
const material =
new THREE.ShaderMaterial(
shaderParams)
const generateTexture = (size, radius) => {
const pixels = []
for (let u = 0; u < size; ++u) {
for (let v = 0; v < size ; ++v) {
const dist = Math.sqrt(
(u/size - 0.5) * (u/size - 0.5) +
(v/size - 0.5) * (v/size - 0.5))
if (dist < 0.1) {
pixels.push(0xff, 0x00, 0x00, 0xff)
} else if (dist < (radius - 0.05)) {
pixels.push(0xff, 0x00, 0x00, 0x00)
} else if (dist < radius) {
pixels.push(0xff, 0x00, 0x00, 0xff)
} else {
pixels.push(0x00, 0x00, 0x00, 0x00)
}
}
}
const dataTexture = new THREE.DataTexture (
Uint8Array.from (pixels),
size, size,
THREE.RGBAFormat,
THREE.UnsignedByteType,
THREE.UVMapping
)
dataTexture.minFilter = THREE.LinearMipMapLinearFilter
dataTexture.magFilter = THREE.LinearFilter // THREE.NearestFilter
dataTexture.needsUpdate = true
return dataTexture
}
const stopwatch = new Stopwatch()
let radius = 0.0
return {
setTexture: (tex) => {
const {texture} = shaderParams.uniforms
texture.value = THREE.ImageUtils.loadTexture(tex)
texture.needsUpdate = true
},
update: () => {
const dt = stopwatch.getElapsedMs() * 0.001
radius += dt * 0.25
radius = radius > 0.5 ? 0.0 : radius
const {texture} = shaderParams.uniforms
texture.value = generateTexture(96, radius)
texture.needsUpdate = true
},
material
}
}
我们正在尝试在 3D 模型中每个对象顶部的特定位置(右上角)显示标记。我们还希望在 3D 标记上呈现文本。这可能吗?如果是,我们将在它上面放置一个 post 处理着色器,这样它就不会在我们四处导航时隐藏在模型中的其他东西下面。
选项 2: 在 2D 中,无论是在 Forge 中还是在 HTML 中,这将是顶部带有文本的图像,在每一帧中,这些图像+文本的位置都必须更新以匹配 3D 对象的 2D 位置,这可能可以,但可能会滞后,这就是我们更愿意使用 3D 选项的原因 - 如果可能的话。
看看我最新的PointCloud Markup demo for an example of a custom shader using a dynamic texture: High-Performance 3D markups with PointCloud in the Forge Viewer。
您可以使用类似的方法生成包含标签的纹理...
createShader (options) {
// Vertex Shader code
const vertexShader = options.vertexShader || `
attribute float pointSize;
attribute vec4 color;
varying vec4 vColor;
void main() {
vec4 vPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * vPosition;
gl_PointSize = pointSize;
vColor = color;
}
`
// Fragment Shader code
const fragmentShader = options.fragmentShader || `
uniform sampler2D texture;
varying vec4 vColor;
void main() {
vec4 tex = texture2D(texture, gl_PointCoord);
if (tex.a < 0.2) discard;
if (vColor.a == 0.0) {
gl_FragColor = vec4(tex.r, tex.g, tex.b, tex.a);
} else {
gl_FragColor = vColor;
}
}
`
const tex = options.texture || defaultTex
// Shader material parameters
const shaderParams = options.shaderParams || {
side: THREE.DoubleSide,
depthWrite: false,
depthTest: false,
fragmentShader,
vertexShader,
opacity: 0.5,
attributes: {
pointSize: {
type: 'f',
value: []
},
color: {
type: 'v4',
value: []
}
},
uniforms: {
texture: {
value: THREE.ImageUtils.loadTexture(tex),
type: 't'
}
}
}
// creates shader material
const material =
new THREE.ShaderMaterial(
shaderParams)
const generateTexture = (size, radius) => {
const pixels = []
for (let u = 0; u < size; ++u) {
for (let v = 0; v < size ; ++v) {
const dist = Math.sqrt(
(u/size - 0.5) * (u/size - 0.5) +
(v/size - 0.5) * (v/size - 0.5))
if (dist < 0.1) {
pixels.push(0xff, 0x00, 0x00, 0xff)
} else if (dist < (radius - 0.05)) {
pixels.push(0xff, 0x00, 0x00, 0x00)
} else if (dist < radius) {
pixels.push(0xff, 0x00, 0x00, 0xff)
} else {
pixels.push(0x00, 0x00, 0x00, 0x00)
}
}
}
const dataTexture = new THREE.DataTexture (
Uint8Array.from (pixels),
size, size,
THREE.RGBAFormat,
THREE.UnsignedByteType,
THREE.UVMapping
)
dataTexture.minFilter = THREE.LinearMipMapLinearFilter
dataTexture.magFilter = THREE.LinearFilter // THREE.NearestFilter
dataTexture.needsUpdate = true
return dataTexture
}
const stopwatch = new Stopwatch()
let radius = 0.0
return {
setTexture: (tex) => {
const {texture} = shaderParams.uniforms
texture.value = THREE.ImageUtils.loadTexture(tex)
texture.needsUpdate = true
},
update: () => {
const dt = stopwatch.getElapsedMs() * 0.001
radius += dt * 0.25
radius = radius > 0.5 ? 0.0 : radius
const {texture} = shaderParams.uniforms
texture.value = generateTexture(96, radius)
texture.needsUpdate = true
},
material
}
}