threeJs着色器ShaderMaterial以及统一着色语言GLSL语法基本介绍

2023-11-01

一、着色器材质ShaderMaterial的基本使用

废话不多讲先来看案例

console.log('着色器入门')

// 引入three.js
import * as THREE from 'three'
// 引入OrbitControls控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

// 初始化场景
const scene = new THREE.Scene()
//创建透视相机
const camera = new THREE.PerspectiveCamera(
  90,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)
// 设置相机位置
camera.position.set(0, 0, 2)
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix()
// 添加相机到场景
scene.add(camera)


// 创建辅助轴
const axesHelper = new THREE.AxesHelper(5)
// 添加辅助轴到场景
scene.add(axesHelper)


// 创建着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: `
        void main(){
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ;
        }
    `,
  fragmentShader: `
        void main(){
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `,
})
// 利用着色器材质创建一个平面
const plane = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(1, 1, 64, 64),
  shaderMaterial
)
// 添加平面到场景
scene.add(plane)


// 初始化渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染器的大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix();
  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置渲染器的像素比例
  renderer.setPixelRatio(window.devicePixelRatio);
});
// 添加渲染器到dom
document.body.appendChild(renderer.domElement)


// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 设置控制器阻尼
controls.enableDamping = true

// 渲染函数
function render() {
  // 更新控制器
  controls.update()
  // 渲染
  renderer.render(scene, camera)
  // 动画
  requestAnimationFrame(render)
}
// 调用渲染函数
render()

运行效果如下图所示:
在这里插入图片描述
这个案例就是使用着色器材质创建一个红色的平面。

核心其实就是这一段代码

// 创建着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: `
        void main(){
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ;
        }
    `,
  fragmentShader: `
        void main(){
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `,
})
// 利用着色器材质创建一个平面
const plane = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(1, 1, 64, 64),
  shaderMaterial
)
// 添加平面到场景
scene.add(plane)

这里来详细讲讲这一段代码的作用

上面的代码创建了一个着色器材质(ShaderMaterial),这是three.js中用于创建自定义着色的高级功能。着色器是直接在GPU上运行的小程序,这可以极大地提高渲染效率。这个例子使用了两种类型的着色器:顶点着色器片元着色器

vertexShader : 这是顶点着色器的代码。顶点着色器的主要任务计算顶点的最终位置3D坐标转变为屏幕的2D坐标)。在这个例子中,顶点着色器仅仅是执行了一个标准的模型-视图-投影变换。函数void main()是着色器的入口点。

`gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0 );`

这行代码是进行了一个坐标变换,将模型空间中的顶点位置变换到裁剪空间中

  • position是原始的顶点位置
  • modelMatrix将其变换到世界空间
  • viewMatrix将世界空间变换到视图空间
  • projectionMatrix将视图空间变换到裁剪空间

fragmentShader : 这是片元着色器的代码。片元着色器的任务计算每个像素的最终颜色。在这个例子中,片元着色器直接设置了所有的像素为红色。

`gl_FragColor = vec4(1.0,0.0,0.0,1.0);`

这行代码将片元的颜色设置为红色vec4代表一个四维的向量,前三个元素分别代表了红色,绿色和蓝色的分量,每个值的范围为0.0~1.0,最后一个元素代表了透明度

总的来说,该代码创建了一个红色效果的自定义着色器材质。每个物体在转移到屏幕坐标后都会被染成红色

二、顶点着色器(vertex shader)和片元着色器(fragment shader)的数据交互

Three.js中,顶点着色器(vertex shader)和片元着色器(fragment shader)是通过统一着色语言(GLSL)进行数据交互的。

在着色器程序中,顶点着色器首先处理每个顶点数据,这些数据可以是顶点的位置、颜色、纹素坐标等。计算结果会存储在特殊的变量中,例如 gl_Positiongl_PointSize。这些结果可以通过"varying"变量被传递到片元着色器中。

"varying"变量是顶点着色器和片元着色器之间唯一的通信方式。你可以将它视为从顶点着色器传递给片元着色器的一种“桥梁”。"varying"变量在顶点着色器中被写入,在片元着色器中被读取

顶点着色器计算的结果被插值 (undersampling) 到每个片元上。其过程称为光栅化 (rasterization)。在光栅化过程中,"varying"变量的数据会在每个像素上都被插值(这被称为传递)。之后,片元着色器会使用这些数据来计算每个像素的最终颜色值。

注意,"varying"变量的数量和大小受到硬件限制,过度使用可能会导致性能下降。在需要传递大量数据时,可以尝试使用纹理或缓冲区对象

可能介绍了概念大家还是云里雾里,我们通过一个案例来分析说明。

还是开始那个基本的案例,为了能更明显的感觉到varying传递数据的作用,我们将着色器材质中设置顶点着色器材质和片元着色器的代码抽离出来,新建两个文件

  • vertex.glsl
void main(){
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ;
}
  • fragment.glsl
void main(){
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

然后在基础案例中引入这两个glsl,使用到着色器材质的顶点着色器和片元着色器上

完整代码如下

// 引入three.js
import * as THREE from 'three'
// 引入OrbitControls控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 引入顶点着色器
import vertexShader from '../shader/myshader/vertex.glsl'
// 引入片元着色器
import fragmentShader from '../shader/myshader/fragment.glsl'

// 初始化场景
const scene = new THREE.Scene()
//创建透视相机
const camera = new THREE.PerspectiveCamera(
  90,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)
// 设置相机位置
camera.position.set(0, 0, 2)
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix()
// 添加相机到场景
scene.add(camera)


// 创建辅助轴
const axesHelper = new THREE.AxesHelper(5)
// 添加辅助轴到场景
scene.add(axesHelper)


// 创建着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
})
// 利用着色器材质创建一个平面
const plane = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(1, 1, 64, 64),
  shaderMaterial
)
// 添加平面到场景
scene.add(plane)


// 初始化渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染器的大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix();
  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置渲染器的像素比例
  renderer.setPixelRatio(window.devicePixelRatio);
});
// 添加渲染器到dom
document.body.appendChild(renderer.domElement)


// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 设置控制器阻尼
controls.enableDamping = true

// 渲染函数
function render() {
  // 更新控制器
  controls.update()
  // 渲染
  renderer.render(scene, camera)
  // 动画
  requestAnimationFrame(render)
}
// 调用渲染函数
render()

改动其实也就这一点:

// 引入
import vertexShader from '../shader/myshader/vertex.glsl'
import fragmentShader from '../shader/myshader/fragment.glsl'
// 使用
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
})

当然效果还是一样的,如图:
在这里插入图片描述
接下来我们尝试在顶点着色器中传入一个变量到片元着色器中来修改平面的颜色。

在顶点着色器中

  • vertex.glsl

varying float vColor;

void main(){
    vColor = 1.0;
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ;
}
  • fragment.glsl
varying float vColor;
void main(){
    gl_FragColor = vec4(1.0, vColor, 0.0, 1.0);
}

我们在顶点着色器中定义了一个floatvColor变量,并赋值为1.0,然后通过varying传递出去,
片元着色器中同样通过varying接收这个vColor变量并使用

此时我们就成功将平面的颜色改为了黄色,效果如图:
在这里插入图片描述

三、统一着色语言(GLSL)

看了上面的两个案例,可能不了解glsl的小伙伴会有疑问,vertex.glslfragment.glsl两个文件中的float是什么?vec4是什么?gl_Positiongl_FragColor又是什么?好家伙还有个void main()???
跟我这搞c语言呢?

那么接下来就介绍一下glsl语言的基础语法。

1. 数据类型

GLSL语言有多种数据类型,包括:

数据类型 描述 示例
bool 布尔类型,只能是 true 或 false bool a = true;
int 整型 int a = 10;
float 浮点型 float a = 1.0;
double 双浮点型,比 float 更高精度 double a = 1.0;
vec2 二维向量,包含两个 float 组件 vec2 a = vec2(1.0, 2.0);
vec3 三维向量,包含三个 float 组件 vec3 a = vec3 (1.0, 2.0, 3.0);
vec4 四维向量,包含四个 float 组件 vec4 a = vec4 (1.0, 2.0, 3.0, 4.0);
ivec2 二维整型向量 ivec2 a = ivec2(1, 2);
ivec3 三维整型向量 ivec3 a = ivec3(1, 2, 3);
ivec4 四维整型向量 ivec4 a = ivec4(1, 2, 3, 4);
mat2 二维矩阵 mat2 a = mat2(1.0, 2.0, 3.0, 4.0);
mat3 三维矩阵 mat3 a = mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
mat4 四维矩阵 mat4 a = mat4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0);
sampler2D 用于访问纹理 uniform sampler2D texture;
samplerCube 用于存储和查询立方体纹理 uniform samplerCube texture;

请注意,GLSL中的变量必须在开始位置声明,这和许多其他编程语言不同。

2. 控制语句

GLSL中的控制语句具有和C语言相似的语法。以下是一些示例:

  1. if-else 语句:
if (condition) {
    // Code to execute if condition is true
} else {
   // Code to execute if condition is false
}

例如:

if (color.r > 0.5) {
    color.r = 1.0;
} else {
    color.r = 0.0;
}
  1. for 语句:
for (initialization; condition; post-loop expression) {
  // code to execute for each loop iteration
}

例如:

for (int i = 0; i < 3; i++) {
    color.rgb[i] = 1.0;
}
  1. while 语句:
while (condition) {
   // code to execute while condition is true
}

例如:

int i = 0;
while (i < 3) {
    color.rgb[i++] = 1.0;
}
  1. do-while 语句:
do {
   // Code to execute
} while (condition)

例如:

int i = 0;
do {
    color.rgb[i++] = 1.0;
} while (i < 3);
  1. switch-case 语句:
switch (expression) {
    case constant1:
        // code to execute if expression equals constant1
        break;
    case constant2:
        // code to execute if expression equals constant2
        break;
    default: 
        // code to execute if none of the above conditions are met
}

例如:

int i = getValue();
switch (i) {
    case 0:
        color.r = 1.0;
        break;
    case 1:
        color.g = 1.0;
        break;
    default:
        color.b = 1.0;
}

3. 函数

GLSLOpenGL着色语言)中,函数的声明和使用方式与C语言相似。简单来说,首先需要声明函数的返回类型,接着声明函数名和括号中的参数列表,然后在大括号中定义函数的具体操作。下面举例说明。

例如,我们声明一个将向量颜色分量都乘以2的函数:

vec3 doubleColor(vec3 color) {
  return 2.0 * color;
}

这里的vec3是函数返回类型,表示一个三维向量。函数名是doubleColor,参数是一个三维向量color。函数体内部的2.0 * color表示将颜色的每一个分量都乘以2。

然后这个函数可以在着色器程序的任何地方被使用,例如:

void main() {
  vec3 color = vec3(1.0, 0.5, 0.3);
  vec3 newColor = doubleColor(color);
  gl_FragColor = vec4(newColor, 1.0);
}

在这个main函数中,首先定义了一个原始颜色color,然后用我们定义的doubleColor函数将原始颜色的每个分量都乘以2得到新的颜色newColor。最后将包含newColor的颜色设置为片元颜色。

需要注意的是,所有的GLSL函数必须在调用之前就已经声明了,这与JavaScript等其他语言不同

4. 内置attributes 和 uniforms

WebGLGLSL中,attributes uniforms是两种预定义的类型,都是用来在着色器中存储和传递数据的。它们的主要区别在于,attributes存储的是每个顶点独有的数据,如位置,颜色,纹理坐标等;而uniforms用于存储在一个渲染调用中对所有顶点都相同的数据,比如变换矩阵,光照参数等。

threejs中,这些attributesuniforms都是通过JavaScriptCPU端设置,然后在GPU端的着色器中获取其值进行计算。

下面是一些常见的attributesuniforms

  • attributes

    • position:顶点的位置。
    • normal:顶点的法向量。
    • uv:顶点的纹理坐标。
  • uniforms

    • modelViewMatrix:模型视图矩阵。
    • projectionMatrix:投影矩阵。
    • normalMatrix:法向量矩阵。
    • time:用于动画等需要时间参数的场景。

例如,下面是一个顶点着色器的例子,其中使用了position attribute和modelViewMatrix、projectionMatrix两个uniform:

attribute vec3 position; // 顶点位置
uniform mat4 modelViewMatrix; // 模型视图矩阵
uniform mat4 projectionMatrix; // 投影矩阵

void main() {
  vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); // 计算顶点在视图空间中的位置
  gl_Position = projectionMatrix * mvPosition; // 投影到屏幕坐标
}

然后在JavaScript中设定这些值:

var geometry = new THREE.BufferGeometry();
var vertices = new Float32Array([
  -1.0, -1.0,  1.0,
   1.0, -1.0,  1.0,
   1.0,  1.0,  1.0,

   1.0,  1.0,  1.0,
  -1.0,  1.0,  1.0,
  -1.0, -1.0,  1.0
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

var material = new THREE.ShaderMaterial({
  uniforms: {
    time: { value: 1.0 },
    resolution: { value: new THREE.Vector2() }
  },
  vertexShader: document.getElementById('vertexShader').textContent,
  fragmentShader: document.getElementById('fragmentShader').textContent
});

var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

这样,我们就可以在着色器中使用这些attributesuniforms进行渲染计算了。

四、通过uv渲染彩色平面

通过上面的介绍,我们知道uv是内置的属性,他刚好是二维的,那么如果我们将他从顶点着色器传递到片元着色器,进行渲染平面会有什么结果呢?
一起看看吧

  • vertex.glsl
varying vec2 vUv;
void main(){
    vUv = uv;
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ;
}
  • fragment.glsl
varying float vColor;
varying vec2 vUv;
void main(){
    gl_FragColor = vec4(vUv, 0.0, 1.0);
}

完整示例代码

// 引入three.js
import * as THREE from 'three'
// 引入OrbitControls控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 引入顶点着色器
import vertexShader from '../shader/myshader/vertex.glsl'
// 引入片元着色器
import fragmentShader from '../shader/myshader/fragment.glsl'

// 初始化场景
const scene = new THREE.Scene()
//创建透视相机
const camera = new THREE.PerspectiveCamera(
  90,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)
// 设置相机位置
camera.position.set(0, 0, 2)
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix()
// 添加相机到场景
scene.add(camera)


// 创建辅助轴
const axesHelper = new THREE.AxesHelper(5)
// 添加辅助轴到场景
scene.add(axesHelper)


// 创建着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
})
// 利用着色器材质创建一个平面
const plane = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(1, 1, 64, 64),
  shaderMaterial
)
// 添加平面到场景
scene.add(plane)


// 初始化渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染器的大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix();
  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置渲染器的像素比例
  renderer.setPixelRatio(window.devicePixelRatio);
});
// 添加渲染器到dom
document.body.appendChild(renderer.domElement)


// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 设置控制器阻尼
controls.enableDamping = true

// 渲染函数
function render() {
  // 更新控制器
  controls.update()
  // 渲染
  renderer.render(scene, camera)
  // 动画
  requestAnimationFrame(render)
}
// 调用渲染函数
render()

效果如下:
在这里插入图片描述
吼吼!利用uv渲染的平面成彩色了是不是很神奇。

为什么呢?

这是因为vUv参数对应的是一个二维向量(vec2),这个向量用于确定像素对应的纹理坐标。它通常是在顶点着色器(Vertex Shader)中计算出来的,然后传递到片元着色器(Fragment Shader)进行使用。

gl_FragColor = vec4(vUv, 0.0, 1.0);这行代码中,我们创建了一个颜色向量,它的前两个分量(R和G)是提供的vUv值,第三个分量(B)是0.0,第四个分量(alpha,表示透明度)是1.0。

简单来说,也就是将纹理位置的坐标值直接转化为了颜色值,因此会得到彩色的效果。
例如

  • 纹理坐标(0, 0)对应的是黑色(R=0, G=0, B=0)
  • 纹理坐标(1, 0)或者(0, 1)对应的是红色或者绿色(R=1, G=0, B=0或者R=0, G=1, B=0)
  • 纹理坐标(1, 1)对应的是黄色(R=1, G=1, B=0)

五、总结

好啦,到这里我们详细介绍了three.js库中的着色器ShaderMaterial和统一着色语言GLSL的基本语法。

首先介绍了ShaderMaterial在three.js中的地位以及功用。它是一种特殊的材质书写方式,让你可以编写自定义着色器。ShaderMaterial给予了我们底层的、未过滤的访问权,让我们可以编写自己的顶点(vertex)和片段(fragment)着色器程序。

接着深入解析了统一着色语言GLSL(OpenGL Shading Language)的语法基础。GLSL是C语言的一种方言,是Open GL的一部分,用于编写短程图形渲染框架。文章讲解了其基本语言构架、数据类型和运算符、流程控制以及函数和过程等核心知识点。

最后给出了如何将这两者结合在一起,如何在three.js中使用GLSL着色器进行渲染的示例,包括如何创建着色器、如何编写着色器代码、以及如何将其应用到three.js场景中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

threeJs着色器ShaderMaterial以及统一着色语言GLSL语法基本介绍 的相关文章

  • Three.js 通过加载模型上的材质名称为材质添加边框

    是否可以在材料周围添加边框 如图所示 我可以通过以下代码设置材质颜色 object traverse function child if child instanceof THREE Mesh child material color se
  • 星系模拟:更改点的颜色并在鼠标悬停时显示文本

    我正在尝试创建模拟 https riteshsingh github io galaxies 4673 个最近星系的位置 星系是点 我想为鼠标悬停时的点着色并加载星系的名称 我花了很多天试图实现它 我可以更改颜色以及进行基本的光线投射 但是
  • 3D 图形矩阵 4x4 中最后一行的 magic 4 的用途是什么?

    当我阅读有关WebGL的书时 我看到了下一个矩阵描述 有关于书中最后一行的信息 WebGL 初学者指南 初学者指南 Diego Cantor Brandon Jones 神秘的第四排 第四排没有任何特殊之处 意义 元素 m4 m8 m12
  • 将球体 a 旋转到自身的 b 点

    我试图弄清楚如何将球体从 A 点旋转到 B 点 我找到了一些Unity3d代码 Quaternion rot Quaternion FromToRotation pointA pointB sphere transform rotation
  • OpenGL:多个顶点的单个顶点属性?

    我有一个接受以下属性的顶点着色器 a posCoord 顶点位置 a texCoord 纹理坐标 传递给片段着色器 a alpha 透明度因子 传递给片段着色器 我正在渲染的对象都是 广告牌 一对直角三角形组成一个矩形 我正在使用一次调用g
  • 如何快速将一个float打包为4个字节?

    我一直在寻找一种在 WebGL 纹理上存储浮动的方法 我找到了一些解决方案 http aras p info blog 2009 07 30 encoding floats to rgba the final 在互联网上 但那些只处理 0
  • 如何在 Ubuntu 的 headless chrome 中启用 WebGL?

    如何在 Ubuntu 14 的 headless chrome 中启用 webgl 或安装 webgl 我尝试安装 libosmesa6 但这没有帮助 有人可以指出我正确的方向吗 我想使用 webgl 来处理无头 chrome 和 sele
  • 扩展 Three.js 类

    我想扩展 Three js Object3D 类 但不知道该怎么做 有一个 Stackoverflow 问题 我已经阅读 重新阅读和尝试过 但无法让它为我工作 有没有办法扩展 ThreeJS 对象 https stackoverflow c
  • 重复凹凸贴图

    我正在尝试使用 Three js r55 将凹凸贴图应用到平面上 以创建一个模糊的感觉表面 这是我的代码 var mapHeight THREE ImageUtils loadTexture images felt png mapHeigh
  • 在 Three.js 中渲染具有大量对象的多个场景的最佳方式

    想象一下 您想要绘制两个场景 每个场景都有数百个球体 并提供在这些场景之间切换的功能 做到这一点的最佳方法是什么 目前 一个开关大约需要 4 到 5 秒 因为我要删除 创建和绘制每个开关上的所有球体 下面是在场景切换上运行的代码示例 cle
  • 调试 Three.js 中的低 FPS

    我正在处理 Three js WebGL 场景 当我缩小时 我注意到 60 FPS 以便所有观察结果 约 20 000 个三角形 都在视图中 但当我放大时 FPS 非常低 因此只有一个小三角形的子集在视野中 我想弄清楚是什么导致了这种差异
  • 一次性渲染阴影

    考虑到阴影投射的成本 我想知道对于动态定位的静态对象 例如 程序城市 是否有一个功能或可能 实验性的方法可以在 Three js 中仅渲染一次阴影贴图 甚至在 webgl 中 因此 结果可以在静态对象的下一帧中免费使用 仅当物体移动时才会进
  • 如何在 webgl 中缩放纹理?

    我有一个尺寸为 800x600 的纹理 如何在 webgl 上缩放它
  • WebGL:enablevertexattribarray索引超出范围

    这是我的顶点和片段着色器
  • Three.js - 将 WebGL 和 CSS3D 与 iFrame 混合

    我准备了一个混合的工作页面WebGL and CSS3D 在SO的一点帮助下here https stackoverflow com questions 24681170 three js properly blending css3d a
  • Three.js 椭圆

    如何在 Three js 中创建一个椭圆 我看过这个 在 THREE js 中绘制椭圆 https stackoverflow com questions 11419896 drawing an ellipse in three js 但如
  • 解决 Three.js / webGL 中的 gl_PointSize 限制

    我正在使用 Three js 创建交互式数据可视化 此可视化涉及渲染 68000 个节点 其中每个不同的节点具有不同的大小和颜色 最初我尝试通过渲染网格来实现此目的 但事实证明这非常昂贵 我当前的尝试是使用 Three js 粒子系统 每个
  • 三.js环境光意想不到的效果

    在下面的代码中 我渲染了一些立方体并使用点光源和环境光照亮它们 然而 当设置为 0xffffff 时 AmbientLight 会将侧面的颜色更改为白色 无论其指定的颜色如何 奇怪的是 点光源按预期工作 我怎样才能使环境光表现得像点光 因为
  • 在 Three.js 中从 Web Worker 加载纹理

    当将大纹理图像应用到网格上一段明显的时间时 Three js 会锁定浏览器的主线程 让我们考虑以下示例 var texLoader new THREE TextureLoader texLoader load someLargeTextur
  • 如何在react-三纤维中提取并播放动画

    嗯 我有 gltf 动画模型 我成功加载模型 但无法播放嵌入的动画 我想知道是否可以以任何方式解决它 顺便说一句 我正在反应中工作 先感谢您 在这里您可以找到型号https drive google com file d 1ZVyklaQu

随机推荐

  • go通过数组(切片)构建菜单树结构

    有这样的一组节点 每个节点包含自己的Id 还有父Id Parent Id 包含children指针数组 但是children是空 需要根据id和parentId把cihldren填充上 实现了如下的方法 type TreeNode inte
  • JAVA TCP客户端和服务器端简单实例

    客户端 package com example demo import java io BufferedReader import java io InputStreamReader import java io PrintWriter i
  • 详解Java中的byte类型(补充内容)

    写在前面 大家有时候可能会对Java中出现的byte类型有些疑惑 今天就来内化这些知识点 这个算是对其他博客的一个补充 内容很少 byte 在Java中 byte占据一个字节 也就是8的bite位 public static void ma
  • Kaiwii

    http blog csdn net kaiwii article details 7478038
  • qt 16进制字符串 转换为 二进制 字节流

    代码 include
  • 找出10个被打乱的数中被拿出的一个数

    include
  • RuoYi-弹出新窗口选择数据回显到父页面

    这里只贴出关键代码 其他代码需要自行编写 返回值处理根据实际需求来 目前是只取第一条 因为选择页面是单选行 表单页面新加方法 选择社区 function selectCommunity var url ctx community selec
  • 深度

    解码区块链 专题文章三 区块链的安全基础架构及构想 近期 国家发改委明确 区块链 被纳入新基建定义和范围 作为一项能够打通各个技术及领域的基础技术 区块链被认为将在各行业深度融合 新领域拓展 新场景新应用开发等方面潜力无限 解码区块链 内容
  • js 小技巧 ( 根据不同的状态生成不同的颜色和状态 )

    HTML 解决办法 动态绑定 color 然后 根据 三元表达式 进行处理 js 解决办法 动态绑定 color 然后 根据在每个数据的后面添加color属性 可能有的人会问vueb不能用不然不会双向绑定 确实vue要使用vueset 但是
  • 他人工作多年后的总结

    1 找一个好公司 精通至少一门语言及其框架 专注做5到10年 先有深度再有广度 不要为了高工资过早转向管理角色 2 从长远来看 拥有个人项目 阅读 写博客和参加访谈都会有助于你成为一个更好的开发人员 3 成为开发者社区的一部分 努力参加线上
  • qt写C++(引用的妙处,内联函数)

    首先看什么是引用 引用和取地址很像 容易混淆 单独出现 a就是对a这个变量取地址 如果是int a 就是声明这是一个引用 引用 include
  • 基于SpringBoot+redis实现一个简单的点赞功能

    点赞操作比较频繁 而且比较随意 所以数据变更很快 如果用mysql 会对mysql产生很大的压力 于是决定使用Redis 防止数据丢失 所以会定期将数据持久化同步到mysql中 一 Redis 缓存设计及实现 1 1 Redis 安装及运行
  • mysql约束之_外键约束 foreign key

    外键约束 foreign key 创建一个员工表employee 员工编号id 员工的姓名name 部门名称dept name 员工所在的地址address CREATE TABLE employee id INT PRIMARY KEY
  • R语言学习笔记

    参考 W N Venables D M Smith and the R DCT Introduction to R Notes on R A Programming Environment for Data Analysis and Gra
  • java集合Map介绍及具体使用

    目录 Map 双例集合 存储 键值对 key value 的数据 1 基本介绍 2 HashMap 2 1源码介绍 2 2 HashMap源码中的重要常量 2 3面试题 3 LinkHashMap 3 1LinkHashMap源码分析 4
  • Pandas数据处理

    数据预览 首先 调用read excel 方法读取数据 import pandas as pd df pd read excel data xlsx df 姓名 班级 语文 数学 0 张三 一班 99 90 1 李四 一班 78 NaN 2
  • 【从零开始学c++】———模拟实现string类(常用接口的实现)

    string 1 前言 2 string类常用接口实现 3 总结 1 前言 之前学到了string类常用接口的后 我很好奇string类在底层是怎样实现的 在由之前学习到c 有关的之后 所以我打算模拟实现一下string类常用的接口 以便加
  • Allegro学习笔记

    1 用Allegro进行PCB设计 文件的后缀名是 brd 2 双击 brd无法打开该文件 必须在Allegro里面File Open中进行打开
  • 《代码大全2》第5章 软件构建中的设计

    目录 前言 本章主题 5 1 设计中的挑战 5 1 1 设计在软件构建中所处的角色 5 1 2 设计是一个险恶的问题 5 2 关键的设计概念 5 2 1 软件的首要技术使命 管理复杂度 1 管理复杂度的重要性 5 2 2 理想的设计特征 5
  • threeJs着色器ShaderMaterial以及统一着色语言GLSL语法基本介绍

    一 着色器材质ShaderMaterial的基本使用 废话不多讲先来看案例 console log 着色器入门 引入three js import as THREE from three 引入OrbitControls控制器 import