本来说写unity里的,由于three测试方便,先试试three
这个图片是目标效果
可以看见草很矮,很密集,如果用instance来绘制的话,遭不住的
忽然发现这个效果很像绒毛效果
于是找了博客康康
https://zhuanlan.zhihu.com/p/256445252
大概就是叠alpha,性能比instance好多了,虽然效果其实比不得instance,他这个实际来说丢失了每一根草的渲染能力,只能调叠层的色彩和整体调色,可能要和一根一根的草混用吧
这是在three构建demo的代码
const geometry = new THREE.PlaneGeometry(20, 20);//new THREE.ConeGeometry( 10, 30, 20, 20 );
geometry.rotateX(Math.PI * 0.5);
// const material = new THREE.MeshPhongMaterial( { color: 0xffffff, wireframe: true } );
const material = new THREE.ShaderMaterial({
uniforms: {
id: { value: 1 },
iTime: { value: 0 },
},
vertexShader: `
uniform float id;
varying vec2 vUv;
varying vec3 vColor;
varying vec3 vNormal;
varying vec3 pos;
void main() {
vUv = uv;
vColor = vec3(1.0, 0.0, 0.0);
pos = position.xyz;
vNormal = normal;
pos+=normal*0.1*id;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos.xyz,1.0);
}
`,
fragmentShader: `
uniform float id;
uniform float iTime;
varying vec3 vColor;
varying vec3 vNormal;
varying vec3 pos;
varying vec2 vUv;
float random (in vec2 st) {
return fract(sin(dot(st.xy,
vec2(12.9898,78.233)))
* 43758.5453123);
}
// 2D Noise based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
float noise (in vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
// Four corners in 2D of a tile
float a = random(i);
float b = random(i + vec2(1.0, 0.0));
float c = random(i + vec2(0.0, 1.0));
float d = random(i + vec2(1.0, 1.0));
// Smooth Interpolation
// Cubic Hermine Curve. Same as SmoothStep()
vec2 u = f*f*(3.0-2.0*f);
// u = smoothstep(0.,1.,f);
// Mix 4 coorners percentages
return mix(a, b, u.x) +
(c - a)* u.y * (1.0 - u.x) +
(d - b) * u.x * u.y;
}
vec4 permute(vec4 x) {
return mod((34.0 * x + 1.0) * x, 289.0);
}
// Cellular noise, returning F1 and F2 in a vec2.
// Speeded up by using 2x2 search window instead of 3x3,
// at the expense of some strong pattern artifacts.
// F2 is often wrong and has sharp discontinuities.
// If you need a smooth F2, use the slower 3x3 version.
// F1 is sometimes wrong, too, but OK for most purposes.
vec2 cellular2x2(vec2 P) {
#define K 0.142857142857 // 1/7
#define K2 0.0714285714285 // K/2
#define jitter 0.8 // jitter 1.0 makes F1 wrong more often
vec2 Pi = mod(floor(P), 289.0);
vec2 Pf = fract(P);
vec4 Pfx = Pf.x + vec4(-0.5, -1.5, -0.5, -1.5);
vec4 Pfy = Pf.y + vec4(-0.5, -0.5, -1.5, -1.5);
vec4 p = permute(Pi.x + vec4(0.0, 1.0, 0.0, 1.0));
p = permute(p + Pi.y + vec4(0.0, 0.0, 1.0, 1.0));
vec4 ox = mod(p, 7.0)*K+K2;
vec4 oy = mod(floor(p*K),7.0)*K+K2;
vec4 dx = Pfx + jitter*ox;
vec4 dy = Pfy + jitter*oy;
vec4 d = dx * dx + dy * dy; // d11, d12, d21 and d22, squared
// Sort out the two smallest distances
#if 0
// Cheat and pick only F1
d.xy = min(d.xy, d.zw);
d.x = min(d.x, d.y);
return d.xx; // F1 duplicated, F2 not computed
#else
// Do it right and find both F1 and F2
d.xy = (d.x < d.y) ? d.xy : d.yx; // Swap if smaller
d.xz = (d.x < d.z) ? d.xz : d.zx;
d.xw = (d.x < d.w) ? d.xw : d.wx;
d.y = min(d.y, d.z);
d.y = min(d.y, d.w);
return sqrt(d.xy);
#endif
}
void main(){
float test2 = (noise(vUv*30.0)*0.5+0.5)*0.5;
vec2 F = cellular2x2((vUv + 0.0* test2 * 0.0025*(1.0 - id)* sin(test2*0.1*iTime) )*2000.);
float test = noise(vUv*15.0);
vec3 yellow = vec3(0.4,0.9,0.0)*0.85;
vec3 green = vec3(0.2,1.0,0.0)*0.85;
float n = 1.0-1.5*F.x;
//gl_FragColor += vec4(0.1, 0.5 + (1.0 - id)*0.25, 0.0, n * id);
gl_FragColor += vec4(mix(green,yellow, test)*0.5+(1.0 - id)*0.5, n * id );
// if(gl_FragColor.a<0.21)discard; else {gl_FragColor.a=1.0;
// }
// gl_FragColor += vec4(n,n,n, n * id*0.5);
}
`,
transparent: true,
side: 2
})
let arr = [];
const COUNT = 30;
for (let i = 0; i < COUNT; i++) {
let geo = geometry.clone();
const materialClone = material.clone();
materialClone.uniforms.id.value = 1.0 - (i / COUNT);
arr.push(materialClone);
const mesh = new THREE.Mesh(geo, materialClone);
scene.add(mesh);
}