"""This sample shows how to do some very simple post processing effects."""
import d3d11
import d3d11x
from d3d11c import *
vertexLayoutDesc = [
("POSITION", 0, FORMAT_R32G32B32_FLOAT),
("TEXTURE", 0, FORMAT_R32G32_FLOAT),
]
class PostProcessSample(d3d11x.Frame):
def onCreate(self):
self.renderTarget = None
self.renderTargetView = None
meshPath = d3d11x.getResourceDir("Mesh", "barrel.obj")
self.mesh = d3d11x.Mesh(self.device, meshPath)
self.mesh.textureView = self.loadTextureView("static-barrel.dds")
self.skyBox = d3d11x.SkyBox(self.device)
self.skyBox.textureView = self.loadTextureView("skybox-clear.dds")
effectPath = d3d11x.getResourceDir("Effects", "SamplePostProcess.fx")
self.postEffect = d3d11.Effect(effectPath)
self.postInputLayout = d3d11.InputLayout(vertexLayoutDesc,
self.postEffect, 0, 0)
#Vertex buffer for 2D stuff.
self.vertexBuffer = d3d11.Buffer(vertexLayoutDesc, 32,
BIND_VERTEX_BUFFER, USAGE_DYNAMIC, CPU_ACCESS_WRITE)
def onResize(self):
#When the window is resized we should re-create
#our render target so that it's size matches the window.
defaultTarget = self.device.getDefaultRT()
rtDesc = defaultTarget.getDesc()
rtSize = defaultTarget.size()
defaultTarget.release()
#Our custom render target and it's view. Note that
#often you need more than one rendert target and
#for performance it is often useful do do post processing
#using smaller render targets. For example bloom or blurring
#can be done using a 4 times smaller render target.
self.renderTarget = d3d11.Texture(None, rtSize + (1, 1),
rtDesc.format, BIND_SHADER_RESOURCE | BIND_RENDER_TARGET)
self.renderTargetView = d3d11.View(self.renderTarget)
def addQuads(self):
wScreen, hScreen = self.renderTarget.size()
aspectRatio = float(wScreen) / hScreen
halfHeight = hScreen / 2.0 - 20
#Three rectangles for the render targets.
rects = [
d3d11x.Rect(10, 10, 0, halfHeight),
d3d11x.Rect(wScreen / 2, 10, 0, halfHeight),
d3d11x.Rect(10, halfHeight + 30, 0, halfHeight),
d3d11x.Rect(wScreen / 2, halfHeight + 30, 0, halfHeight),
]
#Write the rectangle vertices into a buffer.
with d3d11x.Mapper(self.vertexBuffer, MAP_WRITE_DISCARD):
for rect in rects:
rect.width = rect.height * aspectRatio
quad = [
(rect.x, rect.y, 0, 0, 0),
(rect.x + rect.width, rect.y, 0, 1, 0),
(rect.x, rect.y + rect.height, 0, 0, 1),
(rect.x + rect.width, rect.y + rect.height, 0, 1, 1),
]
self.vertexBuffer.extend(quad)
def renderScene(self):
#This renders the scene into the current render target.
eyePoint = d3d11.Vector(0, 5, -10)
viewMatrix = self.createLookAt(eyePoint, (0, 0, 0))
projMatrix = self.createProjection(60, 0.1, 300)
#Render the skybox.
skyMatrix = d3d11.Matrix()
skyMatrix.translate((0, eyePoint.y - self.skyBox.height / 2.0, eyePoint.z))
self.skyBox.render(skyMatrix, viewMatrix, projMatrix)
meshMatrix = d3d11.Matrix()
meshMatrix.rotate((self.time, 0, self.time))
#Add a red light and render the mesh.
self.mesh.setLights([((0, 10, 10), (1, 0, 0, 0))])
self.mesh.render(meshMatrix, viewMatrix, projMatrix)
def onRender(self):
#Replace the default render target with our own,
#but use default depth stencil texture.
self.renderTargetView.clearRenderTarget()
self.device.setRenderTargets([self.renderTargetView], self.device.getDefaultDSView())
#Render the scene once into our custom render target.
self.renderScene()
#Resetore render targets.
self.device.setRenderTargetsDefault()
#Write 3 2D quads into the vertex buffer.
self.addQuads()
self.device.setInputLayout(self.postInputLayout)
self.device.setVertexBuffers([self.vertexBuffer])
self.device.setPrimitiveTopology(PRIMITIVE_TOPOLOGY_TRIANGLESTRIP)
self.postEffect.set("screenSize", self.renderTarget.size())
self.postEffect.set("postTexture", self.renderTargetView)
self.postEffect.set("time", self.time)
#Go through all effect techniques.
for i in range(4):
self.postEffect.apply(i, 0)
self.device.draw(4, i * 4)
self.device.restoreDepthStencilState()
if __name__ == "__main__":
frame = PostProcessSample("Post processing", __doc__)
frame.mainloop()