Three.js 用于方向线性渐变的WebGL着色器
我正在三个js中实现一个定向线性渐变着色器。这是我第一次使用着色器,但我有一个起点:Three.js 用于方向线性渐变的WebGL着色器,three.js,glsl,shader,webgl,linear-gradients,Three.js,Glsl,Shader,Webgl,Linear Gradients,我正在三个js中实现一个定向线性渐变着色器。这是我第一次使用着色器,但我有一个起点: uniforms: { color1: { value: new Three.Color('red') }, color2: { value: new Three.Color('purple') }, bboxMin: {
uniforms: {
color1: {
value: new Three.Color('red')
},
color2: {
value: new Three.Color('purple')
},
bboxMin: {
value: geometry.boundingBox.min
},
bboxMax: {
value: geometry.boundingBox.max
}
},
vertexShader: `
uniform vec3 bboxMin;
uniform vec3 bboxMax;
varying vec2 vUv;
void main() {
vUv.y = (position.y - bboxMin.y) / (bboxMax.y - bboxMin.y);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`,
fragmentShader: `
uniform vec3 color1;
uniform vec3 color2;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(mix(color1, color2, vUv.y), 1.0);
}
`,
这对于“自底向上”的线性渐变非常有效,其中color1(红色)位于底部,color2(紫色)位于顶部。我想知道如何旋转梯度的方向。我知道它需要编辑void main(){
函数,但是我对所需的数学知识有点茫然
基本上,我正在尝试重新实现svg渐变定义:
viewBox="0 0 115.23 322.27">
<defs>
<linearGradient id="linear-gradient" x1="115.95" y1="302.98" x2="76.08" y2="143.47" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#8e0000"/>
<stop offset="1" stop-color="#42210b"/>
</linearGradient>
viewBox=“0 0 115.23 322.27”>
因此,我必须将viewbox和x1、y1、x2、y2,以及两种以上“停止”颜色的可能性转换为制服和某种工作逻辑使用纹理
显示使用纹理制作渐变
作为证明,这通常是解决方案,下面是,在Chrome、Android和Firefox中用于绘制SVG和Canvas2D渐变
然后,您可以像其他纹理一样,通过操纵纹理坐标来偏移、旋转和缩放渐变的应用方式。在three.js中,您可以通过设置texture.offset
、texture.repeat
、和texture.rotation
或更新几何体中的纹理坐标来实现
正文{
保证金:0;
}
#c{
宽度:100vw;
高度:100vh;
显示:块;
}
将*作为三个源导入'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
函数main(){
const canvas=document.querySelector(“#c”);
const renderer=new THREE.WebGLRenderer({canvas});
常数fov=75;
const aspect=2;//画布默认值
常数近=0.1;
常数far=5;
常量摄影机=新的三个透视摄影机(视野、方位、近距离、远距离);
摄像机位置z=2;
const scene=new THREE.scene();
常数几何=新的三个。平面几何(1,1);
const tempColor=new THREE.Color();
函数get255BasedColor(颜色){
tempColor.set(颜色);
返回tempColor.toArray().map(v=>v*255);
}
函数makeRampTexture(停止){
//让我们总是让坡道256x1
常数res=256;
常数数据=新的UINT8阵列(res*3);
const mixedColor=new THREE.Color();
设prevX=0;
对于(设ndx=1;ndxprevX){
const color0=停止[ndx-1]。颜色;
const color1=停止[ndx]。颜色;
const diff=nextX-prevX;
对于(让x=prevX;x使用纹理)
显示使用纹理制作渐变
作为证明,这通常是解决方案,下面是,在Chrome、Android和Firefox中用于绘制SVG和Canvas2D渐变
然后,您可以像其他纹理一样,通过操纵纹理坐标来偏移、旋转和缩放渐变的应用方式。在three.js中,您可以通过设置texture.offset
、texture.repeat
、和texture.rotation
或更新几何体中的纹理坐标来实现
正文{
保证金:0;
}
#c{
宽度:100vw;
高度:100vh;
显示:块;
}
将*作为三个源导入'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
函数main(){
const canvas=document.querySelector(“#c”);
const renderer=new THREE.WebGLRenderer({canvas});
常数fov=75;
const aspect=2;//画布默认值
常数近=0.1;
常数far=5;
常量摄影机=新的三个透视摄影机(视野、方位、近距离、远距离);
摄像机位置z=2;
const scene=new THREE.scene();
常数几何=新的三个。平面几何(1,1);
const tempColor=new THREE.Color();
函数get255BasedColor(颜色){
tempColor.set(颜色);
返回tempColor.toArray().map(v=>v*255);
}
函数makeRampTexture(停止){
//让我们总是让坡道256x1
常数res=256;
常数数据=新的UINT8阵列(res*3);
const mixedColor=new THREE.Color();
设prevX=0;
对于(设ndx=1;ndxprevX){
const color0=停止[ndx-1]。颜色;
const color1=停止[ndx]。颜色;
const diff=nextX-prevX;
对于(让x=prevX;x我被gman推荐的答案是正确的,但是我发现我不得不做一些额外的事情,因为我没有使用标准几何体,而是使用svg图标制作的几何体,而且答案也没有确切地解释如何使用具有多种颜色的线性渐变定义创建三种纹理还有一个明确的方向(你需要弄清楚的事情)
这些步骤只适用于那些偶然发现这些问题的人,他们同样在处理非标准几何体,并且对如何在三种情况下制作线性渐变纹理感到困惑:
使用canvas 2d生成渐变纹理。你必须先计算面部对象的大小,对我来说,我刚刚做了bbox测量,或者如果你不想精确的渐变到面部位置匹配,你可以使用任何大小
function generateTextureGradient(size, x1, y1, x2, y2, colors){
let width = size.width
let height = size.height
const canvas = new self.OffscreenCanvas(width, height)
let context = canvas.getContext('2d')
context.rect(0, 0, width, height)
let gradient = context.createLinearGradient(x1, y1, x2, y2)
for (let color of colors) {
gradient.addColorStop(color.props.offset, color.props['stop-color'])
}
context.fillStyle = gradient
context.fill()
return canvas
}
展开几何体UV,“我的svg几何体”有80个面,但有0个面顶点,使用此循环生成面顶点UV,以便三个人了解如何将纹理放置到网格上
for (var i = 0; i < geometry.faces.length; i++) {
var face = geometry.faces[i];
var faceUVs = geometry.faceVertexUvs[0][i] || [
new Three.Vector2(),
new Three.Vector2(),
new Three.Vector2()
]
var va = geometry.vertices[geometry.faces[i].a]
var vb = geometry.vertices[geometry.faces[i].b]
var vc = geometry.vertices[geometry.faces[i].c]
var vab = new Three.Vector3().copy(vb).sub(va)
var vac = new Three.Vector3().copy(vc).sub(va)
//now we have 2 vectors to get the cross product of...
var vcross = new Three.Vector3().copy(vab).cross(vac);
//Find the largest axis of the plane normal...
vcross.set(Math.abs(vcross.x), Math.abs(vcross.y), Math.abs(vcross.z))
var majorAxis = vcross.x > vcross.y ? (vcross.x > vcross.z ? 'x' : vcross.y > vcross.z ? 'y' : vcross.y > vcross.z) : vcross.y > vcross.z ? 'y' : 'z'
//Take the other two axis from the largest axis
var uAxis = majorAxis == 'x' ? 'y' : majorAxis == 'y' ? 'x' : 'x';
var vAxis = majorAxis == 'x' ? 'z' : majorAxis == 'y' ? 'z' : 'y';
faceUVs[0].set(va[uAxis], va[vAxis])
faceUVs[1].set(vb[uAxis], vb[vAxis])
faceUVs[2].set(vc[uAxis], vc[vAxis])
geometry.faceVertexUvs[0][i] = faceUVs
}
geometry.elementsNeedUpdate = geometry.verticesNeedUpdate = geometry.uvsNeedUpdate = true;
gman给我的答案是正确的,但是我发现我必须做一些额外的事情,因为我没有使用标准几何体,而是使用svg图标制作的几何体,而且答案也没有确切解释如何使用线性渐变定义创建一个三分纹理,该定义可以具有多种颜色和定义的颜色行动(你需要弄清楚的事情)
这些步骤只适用于那些偶然发现这些问题的人
var texture = new Three.CanvasTexture(
generateTextureGradient(
{width, height},
grad.x1,
grad.y1,
grad.x2,
grad.y2,
grad.colors
)
)
var material = new Three.MeshBasicMaterial({
side: Three.DoubleSide,
map: texture,
wireframe: false
})
var mesh = new Three.Mesh(geometry, material)