目录
一,Ocean Setup
设置海洋Surface Grid(使用Large Ocean工具架)
- 调节默认Grid的大小尺寸及细分(使用非常小尺寸来测试);
- 调整频谱输入点的多少,频谱Grid Size,波浪方向,速度,起伏大小等等,以确定surface形态及动态;
按离相机远近细分Grid以展现足够细节,并删除相机额外的部分;
- TriDivide
//转化为相机坐标
@P = fromNDC('/obj/camera', @P);
将频谱分为低频和高频(particle fluid mask)
- 高频用于渲染;
二,Water Setup
解算前设置
容器设置
- 使用预设的Tank设置,并根据角色轨迹,绘制交互范围;
- 目的是减少模拟区域,以提高解算效率;
容器及解算器参数调整
FLIP Container
- 设置粒子间隔为0.2,Grid Scale为2.2;
- 测试时粒子间隔可以适当调大(如0.6),以快速迭代;
- 由于是大尺寸镜头,可稍微降低体素精度Grid Scale(默认为2);
- 添加vorticity、id、及relativedensity属性;
FLIP Sover
- 解算器最大子步为1(默认2);
- 设置为FLIP(Swirly)模式;
- Velocity Smoothing(0.01),以更加飞溅;
碰撞体设置
- FLIP Collide,关闭Surface Collide(贵);
- FLIP Sover,使用Move Outside Collidion;
- File Cache,缓存碰撞体以增加解算效率,Cache Frames预加载一帧以加速解算;
- primitive(16bit),优化缓存大小;
由于ocean surface是有波浪变形的,而解算时的水面时未变形平静的,最后水面变形会与碰撞体不匹配的,解决方法有:
- Guide Simulation,引入引导的surface和vel,会非常的慢;
- 对于比较平静的海面,可使用海洋频谱反向变形碰撞体,最后还原碰撞体;
注,可只模拟特定范围,以快速模拟测试;
解算设置
- 删除空中飞溅的小块,通过体素内粒子密度判断;
- volume rasterize particles
- 添加阻力POP Drag(0.15);
- 对分离的低密度粒子使用更高的阻力;
airresist *= fit(@ptdensity, 3, 8, 1, 0.05);
- 添加些噪波POP Force;
- 针对水面以上的粒子,低密度粒子或碰撞体周围的粒子;
float mask = fit(@P.y, 1, 2, 0, 1); mask *= max(fit(@ptdensity, 6, 15, 1, 0), fit(volumesample(1,0,@P), 0.5, 2, 1, 0)); @nosemask = mask;
- 添加最大速度限制POP Speed Limit;
注,Gas Project Non Divergent Adaptive节点Error Tolerance默认非常慢,改为0.01;
解算后设置
压缩以减少缓存大小
- Fluid Compress,压缩粒子及volume;
针对粒子压缩:
- 如相机相对稳定,也可删除相机外的粒子;
- 如pscale值一样,可转化为detail属性;
- 压缩属性值为16bit(attribute cast),如v、vorticity;
- 删除不必要的属性;
- Convert VDB Points,使用vdb存储点,以压缩数据;
针对volume压缩:
- vel场可不用完全的精度,如降低2倍(VDB Resample);
- 降低surface场激活体素(VDB Active SDF);
三,Meshing Setup
- 注意避免水花和边界碰撞;
- 控制flip解算精度,避免添加过多的细节;大部分细节来自于whitwater;
注,取小范围解算粒子,以快速测试mesh;
Meshing
- 先解包vdb点,在还原pscale属性;
- Particle Fluid Surface,Spherical模式会快很多;
- 可降低voxel scale以提高精度;
- 提高adaptivity自适应;
- 勾选过滤内的smooth,以控制表面凹凸不平;
注,如空中mesh大块太大,可调节pscale属性;还可根据粒子相对密度,来控制pscale属性;速度向下时,可认为已转化为白水;
//向下掉落时,越来越小 @pscale *= fit(@P.y,2,30,1,0.4) * fit(@v.y,-1,-13,1,0.6) * fit(@ptdensity,2,16,0.4,1);
注,通过v,对凹凸不平的表面模糊平滑(blur,deltamush);
剔除外围边界mesh
- 根据绘制的边界曲线,压平y轴;
- 根据边界框和相机,剔除外围边界mesh;
- 控制边界v、vorticity;
float dist = xyzdist(1, @P);
float depth = volumesample(2,0,@P);
float multi = fit(dist,2,12,0,1);
if(depth < -1) i@group_keep=1;
@P.y *= multi;
@v *= multi;
@vorticity *= multi;
应用低频频谱变形并添加变形速度
- 在blast剔除前应用;
- 将频谱变形的速度,添加到解算速度上;
为whitewater创建自定义的surface、vel
- 对变形后的mesh生成surface、vel(vdb from polygon);
- 降低vel场的精度vdb resample(降低2倍),调整激活范围vdb activate;
- 将这两个场存储为16位(primitive);
清理属性和组并缓存
- 分开缓存mesh,和surface、vel(白水最关心此两个场);
- 由于此两个缓存有许多共同的节点,单独缓存会重复计算;
- 针对用于白水的surface、vel缓存,可Cache Frames预加载一帧以加速解算;
//缓存water_surface节点时,先缓存water_fields
fieldsNode = hou.node('/obj/water_sim/water_fields/render')
fieldsNode.render(frame_range=(hou.frame(), hou.frame()))
四,Whitewater Source Setup
- 对缓存的surface/vel场,Cache Frames预加载一帧以加速解算;
生成对白水影响的空气场
- 以角色作为发射源,生成烟雾,模拟精度可适当调低;
- 使用水体surface场、角色,作为碰撞场;
- 应用于force_output接口;
- 使用Gas Vortex Confinement添加更多的涡旋;
- 对其缓存Cache Frames预加载一帧以加速解算;
- 限制最大速度;
float speed = length(v@vel);
v@vel = v@vel/speed * min(speed, 20);
水面白水发射源粒子
- 使用已经变形后的mesh,定义发射源区域(通过mesh的curvature,vorticity,v);
- 使用默认whitewater source节点(使用解算后的压缩粒子)生成emission volume,不理想;
- 对发射区域模糊,以形成自然的过渡;
- 在发射区域scatter撒点,并删除不必要的属性(保留emission、v);
- 对emission压缩属性值为16bit(attribute cast);
- 并转化为vdb存储点Convert VDB Points,以压缩数据;
- 缓存此发射源粒子;
//控制发射区域
int pts[] = pcfind(0, "P", @P, ch("radius"), chi("maxpts"));
float curature = 0;
foreach(int pt; pts){
vector closeP = point(0, "P", pt);
vector Pdiff = normalize(@P - closeP);
curature += max(0, dot(Pdiff, @N));
}
@emission = fit(curature, 0.1, 1, 0, 1) * fit(@vorticity, 0.5, 2, 0, 1) * fit(length2(@v), 8, 100, 0, 1);
增加白水发射源粒子并添加更多细节
- 解包发射源粒子vdb点;
- 对速度属性v,添加noise;
- anti-aliased noise,只改变方向,不改变大小;
- random,随机速度大小(0.9~1);
- 添加粒子数量,point replicate;
- 通过属性控制复制的量,速度大的地方粒子复制多;
- 略微向速度方向移动下粒子,避免粒子太靠近surface;
@replicate = clamp(length(@v)*0.1, 1, ch('maxpts'));
@P += @v * 0.4/24;
- 由于解算的飞溅粒子,相对成块,在对位置添加些noise(attribute noise);
- 为更像水花的结构,可在添加平滑(attribute blur);
- 在使用point replicate增加粒子数量;
- 设置粒子寿命life;
@life = fit01(@emission, 2, 6) * fit01(rand(@ptnum+@Time),0.8,1.2);
角色身体白水发射源粒子
- 控制角色发射区域,为避免发射位置杂乱可先平滑模型;
- 使用peak稍微向外扩开些;
- 使用aanoise打破发射源并随时间删除发射粒子;
int pts[] = pcfind(0, "P", @P, ch("radius"), chi("maxpts"));
float curature = 0;
foreach(int pt; pts){
vector closeP = point(0, "P", pt);
vector Pdiff = normalize(@P - closeP);
curature += dot(Pdiff, @N);
}
//曲率控制
@emission = fit(curature, -0.5, 0.1, 1, 0);
//方向控制,向下的面发射较少
@emission *= fit(dot(@N, set(0,1,0)), -1, 1, 0.2, 1);
//高度控制
@emission *= fit(@P.y, -3, -2, 0, 1);
//出水时间控制
@emission *= fit(@Frame, 1060, 1180, 1, 0.3);
@Cd = @emission;
五,Whitewater Setup
解算控制
使用默认的whitewater solver节点,不会有很好的控制(如air场);直接使用POP solver节点,以获取更多控制;
- 添加重力POP Force,并通过粒子密度控制重力;;
force *= fit(@ptdensity, 0, 4, 0.6, 1);
- 删除水面过低不必要的粒子POP Kill;
//删除水面过低不必要的粒子
if(@P.y<-3.5) dead = 1;
- 邻近的粒子间速度会大致相同(通过张力等),通过转化的速度场实现;
- 可使用编译块,以提高运行速度;
@ptdensity = pow(volumesample(1,0,@P), 0.5);
float ratio = fit(@age, 0.5, 5, 0.5, 0.1);
@v = lerp(@v, volumesamplev(2,0,@P), ratio);
- 使用空气场驱动粒子,并通过粒子密度控制airresistance;
airresist *= fit(@ptdensity, 0, 3, 1, 0.2*rand(@id));
airresist *= fit(@age, 0, 0.8, 0.65, 1);
- 降低高密度区的点数,避免粒子过渡聚集;
//降低高密度区的点数,避免粒子过渡聚集;
if(rand(@id+532) < fit(@ptdensity, 8, 15, 0, 1))
dead = 1;
- 对高密度区速度引入noise,以破开形态;
- 与水面交互,将水面内部的粒子推出到表面并附加水面速度(pop advect by volumes);
@depth = volumesample(0, 'surface', @P) - 0.05;
if(@depth < 0){
vector grad = normalize(volumegradient(0, 'surface', @P));
@P -= grad * @depth;
}
- 与角色交互,角色相对高精度,将内部的粒子推出到表面;
- 反弹速度reflvel的切线速度(反弹速度减去法线速度);
- 并随机融合些角色碰撞速度;
@depth = volumesample(0, 'surface', @P) - 0.05;
if(@depth < 0){
vector grad = normalize(volumegradient(0, 'surface', @P));
@P -= grad * @depth;
vector collisionvel = volumesamplev(0, 'vel', @P);
vector refvel = reflect(@v, grad);
refvel -= grad*dot(grad, refvel) * 0.9;
float bias = fit01(rand(@id + 145), 0.05, 0.15);
@v = lerp(refvel, collisionvel, bias);
}
wedding缓存
- 为避免内存溢出,可分割发射源分开缓存(使用wedge);
- 删除相机外和角色背后的粒子,以优化缓存(VDB Occlusion Mask);
- 删除不必要的属性和组;
- 缓存时,记得缓存为不同文件夹;
`chs("basedir") + "/" + chs("basename")``ifs(ch("enableversion"), "/" + chs("versionstr"),"")`/wedge`@wedgenum`
合并缓存
- File Merge,可将wedding后缓存一起加载;
六,Solaris Render
角色导入及环境预设
- Reference导入对应的usd模型;
- 添加demelight,并添加环境贴图hdr;
- 默认karma渲染可能非常模糊,关闭Enable Depth of Field;
- 通过Correction Toolbar,设置ACES;
Surface导入
Ocean surface
- 将Ocean surface分为远近两部分,近景surface删除解算部分;
- 使用Ocean Evaluate(用低频low)变形surface,在不改变外形的情况下调整下采样(如3);
FLIP Surface
- 计算用于渲染泡沫的区域(通过curature、vorticity、v);
- 删除渲染时完全透明的点;
whitewater导入
- 对水面白水和身体白水分开,水面白水density为1,身体白水density为0.5;
- 通过标准化年龄和点稀疏度调整density;
//生命控制密度
@density *= fit(@normalize_age, 0, 1, 1, 0.05) * fit(@normalize_age, 0, 0.01, 0.5, 1);
//粒子稀疏控制密度,越稀密度越低
@density *= fit(@ptdensity, 0.5, 2, 0.5, 1);
- 轻微将粒子朝相机移动,以避免非常靠近角色或水面的粒子渲染丢失;
vector camP = point(1, 'P', 0);
@P += normalize(camP - @P)*0.1;
- 将粒子转化为VDB;
- 为渲染过的最大细节,可将每个像素对应一个体素(如相机分辨率为1920*820,则设置1920);
- 直接添加运动模糊,包括本身运动和相机运动(避免创建速度场使用渲染器渲染生成运动模糊,效率低);
//补偿相机速度
//将点x/y轴位置转化为0-1的区间,计算此区间点的前后0.25帧位置
@P = toNDC('/obj/camera', @P);
//在还原前后0.25帧的位置,即可计算相机运动
vector P1 = point(1, 'P', @ptnum);
vector P2 = point(2, 'P', @ptnum);
P1 = fromNDC('/obj/camera', P1);
P2 = fromNDC('/obj/camera', P2);
@v += (P2 - P1) * 24 * 2;
- 估计density场,计算并生成梯度场gradient,用于渲染反射;
- 创建低精度density(如1920/2),用于投射阴影和反射;
创建海洋材质
- 设置海洋材质表面着色(Classic Shader Core),设置对应的反射折射,无漫反射;
- 水材质,打破海洋表面的统一,对反射的specular roughness添加aanoise(使用rest并去除y方向的值);
- 泡沫材质,在特定区域显示该泡沫材质;
- 海洋表面随机aanoise区域,及高emission区域;
- 对飞溅出来的水块,影响真实性,这些水块周围会有大量白水,可通过透明度隐藏;
- 由于透明会非常影响渲染,所以对那些完全透明的点提前删除;
- 设置海洋材质高频置换(Ocean Sample Layers);
注,Render Geometry Settings以下置换参数非常耗资源,测试时可关闭;
创建白水材质
- 直接将basicwhitewater从默认材质库中复制到即可Solaris内材质库内即可;
- 对gradient场取反;
- 使用pyroshadercore替代volumeshadercore(无shadow color);
渲染分层
对导入的角色引用,设置激活变量(如@swith_creature、@swith_bird),对应水面和白水使用switch节点切换,以便在分层时,根据此变量选择对应的对象;使用Edit Context Options节点选择对象;
- karma_ocean_far,远处水面,注意要开点速度用于速度模糊,Dicing细分置换;
- primary samples:16,max secondary samples:4;
- diffuse limit:0,reflection limit:2,refraction limit:1;
- 压缩DWA-A,Lossy and Fast(32-scaline block);
- karma_FLIP,近处水面及解算水,使用低精度白水作阴影和反射;
- primary samples:16,max secondary samples:4;
- diffuse limit:1,reflection limit:2,refraction limit:1;
- 压缩DWA-A,Lossy and Fast(32-scaline block);
- karma_whitewater,白水,以水面和角色为遮罩(不需次级射线-diffuse&-reflect&-refract),可不考虑水面Dicing细分置换;
- primary samples:32,max secondary samples:1;
- diffuse limit:0,reflection limit:1,refraction limit:0;
- 压缩DWA-A,Lossy and Fast(32-scaline block);
- karma_bird,角色鸟;
注:为得到正确运动模糊(对变形动画),需让渲染器知道在当前帧之前和之后的时间采样,使用Cache节点;
批量渲染
- 针对指定渲染层渲染时所占内存大小,调整每批次渲染的帧树;
- Wait for All 即渲染前面所有后,在进行下面渲染;
七,合成
- 使用aces颜色空间;
- 导入渲染的素材,即提供的环境背景;
- 通过相机投射环境背景;
- 通过素材的depth层,将素材融入环境背景;
- 对白水Bilateral模糊,并叠加到素材上;
- 输出时也得调整颜色空间(Output-sRGB);