@@ -3,31 +3,39 @@ package cn.coostack.cooparticlesapi.particles
33import cn.coostack.cooparticlesapi.particles.control.ControlParticleManager
44import cn.coostack.cooparticlesapi.particles.control.ParticleControler
55import cn.coostack.cooparticlesapi.utils.Math3DUtil
6- import com.mojang.blaze3d.platform.GlStateManager
7- import com.mojang.blaze3d.systems.RenderSystem
6+ import cn.coostack.cooparticlesapi.utils.RelativeLocation
87import net.fabricmc.api.EnvType
98import net.fabricmc.api.Environment
10- import net.minecraft.client.particle.Particle
119import net.minecraft.client.particle.ParticleTextureSheet
1210import net.minecraft.client.particle.SpriteBillboardParticle
1311import net.minecraft.client.render.Camera
1412import net.minecraft.client.render.LightmapTextureManager
1513import net.minecraft.client.render.VertexConsumer
1614import net.minecraft.client.world.ClientWorld
17- import net.minecraft.particle.ParticleTypes
1815import net.minecraft.util.math.Box
16+ import net.minecraft.util.math.MathHelper
1917import net.minecraft.util.math.Vec3d
2018import net.minecraft.util.math.random.Random
19+ import org.joml.Matrix4f
20+ import org.joml.Quaternionf
2121import org.joml.Vector2f
2222import org.joml.Vector3f
23+ import org.joml.Vector4f
24+ import org.lwjgl.opengl.GL11
2325import java.util.*
26+ import kotlin.math.PI
27+
2428
2529@Environment(EnvType .CLIENT )
2630abstract class ControlableParticle (
2731 world : ClientWorld ,
2832 pos : Vec3d ,
2933 velocity : Vec3d ,
30- val controlUUID : UUID
34+ val controlUUID : UUID ,
35+ /* *
36+ * 是否始终转向玩家(默认实现)
37+ */
38+ val faceToCamera : Boolean = true
3139) : SpriteBillboardParticle(world, pos.x, pos.y, pos.z, velocity.x, velocity.y, velocity.z) {
3240 val controler: ParticleControler = ControlParticleManager .getControl(controlUUID)!!
3341
@@ -180,10 +188,16 @@ abstract class ControlableParticle(
180188 alpha = value.coerceIn(0f , 1f )
181189 }
182190
191+ var previewAngleX: Float = 0f
192+ var currentAngleX: Float = 0f
193+
194+ var previewAngleY: Float = 0f
195+ var currentAngleY: Float = 0f
196+
183197 /* *
184198 * @see prevAngle
185199 */
186- var previewAngle : Float
200+ var previewAngleZ : Float
187201 get() = prevAngle
188202 set(value) {
189203 prevAngle = value
@@ -192,7 +206,7 @@ abstract class ControlableParticle(
192206 /* *
193207 * @see angle
194208 */
195- var currentAngle : Float
209+ var currentAngleZ : Float
196210 get() = angle
197211 set(value) {
198212 angle = value
@@ -238,6 +252,22 @@ abstract class ControlableParticle(
238252 controler.particleInit()
239253 }
240254
255+ var lastRotate = Vector3f (previewAngleX, previewAngleY, previewAngleZ)
256+ var updateRotate = false
257+ fun rotateParticleTo (target : RelativeLocation ) {
258+ rotateParticleTo(Vector3f (target.x.toFloat(), target.y.toFloat(), target.z.toFloat()))
259+ }
260+
261+ fun rotateParticleTo (target : Vec3d ) {
262+ rotateParticleTo(target.toVector3f())
263+ }
264+
265+ fun rotateParticleTo (target : Vector3f ) {
266+ val (x, y, z) = Math3DUtil .calculateEulerAnglesToPoint(target)
267+ updateRotate = true
268+ lastRotate = Vector3f (x, y, z)
269+ }
270+
241271 /* *
242272 * 防止频繁调用Math3DUtil (让键盘休息一会)
243273 * 也不用调用 color = Vector3f(xxx/255f,xxx/255f,xxx/255f)
@@ -264,13 +294,128 @@ abstract class ControlableParticle(
264294 super .tick()
265295 }
266296 controler.doTick()
297+ prevPos = this .pos
267298 if (update) {
268299 prevPos = this .pos
269300 this .pos = lastPreview
270301 update = false
271302 }
303+ previewAngleX = currentAngleX
304+ previewAngleY = currentAngleY
305+ previewAngleZ = currentAngleZ
306+ if (updateRotate) {
307+ currentAngleX = lastRotate.x
308+ currentAngleY = lastRotate.y
309+ currentAngleZ = lastRotate.z
310+ updateRotate = false
311+ }
272312 }
273313
314+ override fun buildGeometry (vertexConsumer : VertexConsumer , camera : Camera , tickDelta : Float ) {
315+ if (faceToCamera) {
316+ super .buildGeometry(vertexConsumer, camera, tickDelta)
317+ return
318+ }
319+ // 获取摄像机位置
320+ val cameraPos = camera.pos
321+ val x = (MathHelper .lerp(tickDelta.toDouble(), this .prevPosX, this .x) - cameraPos.getX()).toFloat()
322+ val y = (MathHelper .lerp(tickDelta.toDouble(), this .prevPosY, this .y) - cameraPos.getY()).toFloat()
323+ val z = (MathHelper .lerp(tickDelta.toDouble(), this .prevPosZ, this .z) - cameraPos.getZ()).toFloat()
324+ val q = Quaternionf ()
325+ q.rotateXYZ(
326+ MathHelper .lerp(tickDelta, this .previewAngleX, this .currentAngleX),
327+ MathHelper .lerp(tickDelta, this .previewAngleY, this .currentAngleY),
328+ MathHelper .lerp(tickDelta, this .previewAngleZ, this .currentAngleZ)
329+ )
330+ // 构建顶点几何
331+ val light = this .getBrightness(tickDelta)
332+
333+
334+ setParticleTexture(vertexConsumer, q, x, y, z, tickDelta, light)
335+ }
336+
337+ private fun setParticleTexture (
338+ vertexConsumer : VertexConsumer ,
339+ q : Quaternionf ,
340+ x : Float ,
341+ y : Float ,
342+ z : Float ,
343+ tickDelta : Float ,
344+ light : Int
345+ ) {
346+ val s = getSize(tickDelta)
347+
348+ addVertex(
349+ vertexConsumer, q, x, y, z, 1f , - 1f , maxU, maxV, s, light
350+ )
351+ addVertex(
352+ vertexConsumer, q, x, y, z, 1f , 1f , maxU, minV, s, light
353+ )
354+ addVertex(
355+ vertexConsumer, q, x, y, z, - 1f , 1f , minU, minV, s, light
356+ )
357+ addVertex(
358+ vertexConsumer, q, x, y, z, - 1f , - 1f , minU, maxV, s, light
359+ )
360+
361+ // 背面
362+ addVertex(
363+ vertexConsumer, q, x, y, z,
364+ vx = - 1f , // 左下角 X
365+ vy = - 1f ,
366+ tu = minU, // UV 镜像
367+ tv = maxV,
368+ size = s,
369+ light = light
370+ )
371+ addVertex(
372+ vertexConsumer, q, x, y, z,
373+ vx = - 1f , // 左上角 X
374+ vy = 1f ,
375+ tu = minU,
376+ tv = minV,
377+ size = s,
378+ light = light
379+ )
380+ addVertex(
381+ vertexConsumer, q, x, y, z,
382+ vx = 1f , // 右上角 X
383+ vy = 1f ,
384+ tu = maxU, // UV 镜像
385+ tv = minV,
386+ size = s,
387+ light = light
388+ )
389+ addVertex(
390+ vertexConsumer, q, x, y, z,
391+ vx = 1f , // 右下角 X
392+ vy = - 1f ,
393+ tu = maxU,
394+ tv = maxV,
395+ size = s,
396+ light = light
397+ )
398+ }
399+
400+ private fun addVertex (
401+ consumer : VertexConsumer ,
402+ q : Quaternionf ,
403+ dx : Float ,
404+ dy : Float ,
405+ dz : Float ,
406+ vx : Float ,
407+ vy : Float ,
408+ tu : Float ,
409+ tv : Float ,
410+ size : Float ,
411+ light : Int
412+ ) {
413+ val pos = Vector3f (vx, vy, 0f ).rotate(q).mul(size).add(dx, dy, dz)
414+ consumer.vertex(pos.x, pos.y, pos.z)
415+ .texture(tu, tv)
416+ .color(red, green, blue, alpha)
417+ .light(light)
418+ }
274419
275420 override fun getType (): ParticleTextureSheet ? {
276421 return textureSheet
0 commit comments