第一版water 待完善

This commit is contained in:
hawk86104 2024-11-18 11:30:35 +08:00
parent 58b68f4204
commit 935db69e6a
15 changed files with 476 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@ -4,7 +4,7 @@
* @Autor: 地虎降天龙
* @Date: 2024-06-05 16:39:29
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-06-06 11:08:32
* @LastEditTime: 2024-11-18 10:22:57
-->
<template>
<TresMesh ref="tmRef" :rotation-x="-Math.PI / 2">

View File

@ -0,0 +1,55 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2024-11-18 10:52:37
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-11-18 11:25:42
-->
<template>
<Suspense>
<water :waterTexture="waterTexture" :causticsTexture="texture" :light="light" />
</Suspense>
</template>
<script lang="ts" setup>
import * as THREE from 'three'
import { useRenderLoop, useTresContext } from '@tresjs/core'
import vertexShader from '../../shaders/caustics/vertex.glsl'
import fragmentShader from '../../shaders/caustics/fragment.glsl'
import water from './water.vue'
const props = defineProps<{
lightFrontGeometry: THREE.Geometry
waterTexture: THREE.Texture
light: THREE.Light
}>()
const _camera = new THREE.OrthographicCamera(0, 1, 1, 0, 0, 2000)
const _geometry = props.lightFrontGeometry
const texture = new THREE.WebGLRenderTarget(1024, 1024, { type: THREE.UNSIGNED_BYTE })
const material = new THREE.RawShaderMaterial({
uniforms: {
light: { value: props.light },
water: { value: null },
},
vertexShader,
fragmentShader,
})
const _causticMesh = new THREE.Mesh(_geometry, material)
const black = new THREE.Color('black')
const { renderer } = useTresContext()
const { onBeforeLoop } = useRenderLoop()
onBeforeLoop(() => {
_causticMesh.material.uniforms['water'].value = props.waterTexture.texture
renderer.value.setRenderTarget(texture)
renderer.value.setClearColor(black, 0)
renderer.value.clear()
// TODO Camera is useless here, what should be done?
renderer.value.render(_causticMesh, _camera)
})
</script>

View File

@ -0,0 +1,56 @@
<template></template>
<script lang="ts" setup>
import * as THREE from 'three'
import { useRenderLoop, useTresContext, useTexture } from '@tresjs/core'
import vertexShader from '../../shaders/water/vertex.glsl'
import fragmentShader from '../../shaders/water/fragment.glsl'
const props = defineProps<{
waterTexture: THREE.Texture
causticsTexture: THREE.Texture
light: THREE.Light
}>()
const geometry = new THREE.PlaneGeometry(2, 2, 200, 200)
const cubetextureloader = new THREE.CubeTextureLoader()
const textureCube = cubetextureloader
.setPath('https://opensource-1314935952.cos.ap-nanjing.myqcloud.com/images/skyBox/6jpg/')
.load(['pos-x.jpg', 'neg-x.jpg', 'pos-y.jpg', 'neg-y.jpg', 'pos-z.jpg', 'neg-z.jpg'])
const pTexture = await useTexture(['./plugins/water/images/tiles.jpg'])
const material = new THREE.RawShaderMaterial({
uniforms: {
light: { value: props.light },
tiles: { value: pTexture },
sky: { value: textureCube },
water: { value: null },
causticTex: { value: null },
underwater: { value: false },
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
})
const mesh = new THREE.Mesh(geometry, material)
const white = new THREE.Color('white')
const { renderer, camera } = useTresContext()
const { onAfterLoop } = useRenderLoop()
onAfterLoop(() => {
renderer.value.setRenderTarget(null)
renderer.value.setClearColor(white, 1)
renderer.value.clear()
material.uniforms['water'].value = props.waterTexture.texture
material.uniforms['causticTex'].value = props.causticsTexture.texture
material.side = THREE.FrontSide
material.uniforms['underwater'].value = true
renderer.value.render(mesh, camera.value)
material.side = THREE.BackSide
material.uniforms['underwater'].value = false
renderer.value.render(mesh, camera.value)
})
</script>

View File

@ -0,0 +1,87 @@
<template>
<caustics :lightFrontGeometry="_geometry" :waterTexture="texture" :light="light" />
</template>
<script lang="ts" setup>
import * as THREE from 'three'
import { useRenderLoop, useTresContext } from '@tresjs/core'
import vertexShader from '../../shaders/simulation/vertex.glsl'
import dropFragmentShader from '../../shaders/simulation/drop_fragment.glsl'
import normalFragmentShader from '../../shaders/simulation/normal_fragment.glsl'
import updateFragmentShader from '../../shaders/simulation/update_fragment.glsl'
import caustics from './caustics.vue'
const props = defineProps<{
light: THREE.Light
}>()
const _camera = new THREE.OrthographicCamera(0, 1, 1, 0, 0, 2000)
const _geometry = new THREE.PlaneGeometry(2, 2)
const _textureA = new THREE.WebGLRenderTarget(256, 256, { type: THREE.FloatType })
const _textureB = new THREE.WebGLRenderTarget(256, 256, { type: THREE.FloatType })
const dropMaterial = new THREE.RawShaderMaterial({
uniforms: {
center: { value: [0, 0] },
radius: { value: 0 },
strength: { value: 0 },
texture: { value: null },
},
vertexShader,
fragmentShader: dropFragmentShader,
})
const normalMaterial = new THREE.RawShaderMaterial({
uniforms: {
delta: { value: [1 / 256, 1 / 256] }, // TODO: Remove this useless uniform and hardcode it in shaders?
texture: { value: null },
},
vertexShader,
fragmentShader: normalFragmentShader,
})
const updateMaterial = new THREE.RawShaderMaterial({
uniforms: {
delta: { value: [1 / 256, 1 / 256] }, // TODO: Remove this useless uniform and hardcode it in shaders?
texture: { value: null },
},
vertexShader,
fragmentShader: updateFragmentShader,
})
const _dropMesh = new THREE.Mesh(_geometry, dropMaterial)
const _normalMesh = new THREE.Mesh(_geometry, normalMaterial)
const _updateMesh = new THREE.Mesh(_geometry, updateMaterial)
let texture = _textureA
const _render = (renderer, mesh) => {
const oldTexture = texture
const newTexture = texture === _textureA ? _textureB : _textureA
mesh.material.uniforms.texture.value = oldTexture.texture
renderer.setRenderTarget(newTexture)
// TODO Camera is useless here, what should be done?
renderer.render(mesh, _camera)
texture = newTexture
}
const stepSimulation = (renderer) => {
_render(renderer, _updateMesh)
}
const updateNormals = (renderer) => {
_render(renderer, _normalMesh)
}
const white = new THREE.Color('white')
const { renderer } = useTresContext()
const { onBeforeLoop } = useRenderLoop()
onBeforeLoop(() => {
stepSimulation(renderer.value)
updateNormals(renderer.value)
renderer.value.setRenderTarget(null)
renderer.value.setClearColor(white, 1)
renderer.value.clear()
})
</script>

View File

@ -4,7 +4,7 @@
* @Autor: 地虎降天龙
* @Date: 2023-11-10 16:11:27
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-06-06 11:14:12
* @LastEditTime: 2024-11-18 10:04:00
*/
export default {
@ -28,5 +28,12 @@ export default {
title: '自定义水',
referenceSource: { title: 'CustomShaderMaterial', url: 'https://github.com/FarazzShaikh/THREE-CustomShaderMaterial' },
},
{
src: 'plugins/water/preview/realWater.png',
type: 'img',
name: 'realWater',
title: '真实水',
referenceSource: { title: 'realWater', url: 'https://github.com/martinRenou/threejs-water' },
},
],
}

View File

@ -0,0 +1,35 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2024-11-18 08:56:34
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-11-18 11:05:59
-->
<template>
<TresCanvas v-bind="state" window-size>
<TresPerspectiveCamera :position="[0.426, 0.677, -2.095]" :fov="75" :near="0.01" :far="1000" />
<OrbitControls />
<TresAmbientLight :intensity="0.5" />
<TresDirectionalLight ref="tdLight" :position="[0.7559289460184544, 0.7559289460184544, -0.3779644730092272]" :intensity="1" />
<waterSimulation v-if="tdLight" :light="tdLight" />
</TresCanvas>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
import waterSimulation from '../components/realWater/waterSimulation.vue'
const state = reactive({
alpha: true,
antialias: true,
windowSize: true,
autoClear: false,
renderMode: 'manual',
// clearColor: 0x999999,
})
const tdLight = ref(null)
</script>

View File

@ -0,0 +1,24 @@
precision highp float;
precision highp int;
#extension GL_OES_standard_derivatives : enable
#include <utils>
varying vec3 oldPos;
varying vec3 newPos;
varying vec3 ray;
void main() {
/* if the triangle gets smaller, it gets brighter, and vice versa */
float oldArea = length(dFdx(oldPos)) * length(dFdy(oldPos));
float newArea = length(dFdx(newPos)) * length(dFdy(newPos));
gl_FragColor = vec4(oldArea / newArea * 0.2, 1.0, 0.0, 0.0);
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER);
/* shadow for the rim of the pool */
vec2 t = intersectCube(newPos, -refractedLight, vec3(-1.0, -poolHeight, -1.0), vec3(1.0, 2.0, 1.0));
gl_FragColor.r *= 1.0 / (1.0 + exp(-200.0 / (1.0 + 10.0 * (t.y - t.x)) * (newPos.y - refractedLight.y * t.y - 2.0 / 12.0)));
}

View File

@ -0,0 +1,34 @@
precision highp float;
precision highp int;
varying vec3 oldPos;
varying vec3 newPos;
varying vec3 ray;
attribute vec3 position;
#include <utils>
/* project the ray onto the plane */
vec3 project(vec3 origin, vec3 ray, vec3 refractedLight) {
vec2 tcube = intersectCube(origin, ray, vec3(-1.0, -poolHeight, -1.0), vec3(1.0, 2.0, 1.0));
origin += ray * tcube.y;
float tplane = (-origin.y - 1.0) / refractedLight.y;
return origin + refractedLight * tplane;
}
void main() {
vec4 info = texture2D(water, position.xy * 0.5 + 0.5);
info.ba *= 0.5;
vec3 normal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a);
/* project the vertices along the refracted vertex ray */
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER);
ray = refract(-light, normal, IOR_AIR / IOR_WATER);
oldPos = project(position.xzy, refractedLight, refractedLight);
newPos = project(position.xzy + vec3(0.0, info.r, 0.0), ray, refractedLight);
gl_Position = vec4(0.75 * (newPos.xz + refractedLight.xz / refractedLight.y), 0.0, 1.0);
}

View File

@ -0,0 +1,22 @@
precision highp float;
precision highp int;
const float PI = 3.141592653589793;
uniform sampler2D texture;
uniform vec2 center;
uniform float radius;
uniform float strength;
varying vec2 coord;
void main() {
/* Get vertex info */
vec4 info = texture2D(texture, coord);
/* Add the drop to the height */
float drop = max(0.0, 1.0 - length(center * 0.5 + 0.5 - coord) / radius);
drop = 0.5 - cos(drop * PI) * 0.5;
info.r += drop * strength;
gl_FragColor = info;
}

View File

@ -0,0 +1,19 @@
precision highp float;
precision highp int;
uniform sampler2D texture;
uniform vec2 delta;
varying vec2 coord;
void main() {
/* get vertex info */
vec4 info = texture2D(texture, coord);
/* update the normal */
vec3 dx = vec3(delta.x, texture2D(texture, vec2(coord.x + delta.x, coord.y)).r - info.r, 0.0);
vec3 dy = vec3(0.0, texture2D(texture, vec2(coord.x, coord.y + delta.y)).r - info.r, delta.y);
info.ba = normalize(cross(dy, dx)).xz;
gl_FragColor = info;
}

View File

@ -0,0 +1,33 @@
precision highp float;
precision highp int;
uniform sampler2D texture;
uniform vec2 delta;
varying vec2 coord;
void main() {
/* get vertex info */
vec4 info = texture2D(texture, coord);
/* calculate average neighbor height */
vec2 dx = vec2(delta.x, 0.0);
vec2 dy = vec2(0.0, delta.y);
float average = (
texture2D(texture, coord - dx).r +
texture2D(texture, coord - dy).r +
texture2D(texture, coord + dx).r +
texture2D(texture, coord + dy).r
) * 0.25;
/* change the velocity to move toward the average */
info.g += (average - info.r) * 2.0;
/* attenuate the velocity a little so waves do not last forever */
info.g *= 0.995;
/* move the vertex along the velocity */
info.r += info.g;
gl_FragColor = info;
}

View File

@ -0,0 +1,9 @@
attribute vec3 position;
varying vec2 coord;
void main() {
coord = position.xy * 0.5 + 0.5;
gl_Position = vec4(position.xyz, 1.0);
}

View File

@ -0,0 +1,69 @@
precision highp float;
precision highp int;
#include <utils>
uniform float underwater;
uniform samplerCube sky;
varying vec3 eye;
varying vec3 pos;
vec3 getSurfaceRayColor(vec3 origin, vec3 ray, vec3 waterColor) {
vec3 color;
if (ray.y < 0.0) {
vec2 t = intersectCube(origin, ray, vec3(-1.0, -poolHeight, -1.0), vec3(1.0, 2.0, 1.0));
color = getWallColor(origin + ray * t.y);
} else {
vec2 t = intersectCube(origin, ray, vec3(-1.0, -poolHeight, -1.0), vec3(1.0, 2.0, 1.0));
vec3 hit = origin + ray * t.y;
if (hit.y < 7.0 / 12.0) {
color = getWallColor(hit);
} else {
color = textureCube(sky, ray).rgb;
color += 0.01 * vec3(pow(max(0.0, dot(light, ray)), 20.0)) * vec3(10.0, 8.0, 6.0);
}
}
if (ray.y < 0.0) color *= waterColor;
return color;
}
void main() {
vec2 coord = pos.xz * 0.5 + 0.5;
vec4 info = texture2D(water, coord);
/* make water look more "peaked" */
for (int i = 0; i < 5; i++) {
coord += info.ba * 0.005;
info = texture2D(water, coord);
}
vec3 normal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a);
vec3 incomingRay = normalize(pos - eye);
if (underwater == 1.) {
normal = -normal;
vec3 reflectedRay = reflect(incomingRay, normal);
vec3 refractedRay = refract(incomingRay, normal, IOR_WATER / IOR_AIR);
float fresnel = mix(0.5, 1.0, pow(1.0 - dot(normal, -incomingRay), 3.0));
vec3 reflectedColor = getSurfaceRayColor(pos, reflectedRay, underwaterColor);
vec3 refractedColor = getSurfaceRayColor(pos, refractedRay, vec3(1.0)) * vec3(0.8, 1.0, 1.1);
gl_FragColor = vec4(mix(reflectedColor, refractedColor, (1.0 - fresnel) * length(refractedRay)), 1.0);
} else {
vec3 reflectedRay = reflect(incomingRay, normal);
vec3 refractedRay = refract(incomingRay, normal, IOR_AIR / IOR_WATER);
float fresnel = mix(0.25, 1.0, pow(1.0 - dot(normal, -incomingRay), 3.0));
vec3 reflectedColor = getSurfaceRayColor(pos, reflectedRay, abovewaterColor);
vec3 refractedColor = getSurfaceRayColor(pos, refractedRay, abovewaterColor);
gl_FragColor = vec4(mix(refractedColor, reflectedColor, fresnel), 1.0);
}
}

View File

@ -0,0 +1,24 @@
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform sampler2D water;
attribute vec3 position;
varying vec3 eye;
varying vec3 pos;
void main() {
vec4 info = texture2D(water, position.xy * 0.5 + 0.5);
pos = position.xzy;
pos.y += info.r;
vec3 axis_x = vec3(modelViewMatrix[0].x, modelViewMatrix[0].y, modelViewMatrix[0].z);
vec3 axis_y = vec3(modelViewMatrix[1].x, modelViewMatrix[1].y, modelViewMatrix[1].z);
vec3 axis_z = vec3(modelViewMatrix[2].x, modelViewMatrix[2].y, modelViewMatrix[2].z);
vec3 offset = vec3(modelViewMatrix[3].x, modelViewMatrix[3].y, modelViewMatrix[3].z);
eye = vec3(dot(-offset, axis_x), dot(-offset, axis_y), dot(-offset, axis_z));
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}