上面gif效果不是太好,是因为录屏软件问题,下面的截图是正常效果
代码如下:
import {
PlaneBufferGeometry,
ShaderMaterial,
Vector4,
DoubleSide,
Mesh,
Object3D,
Color,
Vector2
} from 'three';
/**
* 创建调色板
* 使用方式
* 1、引入库
* import { ColorPicker } from './ColorPicker.js';
* 2、创建对象并添加到场景
* this.colorPicker = new ColorPicker();
this.scene.add(this.colorPicker.colorPicker);
* 3、使用射线检测来修改选中颜色
var planeIntersects = this.ray.intersectObjects(this.scene.children, true);
var planeIntersect = planeIntersects== null ? null : planeIntersects[0];
if (planeIntersect) {
if(this.colorPicker && planeIntersect.object.name.indexOf("ColorPicker")>=0){
let newColor = this.colorPicker.getColor(planeIntersect);
console.log(newColor);
}
}
*/
class ColorPicker {
constructor() {
this.saturationParams = {
segment:1,
targetColor:new Vector4(1,0,0,1),
maskColor:new Vector4(1,1,1,1),
maskOffset:0.015,
maskPos:new Vector2(0,0)
}
this.hueParams = {
segment:1.0,
width:0.1,
height:1.0,
hues:[2,0,1,2,0,1],
colors:[new Vector4(1, 0, 0, 1), new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1), new Vector4(0, 1, 0, 1), new Vector4(0, 1, 0, 1), new Vector4(1, 0, 0, 1)],
maskColor:new Vector4(1,1,1,1),
maskOffset:0.01,
}
this.colorPicker = null;
this.CreateColorPicker();
}
/**
* 创建调色板
*/
CreateColorPicker() {
this.colorPicker = new Object3D();
this.colorPicker.name = "ColorPicker";
let Saturation = this.createSaturation();
this.colorPicker.attach(Saturation);
this.colorPicker._Saturation = Saturation;
let Hue = this.createHue();
this.colorPicker.attach(Hue);
this.colorPicker._Hue = Hue;
}
/**
* 获取点击颜色
* @param {*} intersect 射线检测到的物体
* @returns
*/
getColor(intersect){
if(intersect && intersect.object.name.indexOf("ColorPicker")>=0){
let obj = intersect.object;
if(obj._type && obj._type == "Hue"){
this.changeHue(intersect.point);
return this.selectColor(this.saturationParams.maskPos);
}
else if(obj._type && obj._type == "Saturation"){
intersect.point.y *= -1;
return this.selectColor(intersect.point);
}
}
}
changeHue(point) {
this.colorPicker._Hue.material.uniforms.maskHeight.value = point.y;
let y = (point.y + this.hueParams.height / 2) / this.hueParams.height;
let color = this.getHueColor(y);
this.colorPicker._Saturation.material.uniforms.targetColor.value = color;
this.saturationParams.targetColor = color;
}
selectColor(point){
this.colorPicker._Saturation.material.uniforms.maskPos.value = new Vector2(point.x,point.y);
this.saturationParams.maskPos = new Vector2(point.x,point.y)
var x = (point.x+this.saturationParams.segment/2)/this.saturationParams.segment;
var y = (point.y+this.saturationParams.segment/2)/this.saturationParams.segment;
return this.getSaturationColor([this.saturationParams.targetColor.x,this.saturationParams.targetColor.y,this.saturationParams.targetColor.z],x,y);
}
getSaturationColor(color,x,y){
var newColor = [1,1,1];
for (var i = 0; i < 3; i++)
{
if (color[i] != 1)
{
newColor[i] = (1 - color[i]) * (1 - x) + color[i];
}
}
for (var i = 0; i < 3; i++)
{
newColor[i] *= (1 - y);
}
return new Color(newColor[0],newColor[1],newColor[2],1);
}
/**
* 根据y值获取hue选中的颜色
* @param {*} y
* @returns
*/
getHueColor(y){
if(y<0) y=0.0;
if(y>1.0) y=1.0;
var c = 0.166667;
var index = Math.floor(y / c);
var h = this.hueParams.hues[index];
var newColor = this.hueParams.colors[index].clone();
var less = (y - index * c) / c;
var value = index % 2 == 0 ? less : 1.0 - less;
if(h == 0) newColor.x = value;
else if(h == 1) newColor.y = value;
else if(h == 2) newColor.z = value;
return newColor;
}
/**
* 创建Saturation
* @returns
*/
createSaturation() {
let segment = 1;
let planeGeo = new PlaneBufferGeometry(this.saturationParams.segment, this.saturationParams.segment);
let planeMat = new ShaderMaterial({
uniforms: {
targetColor: { value: this.saturationParams.targetColor},
resolution: { value: this.saturationParams.segment },
maskPos:{value:this.saturationParams.maskPos},
maskColor:{value:this.saturationParams.maskColor},
maskOffset:{value:this.saturationParams.maskOffset},
},
side: DoubleSide,
vertexShader: [
"varying vec3 modelPos;",
"void main() {",
" modelPos = position;",
" gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform vec4 targetColor;",
"uniform float resolution;",
"uniform float maskOffset;",
"uniform vec4 maskColor;",
"uniform vec2 maskPos;",
"varying vec3 modelPos;",
"vec4 GetSaturation(vec4 targetC, float x, float y)",
"{",
" vec4 newColor = vec4(1.0,1.0,1.0,1.0);",
" for (int i = 0; i < 3; i++)",
" {",
" if (targetC[i] < 0.999)",
" {",
" newColor[i] = (1.0 - targetC[i]) * (1.0 - x) + targetC[i];",
" }",
" }",
" newColor *= (1.0 - y);",
" newColor.a = 1.0;",
" return newColor;",
"}",
"void main() {",
" if(modelPos.x >= maskPos.x-maskOffset && modelPos.x <= maskPos.x+maskOffset && modelPos.y >= maskPos.y-maskOffset && modelPos.y <= maskPos.y+maskOffset)",
" gl_FragColor = maskColor;",
" else{",
" float x = (modelPos.x + resolution/2.0)/resolution;",
" float y = (modelPos.y + resolution/2.0)/resolution;",
" gl_FragColor = GetSaturation(targetColor,x,y);",
" }",
"}"
].join("\n")
});
let plane = new Mesh(planeGeo, planeMat);
plane.rotateX(Math.PI);
plane.scale.set(1 / segment, 1 / segment, 1 / segment);
plane._type = "Saturation";
plane.name = "ColorPicker_Saturation";
return plane;
}
/**
* 创建hue
* @returns
*/
createHue() {
let planeGeo = new PlaneBufferGeometry(this.hueParams.width, this.hueParams.height, this.hueParams.segment, this.hueParams.segment);
let planeMat = new ShaderMaterial({
uniforms: {
resolution: { value: this.hueParams.height },
hues: { value: this.hueParams.hues },
maskHeight: { value: this.hueParams.height / 2.0 },
colors: { value: this.hueParams.colors },
maskColor: { value: this.hueParams.maskColor },
maskOffset: { value: this.hueParams.maskOffset },
},
side: DoubleSide,
vertexShader: [
"varying vec3 modelPos;",
"void main() {",
" modelPos = position;",
" gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform float resolution;",
"uniform float maskHeight;",
"uniform int[6] hues;",
"uniform vec4[6] colors;",
"varying vec3 modelPos;",
"float c = 0.166667;",
"uniform float maskOffset;",
"uniform vec4 maskColor;",
"vec4 GetHue(float y)",
"{",
" y = clamp(y,0.0,1.0);",
" highp int index = int(floor(y/c));",
" int h = hues[index];",
" vec4 newColor = colors[index];",
" float less = (y-float(index)*c)/c;",
" newColor[h] = index % 2 == 0 ? less : 1.0-less;",
" return newColor;",
"}",
"void main() {",
" if(modelPos.y > maskHeight - maskOffset && modelPos.y<maskHeight + maskOffset)",
" gl_FragColor = maskColor;",
" else{",
" float y = (modelPos.y + resolution/2.0)/resolution;",
" gl_FragColor = GetHue(y);",
" }",
"}"
].join("\n")
});
let plane = new Mesh(planeGeo, planeMat);
plane.rotateX(Math.PI);
plane.rotateZ(Math.PI);
plane.scale.set(1 / this.hueParams.segment, 1 / this.hueParams.segment, 1 / this.hueParams.segment);
plane.position.x += 0.6;
plane._type = "Hue";
plane.name = "ColorPicker_Hue";
return plane;
}
}
export { ColorPicker }