shader编程-通过交集并集差集实现形状的合并(WebGL-Shader开发基础04)
Posted 点燃火柴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shader编程-通过交集并集差集实现形状的合并(WebGL-Shader开发基础04)相关的知识,希望对你有一定的参考价值。
1. 准备
先复习一下数学概念,交集、并集、差集如下图所示
我们准备拿圆做实验,绘制圆的函数如下
float circle(vec2 st,vec2 center,float radius) {
float blur = 0.002;
float pct = distance(st,center);//计算任意点到圆心的距离
return 1.0-smoothstep(radius,radius+blur,pct);
}
2. 交集实现
交集是求两个集合相交的部分,实现的方式有两种,一个是使用min函数,另外一种是将二者相乘,结果是一样的,为了验证给出了两个求交集的函数,如下
//交集
float shapeIntersection(float a,float b){
return min(a,b);
}
float shapeIntersection1(float a,float b){
return a*b;
}
调用过程是首先绘制了两个圆,然后对这两个圆求交,具体如下
void main( void ) {
//窗口坐标调整为[-1,1],坐标原点在屏幕中心
vec2 st = (gl_FragCoord.xy * 2. - u_resolution) / u_resolution.y;
vec3 line_color = vec3(1.0,1.0,0.0);
vec3 color = vec3(0.6);//背景色
float pct = 0.0;
//绘制两个圆
float cirlce = circle(st,vec2(-0.2,0.0),0.65);
float cirlce1 = circle(st,vec2(0.2,0.0),0.65);
//交集
pct = shapeIntersection(cirlce,cirlce1);
//pct = shapeIntersection1(cirlce,cirlce1);
color = mix(color,line_color,pct);
gl_FragColor = vec4(color, 1);
}
结果如下
3. 并集实现
并集是求两个集合所覆盖的全部的部分,实现的方式也有两种,一个是使用max函数,另外一种是将二者相加,如下
//并集
float shapeUnion(float a,float b){
return max(a,b);
}
float shapeUnion1(float a,float b){
return a+b;
}
调用过程非常简单在上一步的基础上直接调用函数求并集即可
//并集
pct = shapeUnion(cirlce,cirlce1);
//pct = shapeUnion1(cirlce,cirlce1);
结果如下
3. 差集实现
差集的实现,其实要先求交集,然后用集合A减去二者的交集就得到A集合相对于B集合的差集,代码如下
//差集
float shapeDifferenceSet(float a,float b){
return a-min(a,b);
}
调用过程就不解释了,直接看执行结果
4. 示例代码
<body>
<div id="container"></div>
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
<script>
var container;
var camera, scene, renderer;
var uniforms;
var vertexShader = `
void main() {
gl_Position = vec4( position, 1.0 );
}
`
var fragmentShader = `
#ifdef GL_ES
precision mediump float;
#endif
uniform float u_time;
uniform vec2 u_mouse;
uniform vec2 u_resolution;
float circle(vec2 st,vec2 center,float radius) {
float blur = 0.002;
float pct = distance(st,center);//计算任意点到圆心的距离
return 1.0-smoothstep(radius,radius+blur,pct);
}
//交集
float shapeIntersection(float a,float b){
return min(a,b);
}
float shapeIntersection1(float a,float b){
return a*b;
}
//并集
float shapeUnion(float a,float b){
return max(a,b);
}
float shapeUnion1(float a,float b){
return a+b;
}
//差集
float shapeDifferenceSet(float a,float b){
return a-min(a,b);
}
void main( void ) {
//窗口坐标调整为[-1,1],坐标原点在屏幕中心
vec2 st = (gl_FragCoord.xy * 2. - u_resolution) / u_resolution.y;
//窗口坐标调整为[0,1],坐标原点在屏幕左下角
//vec2 st = gl_FragCoord.xy/u_resolution;
vec3 line_color = vec3(1.0,1.0,0.0);
vec3 color = vec3(0.6);//背景色
float pct = 0.0;
//绘制两个圆
float cirlce = circle(st,vec2(-0.2,0.0),0.65);
float cirlce1 = circle(st,vec2(0.2,0.0),0.65);
//交集
pct = shapeIntersection(cirlce,cirlce1);
pct = shapeIntersection1(cirlce,cirlce1);
//并集
pct = shapeUnion(cirlce,cirlce1);
//pct = shapeUnion1(cirlce,cirlce1);
//差集
pct = shapeDifferenceSet(cirlce,cirlce1);
color = mix(color,line_color,pct);
gl_FragColor = vec4(color, 1);
}
`
init();
animate();
function init() {
container = document.getElementById('container');
camera = new THREE.Camera();
camera.position.z = 1;
scene = new THREE.Scene();
var geometry = new THREE.PlaneBufferGeometry(2, 2);
uniforms = {
u_time: {
type: "f",
value: 1.0
},
u_resolution: {
type: "v2",
value: new THREE.Vector2()
},
u_mouse: {
type: "v2",
value: new THREE.Vector2()
}
};
var material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
container.appendChild(renderer.domElement);
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
document.onmousemove = function (e) {
uniforms.u_mouse.value.x = e.pageX
uniforms.u_mouse.value.y = e.pageY
}
}
function onWindowResize(event) {
renderer.setSize(800, 800);
uniforms.u_resolution.value.x = renderer.domElement.width;
uniforms.u_resolution.value.y = renderer.domElement.height;
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
uniforms.u_time.value += 0.02;
renderer.render(scene, camera);
}
</script>
</body>
以上是关于shader编程-通过交集并集差集实现形状的合并(WebGL-Shader开发基础04)的主要内容,如果未能解决你的问题,请参考以下文章
shader编程-三维场景下使用交集并集差集方法CSG建模(WebGL-Shader开发基础10)
shader编程-RayMarching三维场景下使用交集并集差集方法CSG建模(WebGL-Shader开发基础10)
shader编程-RayMarching三维场景下使用交集并集差集方法CSG建模(WebGL-Shader开发基础10)
shader编程-RayMarching三维场景下使用交集并集差集方法CSG建模(WebGL-Shader开发基础10)