123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- from ... import ShaderMaterial
- from ... import ReadFile
-
- from mathutils import Vector
- from mathutils import Matrix
- import time
- import math
- import bge
- import bgl
-
- class Water(ShaderMaterial):
- '''The original work for this material comes from Martinsh:
- > http://devlog-martinsh.blogspot.ca/'''
-
- FragmentShader = ReadFile('./water.fs', __file__)
- VertexShader = ReadFile('./water.vs', __file__)
-
- # Parameters
- backgroundColor = Vector((.1, .2, .8, .0))
- waterCamera = property(
- lambda self: self.owner.children.get('WaterRenderCamera'))
- activeCamera = property(
- lambda self: self.owner.scene.active_camera)
- height = property(
- lambda self: bge.render.getWindowHeight())
- width = property(
- lambda self: bge.render.getWindowWidth())
- reflectionSize = 512
- refractionSize = 512
- timeModulo = 1 << 16
- offset = -0.2
-
- def init(self):
-
- # Setting up the reflection texture
- self.reflection = bge.texture.Texture(self.owner, 0, 0)
- self.reflection.source = bge.texture.ImageRender(
- self.owner.scene, self.waterCamera)
- self.reflection.source.capsize = (
- self.width, self.height)
- # self.reflectionSize, self.reflectionSize)
- # self.reflectionSize // 2, self.reflectionSize // 2)
- self.reflection.source.background = list(
- 255 * self.backgroundColor)
- self.reflection.refresh(True)
-
- # Setting up the refraction texture
- self.refraction = bge.texture.Texture(self.owner, 0, 1)
- self.refraction.source = bge.texture.ImageRender(
- self.owner.scene, self.waterCamera)
- self.refraction.source.capsize = (
- self.width, self.height)
- # self.refractionSize, self.refractionSize)
- # self.refractionSize // 2, self.refractionSize // 2)
- self.refraction.source.background = list(
- 255 * self.backgroundColor)
- self.refraction.refresh(True)
-
- def pre_draw_setup(self, shader):
- '''I have no idea why, but this has to run on pre_draw_setup...'''
- shader.setAttrib(bge.logic.SHD_TANGENT)
- shader.setUniformDef('ModelMatrix', bge.logic.MODELMATRIX)
- shader.setUniformDef('cameraPos', bge.logic.CAM_POS)
- shader.setSampler('reflectionSampler', 0)
- shader.setSampler('refractionSampler', 1)
- shader.setSampler('normalSampler', 2)
- shader.setSampler('depthSampler', 3)
- shader.setUniform1f('timer',
- (3 * time.time()) % self.timeModulo)
-
- # User uniforms
- shader.setUniform1f('scale', self.owner.get('water.scale', 1.))
- shader.setUniform1f('windSpeed', self.owner.get('water.wind.speed', .2))
-
- self.watertexture()
-
- def watertexture(self):
- waterCamera = self.waterCamera
- activeCamera = self.activeCamera
-
- # Setting up the water camera parameters
- waterCamera.lens = activeCamera.lens
- waterCamera.projection_matrix = activeCamera.projection_matrix
- self.owner.visible = False
-
- # plane normals Z = Front
- normal = self.owner.getAxisVect((0., 0., 1.))
-
- # closest distance from center to plane
- distance = -self.owner.position.project(normal).magnitude
-
- # VdotN to get front-face/back-face
- V = (activeCamera.position - self.owner.position
- ).normalized().dot(normal)
-
- # Invert normals when back-face (?)
- if V < 0: normal = -normal
-
- # Processing the reflection and the refraction
- self.processReflection(activeCamera, waterCamera, normal, distance)
- self.processRefraction(activeCamera, waterCamera, normal, distance)
- self.owner.visible = True
-
- def processReflection(self, activeCamera, waterCamera, normal, distance):
- '''This is the refactored way of processing reflection'''
- M1 = Matrix(self.owner.orientation)
- M2 = Matrix(self.owner.orientation)
- M2.invert()
-
- R = Matrix.Rotation(math.radians(180), 3, 'Y')
- U = Matrix.Scale(-1, 3, Vector((1, 0, 0)))
-
- position = (activeCamera.position - self.owner.position) * M1
- position = self.owner.position + position * R * U * M2
-
- orientation = Matrix(activeCamera.orientation)
- orientation.transpose()
- orientation = orientation * M1 * R * U * M2
- orientation.transpose()
-
- # Orienting and positioning the water camera
- waterCamera.orientation = orientation
- waterCamera.position = position
-
- # Culling front faces as the camera is scaled to -1 (?)
- bgl.glCullFace(bgl.GL_FRONT)
-
- # Changing clipping plane
- plane = bgl.Buffer(bgl.GL_DOUBLE, [4], (
- -normal[0], -normal[1], -normal[2], -distance + self.offset))
- bgl.glClipPlane(bgl.GL_CLIP_PLANE0, plane)
- bgl.glEnable(bgl.GL_CLIP_PLANE0)
-
- self.reflection.refresh(True)
-
- # Reverting parameters
- bgl.glCullFace(bgl.GL_BACK)
- bgl.glDisable(bgl.GL_CLIP_PLANE0)
-
- def processRefraction(self, activeCamera, waterCamera, normal, distance):
- '''This is the refactored way of processing refraction'''
- orientation = Matrix(activeCamera.orientation)
- position = activeCamera.position
-
- # Orienting and positioning the water camera
- waterCamera.orientation = orientation
- waterCamera.position = position
-
- # Changing clipping plane
- plane = bgl.Buffer(bgl.GL_DOUBLE, [4], (
- normal[0], normal[1], normal[2], -distance + self.offset))
- bgl.glClipPlane(bgl.GL_CLIP_PLANE1, plane)
- bgl.glEnable(bgl.GL_CLIP_PLANE1)
-
- self.refraction.refresh(True)
-
- bgl.glDisable(bgl.GL_CLIP_PLANE1)
|