思路
1、随便实现一个着色模型。
2、然后传入 世界坐标Y值。
3、根据Y值 在偏元着色器,舍弃,不需要的片元。
代码直接全部贴了。
测试主逻辑代码
test(): void {
//加载IDE指定的场景
let scene: Laya.Scene3D = Laya.stage.addChild(new Laya.Scene3D()) as any;
let camera = new Laya.Camera();
let light = new Laya.DirectionLight();
let sphere = new Laya.MeshSprite3D(Laya.PrimitiveMesh.createSphere(5));
let mat = new ChangeVisibleMat();
scene.addChild(sphere);
scene.addChild(camera);
scene.addChild(light);
light.transform.localPosition = new Laya.Vector3(50, 25, 15);
light.transform.lookAt(sphere.transform.position, new Laya.Vector3(0, 1, 0));
camera.transform.position = new Laya.Vector3(15, 15, 15);
camera.transform.lookAt(sphere.transform.position, new Laya.Vector3(0, 1, 0));
camera.farPlane = 100;
Laya.timer.frameLoop(1, this, () => {
sphere.transform.localRotationEulerY += 0.005;
})
Laya.loader.load("res/dimian_04.jpg", Laya.Handler.create(this, () => {
let tex = Laya.loader.getRes("res/dimian_04.jpg");
mat.texture = tex;
let direction = new Laya.Vector3();
light.transform.getForward(direction);
direction.setValue(direction.x * -1, direction.y * -1, direction.z * -1);
mat.directionLight = direction;
mat.colorLight = light.color.clone();
// mat.borderColor = new Laya.Vector3(0.5, 0.5, 0.5)
// let mat = new Laya.BlinnPhongMaterial();
sphere.meshRenderer.material = mat;
Laya.timer.loop(100, this, () => {
mat.visibleY += 0.01;
})
}));
}
材质mat代码
export default class ChangeVisibleMat extends Laya.Material {
private PHONE_TEXTURE = Laya.Shader3D.propertyNameToID("u_Texture");
private DIRECTION_LIGHT = Laya.Shader3D.propertyNameToID("u_DirectionLight_");
private COLOR_LIGHT = Laya.Shader3D.propertyNameToID("u_ColorLight_");
private Y = Laya.Shader3D.propertyNameToID("u_y");
constructor() {
super();
this.setShaderName("ChangeVisibleShader");
this._shaderValues.setNumber(this.Y, 0);
}
set visibleY(Y: number) {
this._shaderValues.setNumber(this.Y, Y);
}
get visibleY(): number {
return this._shaderValues.getNumber(this.Y);
}
set directionLight(direction: Laya.Vector3) {
this._shaderValues.setVector3(this.DIRECTION_LIGHT, direction);
}
get directionLight(): Laya.Vector3 {
return this._shaderValues.getVector3(this.DIRECTION_LIGHT);
}
set colorLight(color: Laya.Vector3) {
this._shaderValues.setVector3(this.COLOR_LIGHT, color);
}
get colorLight(): Laya.Vector3 {
return this._shaderValues.getVector3(this.COLOR_LIGHT);
}
set texture(tex) {
this._shaderValues.setTexture(this.PHONE_TEXTURE, tex);
}
}
shader文件
import PhoneVs from "./ChangeVisibleShaderVS.vs";
import PhoneFs from "./ChangeVisibleShaderFS.fs";
export default class ShaderChangeVisible {
initShader(): void {
//所有的attributeMap属性
var attributeMap = {
'a_Position': Laya.VertexMesh.MESH_POSITION0,
'a_Normal': Laya.VertexMesh.MESH_NORMAL0,
'a_Texcoord': Laya.VertexMesh.MESH_TEXTURECOORDINATE0,
'a_BoneWeights': Laya.VertexMesh.MESH_BLENDWEIGHT0,
'a_BoneIndices': Laya.VertexMesh.MESH_BLENDINDICES0
};
//所有的uniform属性
var uniformMap = {
'u_Bones': Laya.Shader3D.PERIOD_CUSTOM,//绑定
'u_CameraPos': Laya.Shader3D.PERIOD_CAMERA,
'u_DirectionLight_': Laya.Shader3D.PERIOD_MATERIAL,
'u_ColorLight_': Laya.Shader3D.PERIOD_MATERIAL,
'u_MvpMatrix': Laya.Shader3D.PERIOD_SPRITE,
'u_WorldMat': Laya.Shader3D.PERIOD_SPRITE,
'u_Texture': Laya.Shader3D.PERIOD_MATERIAL,
'u_y': Laya.Shader3D.PERIOD_MATERIAL,
};
var customShader = Laya.Shader3D.add("ChangeVisibleShader");
var subShader = new Laya.SubShader(attributeMap, uniformMap);
customShader.addSubShader(subShader);
let a = subShader.addShaderPass(PhoneVs, PhoneFs);
a.renderState.cull = Laya.RenderState.CULL_NONE;
}
}
fs
#ifdef FSHIGHPRECISION
precision highp float;
#else
precision mediump float;
#endif
#include "Lighting.glsl";
varying vec2 v_Texcoord;
uniform vec3 u_DirectionLight_;
uniform vec3 u_ColorLight_;
uniform vec3 u_BoderColor;
uniform float u_y;
varying vec3 v_Normal;
uniform sampler2D u_Texture;
uniform vec3 u_CameraPos;
varying vec3 v_PositionWorld;
void main()
{
//环境光
vec3 ambColor = texture2D(u_Texture,v_Texcoord).xyz;
// //高光
float cosValue = max(0.0,dot(v_Normal,u_DirectionLight_));
vec3 specular = texture2D(u_Texture,v_Texcoord).xyz*pow(cosValue,5.0);
// //漫反射
vec3 diffuse = texture2D(u_Texture,v_Texcoord).xyz*cosValue;
vec3 color = ambColor*0.15 + diffuse*0.5 + specular*1.5;
if(u_y < 0.0001){
gl_FragColor = vec4(color,1.0);
}else{
if(v_PositionWorld.y<u_y){
gl_FragColor = vec4(color,1.0);
}else{
discard;
}
}
}
vs
#include "Lighting.glsl";
attribute vec4 a_Position;
attribute vec2 a_Texcoord;
attribute vec3 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_WorldMat;
// uniform float u_y;
varying vec2 v_Texcoord;
varying vec3 v_Normal;
#ifdef BONE
attribute vec4 a_BoneIndices;
attribute vec4 a_BoneWeights;
const int c_MaxBoneCount = 24;//数量
uniform mat4 u_Bones[c_MaxBoneCount];//骨骼
#endif
varying vec3 v_PositionWorld;
void main()
{
#ifdef BONE
mat4 skinTransform=mat4(0.0);
skinTransform += u_Bones[int(a_BoneIndices.x)] * a_BoneWeights.x;
skinTransform += u_Bones[int(a_BoneIndices.y)] * a_BoneWeights.y;
skinTransform += u_Bones[int(a_BoneIndices.z)] * a_BoneWeights.z;
skinTransform += u_Bones[int(a_BoneIndices.w)] * a_BoneWeights.w;
vec4 position = skinTransform * a_Position;
gl_Position=u_MvpMatrix * position;
mat3 worldMat=mat3(u_WorldMat * skinTransform);
#else
gl_Position=u_MvpMatrix * a_Position ;
mat3 worldMat=mat3(u_WorldMat);
#endif
v_Texcoord=a_Texcoord;
v_Normal=worldMat*a_Normal;
#ifdef BONE
v_PositionWorld=(u_WorldMat*position).xyz;
#else
v_PositionWorld=(u_WorldMat*a_Position).xyz;
#endif
}
加载shader
import ShaderChangeVisible from "./ChangeVisibleShader/ShaderChangeVisible";
export default class ShaderMgr {
private static _Inst: ShaderMgr = null;
public static get Inst(): ShaderMgr {
if (ShaderMgr._Inst == null) ShaderMgr._Inst = new ShaderMgr();
return ShaderMgr._Inst;
}
initShader(): void {
//shader工具
//边缘发光
//
new ShaderChangeVisible().initShader();
}
}
效果如下