更多有趣示例 尽在
小红砖社区
示例
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js">script>
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
gl_Position = vec4( position, 1.0 );
}
script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 u_mouse;
const int octaves = 2;
const float seed = 43758.5453123;
const float seed2 = 73156.8473192;
const float eps = 0.005;
const vec3 ambientLight = 0.99 * vec3(1.0, 1.0, 1.0);
const vec3 light1Pos = vec3(10., 5.0, -25.0);
const vec3 light1Intensity = vec3(0.35);
const vec3 light2Pos = vec3(-20., -25.0, 85.0);
const vec3 light2Intensity = vec3(0.2);
vec3 movement = vec3(.0);
const int maxIterations = 256;
const int maxIterationsShad = 16;
const float stepScale = .7;
const float stopThreshold = 0.001;
mat4 rotationMatrix(vec3 axis, float angle)
{
axis = normalize(axis);
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;
return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0,
0.0, 0.0, 0.0, 1.0);
}
float length2( vec2 p )
{
return sqrt( p.x*p.x + p.y*p.y );
}
float length6( vec2 p )
{
p = p*p*p; p = p*p;
return pow( p.x + p.y, 1.0/6.0 );
}
float length8( vec2 p )
{
p = p*p; p = p*p; p = p*p;
return pow( p.x + p.y, 1.0/8.0 );
}
float sdBox( vec3 p, vec3 b )
{
vec3 d = abs(p) - b;
return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}
float udBox( vec3 p, vec3 b )
{
return length(max(abs(p)-b,0.0));
}
float udRoundBox( vec3 p, vec3 b, float r )
{
return length(max(abs(p)-b,0.0))-r;
}
float sdSphere( vec3 p, float s )
{
return length(p)-s;
}
float sdCylinder( vec3 p, vec3 c )
{
return length(p.xz-c.xy)-c.z;
}
float sdCappedCylinder( vec3 p, vec2 h )
{
vec2 d = abs(vec2(length(p.xz),p.y)) - h;
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
float sdTorus82( vec3 p, vec2 t )
{
vec2 q = vec2(length2(p.xz)-t.x,p.y);
return length8(q)-t.y;
}
float sdPlane( vec3 p)
{
return p.y;
}
float tri( float x ){
return abs( fract(x) - .5 );
}
vec3 tri3( vec3 p ){
return vec3(
tri( p.z + tri( p.y * 1. ) ),
tri( p.z + tri( p.x * 1. ) ),
tri( p.y + tri( p.x * 1. ) )
);
}
float triNoise3D( vec3 p, float spd , float time){
float z = 1.4;
float rz = 0.;
vec3 bp = p;
for( float i = 0.; i <= 3.; i++ ){
vec3 dg = tri3( bp * 2. );
p += ( dg + time * .1 * spd );
bp *= 1.8;
z *= 1.5;
p *= 1.2;
float t = tri( p.z + tri( p.x + tri( p.y )));
rz += t / z;
bp += 0.14;
}
return rz;
}
float smin(float a, float b, float k) {
float res = exp(-k*a) + exp(-k*b);
return -log(res)/k;
}
vec3 random3( vec3 p ) {
return fract(sin(vec3(dot(p,vec3(127.1,311.7,319.8)),dot(p,vec3(269.5,183.3, 415.2)),dot(p,vec3(362.9,201.5,134.7))))*43758.5453);
}
vec2 random2( vec2 p ) {
return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453);
}
float world_sdf(in vec3 p) {
float world = 10.;
vec3 grid = floor(p);
vec2 rand = random2(grid.xy);
float n = triNoise3D(p * .1, 0., u_time) * .5 - .25;
p = mod(p, 2.0) - 1.;
world = sdSphere(p, 1.1);
vec3 _p = p + n;
world = max(-(length(_p.xy) - .3), world);
world = max(-(length(_p.yz) - .6), world);
world = max(-(length(_p.xz) - .5), world);
return world;
}
vec3 calculate_normal(in vec3 p)
{
const vec3 small_step = vec3(0.0001, 0.0, 0.0);
float gradient_x = world_sdf(vec3(p.x + eps, p.y, p.z)) - world_sdf(vec3(p.x - eps, p.y, p.z));
float gradient_y = world_sdf(vec3(p.x, p.y + eps, p.z)) - world_sdf(vec3(p.x, p.y - eps, p.z));
float gradient_z = world_sdf(vec3(p.x, p.y, p.z + eps)) - world_sdf(vec3(p.x, p.y, p.z - eps));
vec3 normal = vec3(gradient_x, gradient_y, gradient_z);
return normalize(normal);
}
float rayMarching( vec3 origin, vec3 dir, float start, float end, inout float field ) {
float sceneDist = 1e4;
float rayDepth = start;
for ( int i = 0; i < maxIterations; i++ ) {
sceneDist = world_sdf( origin + dir * rayDepth );
if (( sceneDist < stopThreshold ) || (rayDepth >= end)) {
break;
}
rayDepth += sceneDist * stepScale;
}
if ( sceneDist >= stopThreshold ) rayDepth = end;
else rayDepth += sceneDist;
return rayDepth;
}
float softShadow(vec3 ro, vec3 lp, float k){
vec3 rd = (lp-ro);
float shade = 1.0;
float dist = 0.05;
float end = max(length(rd), 0.001);
rd /= end;
for (int i=0; i<maxIterationsShad; i++){
float h = world_sdf(ro + rd*dist);
shade = min(shade, k*h/dist);
dist += clamp(h, 0.01, 0.5);
if (h<0.001 || dist > end) break;
}
return shade;
}
float calculateAO(vec3 p, vec3 n)
{
const float AO_SAMPLES = 5.0;
float r = 0.0;
float w = 1.0;
for (float i=1.0; i<=AO_SAMPLES; i++)
{
float d0 = i * 0.15;
r += w * (d0 - world_sdf(p + n * d0));
w *= 0.5;
}
return 1.0-clamp(r,0.0,1.0);
}
vec3 lighting( vec3 sp, vec3 camPos, int reflectionPass, float dist, float field, vec3 rd) {
vec3 sceneColor = vec3(0.0);
vec3 objColor = vec3(2.0, .7, .5);
vec3 grid = floor(sp * .5);
vec3 rand = random3(grid);
objColor += rand*.1;
vec3 surfNormal = calculate_normal(sp);
vec3 lp = vec3(1., 1.0, .0) + movement;
vec3 ld = lp-sp;
vec3 lcolor = vec3(1.,0.97,0.92) * .8;
float len = length( ld );
ld /= len;
float sceneLen = length(camPos - sp);
float sceneAtten = min( 1.0 / ( 0.015*sceneLen*sceneLen ), 1.0 );
vec3 ref = reflect(-ld, surfNormal);
float ao = 1.0;
float ambient = .5;
float specularPower = 2.;
float diffuse = max( 0.0, dot(surfNormal, ld) );
float specular = max( 0.0, dot( ref, normalize(camPos-sp)) );
specular = pow(specular, specularPower);
sceneColor += (objColor*(diffuse*0.8+ambient)+specular*0.5)*lcolor*1.3;
sceneColor = mix(sceneColor, vec3(0.), 1.-sceneAtten*sceneAtten);
float shadow = softShadow(sp, lp, .9);
sceneColor *= clamp(shadow + .4, 0., 1.);
return sceneColor;
}
void main() {
vec2 aspect = vec2(u_resolution.x/u_resolution.y, 1.0);
vec2 uv = (2.0*gl_FragCoord.xy/u_resolution.xy - 1.0)*aspect;
movement = vec3(0, 0., u_time / 1.);
vec3 lookAt = vec3(1., 1., 1.);
float t = u_time * .5;
lookAt += vec3(cos(t) * 3., sin(t * .1) * 3., sin(t) * 3.);
vec3 camera_position = vec3(1., 1., -1.0);
lookAt += movement;
camera_position += movement;
vec3 forward = normalize(lookAt-camera_position);
vec3 right = normalize(vec3(forward.z, 0., -forward.x ));
vec3 up = normalize(cross(forward,right));
float FOV = .8;
vec3 ro = camera_position;
vec3 rd = normalize(forward + FOV*uv.x*right + FOV*uv.y*up);
const float clipNear = 0.0;
const float clipFar = 16.0;
float field = 0.;
float dist = rayMarching(ro, rd, clipNear, clipFar, field );
if ( dist >= clipFar ) {
gl_FragColor = vec4(vec3(1.), 1.0);
return;
}
vec3 sp = ro + rd*dist;
vec3 sceneColor = lighting( sp, camera_position, 0, dist, field, rd);
gl_FragColor = vec4(1. - clamp(sceneColor, 0.0, 1.0), 1.0);
}
script>
<div id="container" touch-action="none">div>
CSS
body {
margin: 0;
padding: 0;
}
#container {
position: fixed;
touch-action: none;
}
JS
let container;
let camera, scene, renderer;
let uniforms;
let loader=new THREE.TextureLoader();
let texture;
loader.setCrossOrigin("anonymous");
loader.load(
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/982762/noise.png',
function do_something_with_texture(tex) {
texture = tex;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.minFilter = THREE.LinearFilter;
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_noise: { type: "t", value: texture },
u_mouse: { type: "v2", value: new THREE.Vector2() }
};
var material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
material.extensions.derivatives = true;
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
container.appendChild( renderer.domElement );
onWindowResize();
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener('pointermove', (e)=> {
let ratio = window.innerHeight / window.innerWidth;
uniforms.u_mouse.value.x = (e.pageX - window.innerWidth / 2) / window.innerWidth / ratio;
uniforms.u_mouse.value.y = (e.pageY - window.innerHeight / 2) / window.innerHeight * -1;
e.preventDefault();
});
}
function onWindowResize( event ) {
renderer.setSize( window.innerWidth, window.innerHeight );
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.01;
renderer.render( scene, camera );
}