内置材质
WebGPU 引擎
本页全部内置材质在 render: { engine: "webgpu" } 时会自动切换为对应的 TSL 节点材质实现,创建参数与用法不变;运行期改值请统一用 material.uniforms.xxx.value(两种引擎通用)。⚠️ 同名属性存取器(如 mat.uSpeed = 3)在 webgl 下只有 shaderMaterial() 工厂生成的材质才有——FlowMaterial(含 createTextFlowMaterial/createRenderElementFlowMaterial)、AnimatorFrameMaterial、RadarMaterial;HolographicMaterial、FixedSizeMeshMaterial、createFlowGradientMaterial、ShadertoyMaterial、反射材质等在 webgl 下直接写同名属性会被静默忽略。另:webgpu 下 createReflectorShaderMesh 不支持 ignoreObjects/includeObjects(只告警,反射整个场景)。webgpu 引擎下请在 await app.whenReady() 之后再创建材质,详见 WebGPU 渲染引擎。
TextFlowMaterial 文本滚动材质
通过createTextFlowMaterial创建文本滚动材质
用法
垂直文本滚动效果
let geoW = 10, geoH = 10 / 2;
let geom = new THREE.PlaneGeometry(geoW, geoH);
let mat = vjmap3d.createTextFlowMaterial(app, {
geometryWidth: geoW,
geometryHeight: geoH,
flowDirection: "vertical",
flowSpeed: 0.03,
text: `春天是一年四季中最美丽的季节之一,也是最富有生机的季节。在这个季节里,大自然给我们带来了很多惊喜和愉悦。在这个季节里,我喜欢去公园里散步,欣赏那里的美景。
走进公园,你会看到一条小路蜿蜒伸向远方。小路两旁种满了各种各样的树木,有高大的梧桐树,还有低矮的桃树和梨树。它们长出了嫩绿的新叶,这些新叶在阳光下闪闪发光,仿佛在向人们报告春天的到来。`,
fill: "#FF1285",
font: "30px sans-serif",
padding: [5, 5, 5, 5],
backgroundColor: "#FFFE91",
lineHeight: 50,
width: 300,
overflow: "break"
});
let mesh = new THREE.Mesh(geom, mat);
mesh.position.set(0, 0, 0);
mesh.rotateY(Math.PI / 16);
app.scene.add(mesh);
水平文本滚动效果
let geoW2 = 20, geoH2 = 20 / 5;
let geom2 = new THREE.PlaneGeometry(geoW2, geoH2);
let mat2 = vjmap3d.createTextFlowMaterial(app, {
geometryWidth: geoW2,
geometryHeight: geoH2,
flowDirection: "horizon",
flowSpeed: 0.03,
text: `春天是一年四季中最美丽的季节之一,也是最富有生机的季节。在这个季节里,大自然给我们带来了很多惊喜和愉悦。在这个季节里,我喜欢去公园里散步,欣赏那里的美景。`,
fill: "#16417C",
font: "30px sans-serif",
padding: [5, 5, 5, 5],
backgroundColor: "#00ff00",
lineHeight: 50
});
let mesh2 = new THREE.Mesh(geom2, mat2);
mesh2.position.set(-5, 0, -10);
app.scene.add(mesh2);
示例
::: tabs
@tab 三维模式
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
// 垂直文本滚动
let geoW = 10, geoH = 10 / 2;
let geom = new THREE.PlaneGeometry(geoW, geoH);
let mat = vjmap3d.createTextFlowMaterial(app, {
geometryWidth: geoW,
geometryHeight: geoH,
flowDirection: "vertical",
flowSpeed: 0.03,
text: `春天是一年四季中最美丽的季节之一,也是最富有生机的季节。在这个季节里,大自然给我们带来了很多惊喜和愉悦。在这个季节里,我喜欢去公园里散步,欣赏那里的美景。
走进公园,你会看到一条小路蜿蜒伸向远方。小路两旁种满了各种各样的树木,有高大的梧桐树,还有低矮的桃树和梨树。它们长出了嫩绿的新叶,这些新叶在阳光下闪闪发光,仿佛在向人们报告春天的到来。
沿着小路往前走,你会看到一片盛开的花海。有各种各样的花朵,比如红色的玫瑰,紫色的薰衣草,黄色的向日葵等等。它们争奇斗艳,各自展示着自己的美丽。在这片花海里,你可以闻到各种各样的香味,让人心旷神怡,烦恼忧虑全都忘了。
在公园里还有一些人工建筑和设施。比如有一个小湖泊,湖里有几只鸭子在戏水,还有一些小鱼在游来游去。湖边有一座小亭子,供游客休息和观赏湖景。还有一些儿童游乐设施,比如秋千、滑梯、沙池等等,让孩子们尽情玩耍和欢笑。
春天是一个充满生机和希望的季节。在这个季节里,我们可以感受到大自然的神奇力量和无限魅力。春天是万物复苏的季节,在这个季节里我们可以看到大自然为我们描绘出一幅美丽画卷。让我们一起欣赏春天的美景吧!`,
fill: "#FF1285",
font: "30px sans-serif",
padding: [5, 5, 5, 5],
backgroundColor: "#FFFE91",
lineHeight: 50,
width: 300,
overflow: "break"
});
let mesh = new THREE.Mesh(geom, mat);
mesh.position.set(0, 0, 0);
mesh.rotateY(Math.PI / 16);
app.scene.add(mesh);
// 水平滚动文本
let geoW2 = 20, geoH2 = 20 / 5;
let geom2 = new THREE.PlaneGeometry(geoW2, geoH2);
let mat2 = vjmap3d.createTextFlowMaterial(app, {
geometryWidth: geoW2,
geometryHeight: geoH2,
flowDirection: "horizon",
flowSpeed: 0.03,
text: `春天是一年四季中最美丽的季节之一,也是最富有生机的季节。在这个季节里,大自然给我们带来了很多惊喜和愉悦。在这个季节里,我喜欢去公园里散步,欣赏那里的美景。`,
fill: "#16417C",
font: "30px sans-serif",
padding: [5, 5, 5, 5],
backgroundColor: "#00ff00",
lineHeight: 50
});
let mesh2 = new THREE.Mesh(geom2, mat2);
mesh2.position.set(-5, 0, -10);
app.scene.add(mesh2);
@tab 唯杰地图三维图层模式
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// 打开地图
let res = await svc.openMap({
mapid: env.exampleMapId, // 地图ID
// @ts-ignore
mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap.openMapLightStyle() // div为深色背景颜色时,这里也传深色背景样式
})
if (res.error) {
// 如果打开出错
showError(res.error)
return;
}
// 获取地图范围
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
// 根据地图范围建立几何投影坐标系
let prj = new vjmap.GeoProjection(mapBounds);
//
// 地图对象
let map = new vjmap.Map({
container: 'map', // DIV容器ID
style: svc.rasterStyle(), // 样式,这里是栅格样式
center: prj.toLngLat(mapBounds.center()), // 设置地图中心点
zoom: 2, // 设置地图缩放级别
pitch: 45,
antialias: true, // 反锯齿
renderWorldCopies: false // 不显示多屏地图
});
//
// 关联服务对象和投影对象
map.attach(svc, prj);
await map.onLoad();
//
// 创建3d图层
let mapLayer = new vjmap3d.MapThreeLayer(map, {
stat: {
show: true,
left: "0"
}
});
map.addLayer(new vjmap.ThreeLayer({ context: mapLayer }))
let app = mapLayer.app;
let mapW = vjmap3d.toDist(mapBounds.width())
// 垂直文本滚动
let geoW = mapW / 10, geoH = mapW / 20;
let geom = new THREE.PlaneGeometry(geoW, geoH);
let mat = vjmap3d.createTextFlowMaterial(app, {
geometryWidth: geoW,
geometryHeight: geoH,
flowDirection: "vertical",
flowSpeed: 0.03,
text: `春天是一年四季中最美丽的季节之一,也是最富有生机的季节。在这个季节里,大自然给我们带来了很多惊喜和愉悦。在这个季节里,我喜欢去公园里散步,欣赏那里的美景。
走进公园,你会看到一条小路蜿蜒伸向远方。小路两旁种满了各种各样的树木,有高大的梧桐树,还有低矮的桃树和梨树。它们长出了嫩绿的新叶,这些新叶在阳光下闪闪发光,仿佛在向人们报告春天的到来。
沿着小路往前走,你会看到一片盛开的花海。有各种各样的花朵,比如红色的玫瑰,紫色的薰衣草,黄色的向日葵等等。它们争奇斗艳,各自展示着自己的美丽。在这片花海里,你可以闻到各种各样的香味,让人心旷神怡,烦恼忧虑全都忘了。
在公园里还有一些人工建筑和设施。比如有一个小湖泊,湖里有几只鸭子在戏水,还有一些小鱼在游来游去。湖边有一座小亭子,供游客休息和观赏湖景。还有一些儿童游乐设施,比如秋千、滑梯、沙池等等,让孩子们尽情玩耍和欢笑。
春天是一个充满生机和希望的季节。在这个季节里,我们可以感受到大自然的神奇力量和无限魅力。春天是万物复苏的季节,在这个季节里我们可以看到大自然为我们描绘出一幅美丽画卷。让我们一起欣赏春天的美景吧!`,
fill: "#FF1285",
font: "30px sans-serif",
padding: [5, 5, 5, 5],
backgroundColor: "#FFFE91",
lineHeight: 50,
width: 300,
overflow: "break"
});
let mesh = new THREE.Mesh(geom, mat);
mesh.position.copy(vjmap3d.toWorld(mapBounds.center().toArray()));
mesh.rotateX( Math.PI / 2)
mesh.rotateY( Math.PI)
app.scene.add(mesh);
// 水平滚动文本
let geoW2 = mapW / 10, geoH2 = mapW / 50;
let geom2 = new THREE.PlaneGeometry(geoW2, geoH2);
let mat2 = vjmap3d.createTextFlowMaterial(app, {
geometryWidth: geoW2,
geometryHeight: geoH2,
flowDirection: "horizon",
flowSpeed: 0.03,
text: `春天是一年四季中最美丽的季节之一,也是最富有生机的季节。在这个季节里,大自然给我们带来了很多惊喜和愉悦。在这个季节里,我喜欢去公园里散步,欣赏那里的美景。`,
fill: "#16417C",
font: "30px sans-serif",
padding: [5, 5, 5, 5],
backgroundColor: "#00ff00",
lineHeight: 50
});
let mesh2 = new THREE.Mesh(geom2, mat2);
mesh2.position.copy(vjmap3d.toWorld(mapBounds.randomPoint().toArray()));
mesh2.rotateX( Math.PI / 2)
mesh2.rotateY( Math.PI)
app.scene.add(mesh2);
:::
AnimatorFrameMaterial 动画帧纹理材质
动画帧纹理材质AnimatorFrameMaterial根据一张动画帧精灵图组成的图片创建的纹理材质
用法
let texture = await vjmap3d.ResManager.loadTextureSync(env.assetsPath + "sprites/alien.png", true);
let mat = new vjmap3d.AnimatorFrameMaterial(
{
imageWidth: texture.source.data.width,
imageHeight: texture.source.data.height,
rowCount: 1,
colCount: 16,
//spriteCount: 16,
//spriteWidth: texture.source.data.width / 16,
//spriteHeight: texture.source.data.height,
curRunFrameCount: app.time.frameCount,
map: texture,
side: THREE.DoubleSide,
transparent: true
},
{ time: app.commonUniforms.time }
);
let geoW = 5, geoH = 5;
let geom = new THREE.PlaneGeometry(geoW, geoH);
let mesh = new THREE.Mesh(geom, mat);
mesh.position.set(1, 0, 1);
app.scene.add(mesh);
示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let texture = await vjmap3d.ResManager.loadTextureSync(env.assetsPath + "sprites/alien.png", true);
let mat = new vjmap3d.AnimatorFrameMaterial(
{
imageWidth: texture.source.data.width,
imageHeight: texture.source.data.height,
rowCount: 1,
colCount: 16,
//spriteCount: 16,
//spriteWidth: texture.source.data.width / 16,
//spriteHeight: texture.source.data.height,
curRunFrameCount: app.time.frameCount,
map: texture,
side: THREE.DoubleSide,
transparent: true
},
{ time: app.commonUniforms.time }
);
let geoW = 5, geoH = 5;
let geom = new THREE.PlaneGeometry(geoW, geoH);
let mesh = new THREE.Mesh(geom, mat);
mesh.position.set(1, 0, 1);
app.scene.add(mesh);
ReflectorMaterial 反射材质
通过 createReflectorShaderMesh 创建反射材质。
用法
const geometry = new THREE.PlaneGeometry(100, 100)
const { mesh, material } = vjmap3d.createReflectorShaderMesh(geometry, {
reflectorMaterialType: "ReflectorDudvMaterial",
reflectivity: 0.2
})
mesh.name = "reflectorShaderMesh"
mesh.rotation.x = -Math.PI / 2
mesh.position.y = -0.3
app.scene.add(mesh);
示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let carMesh = await vjmap3d.ResManager.loadModel(env.assetsPath + "models/car.glb", {
toEntity: true
});
carMesh.scale.set(5, 5, 5)
carMesh.addTo(app);
const geometry = new THREE.PlaneGeometry(100, 100)
const { mesh, material } = vjmap3d.createReflectorShaderMesh(geometry, {
reflectorMaterialType: "ReflectorDudvMaterial",
reflectivity: 0.2
})
mesh.name = "reflectorShaderMesh"
mesh.rotation.x = -Math.PI / 2
mesh.position.y = -0.3
app.scene.add(mesh);
const ui = await app.getConfigPane()
ui.appendChild({
type: "slider",
label: 'reflectivity',
property: [material.uniforms.uReflectivity, "value"],
bounds: [0, 1],
stepSize: 0.001 // 原始配置对象的步长键名是 stepSize(写 step 会被忽略)
})
ui.appendChild({
type: "slider",
label: '位置y',
property: [mesh.position, "y"],
bounds: [-10, 0],
stepSize: 0.01
})
MeshReflectorMaterial是另一条路径(签名new MeshReflectorMaterial(app, parent: Mesh, config?)):它不是 Material 子类而是包装类——parent只用作反射平面(反射相机/渲染目标挂在它上面),构造函数不会替换parent.material;真正的材质在实例的.material字段(MeshReflectorMaterialImpl extends MeshStandardMaterial),必须自己写parent.material = refl.material。不要把返回值本身当材质赋给mesh.material。
flowGradientMaterial 流动的渐变材质
通过 createFlowGradientMaterial 创建流动的渐变材质。
用法
let mat = vjmap3d.createFlowGradientMaterial(app, {
object: mesh, // 或计算出mesh的坐标最小值min和物体坐标最大值max
lightScale: 0.1, // 动画光带宽度占物体高度的比例(负数表示绝对宽度);没有 borderWidth 这个参数
circleTime: Math.random() + 0.2,
lightColor: vjmap3d.randColor(),
color: vjmap3d.randColor(),
topColor: vjmap3d.randColor(),
})
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let data = [];
for(let i = 0; i < 10; i++) {
for(let j = 0; j < 10; j++) {
const box = new THREE.Mesh(
new THREE.BoxGeometry(Math.random() * 3 + 0.5, Math.random() * 5 + 3, Math.random() * 3 + 0.5),
new THREE.MeshStandardMaterial({ color: 0xff0000 })
);
box.position.set(i * 10 - 50, 0, j * 10 - 50)
app.scene.add(box);
let mat = vjmap3d.createFlowGradientMaterial(app, {
object: box,
lightScale: 0.1, // 光带宽度占高度比例
circleTime: Math.random() + 0.2,
lightColor: vjmap3d.randColor(),
color: vjmap3d.randColor(),
topColor: vjmap3d.randColor(),
})
box.material = mat;
}
}
RadarMaterial 雷达动画材质
通过 RadarMaterial 创建雷达动画材质
用法
let radius = 3;
let mat = new vjmap3d.RadarMaterial(
{
uRadius: radius,
uColor: new THREE.Color("#00ffff"),
uSpeed: 2,
uSectorAngle: 200,
uEdge: radius / 50,
opacity: 0.9, // ⚠️ webgl 下雷达着色器不读 opacity(透明度由扇区渐变决定),此项无效
transparent: true,
blending: THREE.AdditiveBlending,
depthWrite: false,
side: THREE.DoubleSide,
depthTest: true,
},
{ uTime: app.commonUniforms.iTime }
);
示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let radius = 3;
let mat = new vjmap3d.RadarMaterial(
{
uRadius: radius,
uColor: new THREE.Color("#00ffff"),
uSpeed: 2,
uSectorAngle: 200,
uEdge: radius / 50,
opacity: 0.9, // ⚠️ webgl 下雷达着色器不读 opacity(透明度由扇区渐变决定),此项无效
transparent: true,
blending: THREE.AdditiveBlending,
depthWrite: false,
side: THREE.DoubleSide,
depthTest: true,
},
{ uTime: app.commonUniforms.iTime }
);
let geom = new THREE.CircleGeometry(radius);
let mesh = new THREE.Mesh(geom, mat);
mesh.position.set(0, 0, 0);
mesh.rotateX(- Math.PI / 2)
app.scene.add(mesh);
ShadertoyMaterial Shadertoy材质
shadertoy是一个在浏览器中教学3D图形学的在线社区和通过WebGL创建分享shader程序的工具。网站上shader示例非常丰富。可直接复制shadertoy中的代码,通过 ShadertoyMaterial 创建Shadertoy材质
WebGPU 引擎下的 Shadertoy
webgpu 引擎下,shadertoy 的 GLSL 代码会在运行时自动转译为 TSL 节点再编译到 WGSL,无需修改 shader:支持 iTime / iResolution / iMouse(实时鼠标)/ iChannel0-3 / 自定义 uniforms / #define 与 #ifdef。少数复杂语法可能转译失败,此时自动回退为基础材质并在控制台告警。
用法
// https://www.shadertoy.com/view/4dlfR7
let shader = `
#define NUM_PARTICLES 200.0
#define GLOW 0.5
vec3 Orb(vec2 uv, vec3 color, float radius, float offset)
{
vec2 position = vec2(sin(offset * (iTime+30.)),
cos(offset * (iTime+30.)));
position *= sin((iTime ) - offset) * cos(offset);
//offset = pModPolar(position,2.);
radius = radius * offset;
float dist = radius / distance(uv, position);
return color * pow(dist, 1.0 / GLOW);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = vec2(fragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
vec3 pixel = vec3(0.0, 0.0, 0.0);
vec3 color = vec3(0.0, 0.0, 0.0);
color.r = ((sin(((iTime)) * 0.55) + 1.5) * 0.4);
color.g = ((sin(((iTime)) * 0.34) + 2.0) * 0.4);
color.b = ((sin(((iTime)) * 0.31) + 4.5) * 0.3);
float radius = 0.005;
for (float i = 0.0; i < NUM_PARTICLES; i++)
pixel += Orb(uv, color, radius, i / NUM_PARTICLES);
fragColor = mix(vec4(uv,0.8+0.5*sin(iTime),1.0), vec4(pixel, 1.0), 0.8);
}`
let mat = new vjmap3d.ShadertoyMaterial(app, {
shader: shader
});
示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
// https://www.shadertoy.com/view/4dlfR7
let shader = `
#define NUM_PARTICLES 200.0
#define GLOW 0.5
vec3 Orb(vec2 uv, vec3 color, float radius, float offset)
{
vec2 position = vec2(sin(offset * (iTime+30.)),
cos(offset * (iTime+30.)));
position *= sin((iTime ) - offset) * cos(offset);
//offset = pModPolar(position,2.);
radius = radius * offset;
float dist = radius / distance(uv, position);
return color * pow(dist, 1.0 / GLOW);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = vec2(fragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
vec3 pixel = vec3(0.0, 0.0, 0.0);
vec3 color = vec3(0.0, 0.0, 0.0);
color.r = ((sin(((iTime)) * 0.55) + 1.5) * 0.4);
color.g = ((sin(((iTime)) * 0.34) + 2.0) * 0.4);
color.b = ((sin(((iTime)) * 0.31) + 4.5) * 0.3);
float radius = 0.005;
for (float i = 0.0; i < NUM_PARTICLES; i++)
pixel += Orb(uv, color, radius, i / NUM_PARTICLES);
fragColor = mix(vec4(uv,0.8+0.5*sin(iTime),1.0), vec4(pixel, 1.0), 0.8);
}`
let mat = new vjmap3d.ShadertoyMaterial(app, {
shader: shader
});
let geoW = 2,
geoH = 2;
let geom = new THREE.BoxGeometry(geoW, geoH, 2);
let mesh = new THREE.Mesh(geom, mat);
mesh.position.set(0, 2, 0);
app.scene.add(mesh);
FixedSizeMeshMaterial 固定像素大小材质
FixedSizeMeshMaterial 屏幕固定大小的材质(只取网格原点做投影,几何的 xy 坐标按屏幕偏移叠加,大小与相机远近无关)。注意换算:1 个几何单位 ≈ 0.5 个 canvasSize 像素(app.commonUniforms.resolution 是乘过 pixelRatio 的设备像素),并受物体 scale 影响——下例半径 50 的圆在屏幕上约 25 个设备像素半径
用法
let circleGeometry = new THREE.CircleGeometry(50);
let circleMaterial = new vjmap3d.FixedSizeMeshMaterial({
color: 0x00ffff,
canvasSize: app.commonUniforms.resolution
});
let circle = new THREE.Mesh(circleGeometry, circleMaterial);
app.scene.add(circle)
示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let circleGeometry = new THREE.CircleGeometry(50);
let circleMaterial = new vjmap3d.FixedSizeMeshMaterial({
color: 0x00ffff,
canvasSize: app.commonUniforms.resolution
});
let circle = new THREE.Mesh(circleGeometry, circleMaterial);
app.scene.add(circle)
FlowMaterial 移动的纹理材质
通过 createRenderElementFlowMaterial 创建移动的纹理材质。
用法
let mat = vjmap3d.createRenderElementFlowMaterial(app, {
geometryWidth: width,
geometryHeight: height,
flowDirection: "horizon",
flowSpeed: -0.1,
element: [
new vjmap3d.render2d.Rect({
shape: {
x: 0,
y: 0,
width: 1000,
height: 1000 * height / width
},
style: {
fill: "#00023D"
}
})
]
});
let mesh = new THREE.Mesh(geometry, mat);
app.scene.add(mesh);
示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let width = 10, height = 5;
const geometry = new THREE.PlaneGeometry(width, height)
let ArrowRight = vjmap3d.render2d.Path.extend({
type: "arrowRight",
shape: {
x: 0,
y: 0,
width: 0,
height: 0
},
buildPath(ctx, shape) {
let x = shape.x;
let y = shape.y;
let height = shape.height;
let width = shape.width;
// @ts-ignore
let x1 = parseInt(x + width - 36);
// @ts-ignore
let y1 = parseInt(y + height / 5);
// @ts-ignore
let y2 = parseInt(y + (height / 5) * 4);
ctx.moveTo(x, y1);
ctx.lineTo(x1, y1);
ctx.lineTo(x1, y);
ctx.lineTo(x + width, y + height / 2);
ctx.lineTo(x1, y + height);
ctx.lineTo(x1, y2);
ctx.lineTo(x, y2);
ctx.closePath();
}
});
let arrows = []
for(let i = 0; i < 5; i++) {
arrows.push(new ArrowRight({
// @ts-ignore
shape: {
x: 0,
y: i * 100,
cx: 250,
cy: 25,
width: 50,
height: 60
},
style: {
fill: "#00ffff"
}
}));
}
let mat = vjmap3d.createRenderElementFlowMaterial(app, {
geometryWidth: width,
geometryHeight: height,
flowDirection: "horizon",
flowSpeed: -0.1,
element: [
new vjmap3d.render2d.Rect({
shape: {
x: 0,
y: 0,
width: 1000,
height: 1000 * height / width
},
style: {
fill: "#00023D"
}
}),
...arrows
]
});
let mesh = new THREE.Mesh(geometry, mat);
app.scene.add(mesh);
HolographicMaterial 全息投影材质
通过 HolographicMaterial 创建全息投影材质
用法
let mat = new vjmap3d.HolographicMaterial(app, {
fresnelAmount: 0.45,
fresnelOpacity: 0.1,
scanlineSize: 2.0,
hologramBrightness: 1.2,
signalSpeed: 0.45,
hologramColor: "#51a4de",
enableBlinking: true,
blinkFresnelOnly: true,
hologramOpacity: 1.0,
})
示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let size = 3;
let position = new THREE.Vector3(0, 0, 0);
// 创建半球几何体
let radius = size;
let widthSegments = 32;
let heightSegments = 16;
let phiStart = 0;
let phiLength = Math.PI;
let geom = new THREE.SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength);
let mat = new vjmap3d.HolographicMaterial(app, {
fresnelAmount: 0.45,
fresnelOpacity: 0.1,
scanlineSize: 2.0,
hologramBrightness: 1.2,
signalSpeed: 0.45,
hologramColor: "#51a4de",
enableBlinking: true,
blinkFresnelOnly: true,
hologramOpacity: 1.0,
})
let mesh = new THREE.Mesh(geom, mat);
mesh.position.copy(position);
mesh.rotateX(-Math.PI / 2);
app.scene.add(mesh);
MeshTransmissionMaterial 透射材质
通过 MeshTransmissionMaterial 创建透射材质
与
MeshReflectorMaterial同型:构造(app, parent: Mesh, config?)返回包装对象,真材质在.material(.material是ShaderMaterial)——必须写mesh.material = mat.material,不能把返回值直接当材质用。
用法
const mesh = new THREE.Mesh();
const geo = new THREE.TorusGeometry(3, 1, 32, 100);
const mat = new vjmap3d.MeshTransmissionMaterial(app, mesh);
mesh.geometry = geo;
mesh.material = mat.material;
app.scene.add(mesh);
示例
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
const mesh = new THREE.Mesh();
const geo = new THREE.TorusGeometry(3, 1, 32, 100);
const mat = new vjmap3d.MeshTransmissionMaterial(app, mesh);
mesh.geometry = geo;
mesh.material = mat.material;
app.scene.add(mesh);